add delete Message logic for opengroupv2

pull/1576/head
Audric Ackermann 5 years ago
parent 98b69c17f0
commit 28ad468965
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -29,6 +29,7 @@ import { ConversationController } from '../../../session/conversations';
import { getMessageById, getPubkeysInPublicConversation } from '../../../data/data';
import autoBind from 'auto-bind';
import { getDecryptedMediaUrl } from '../../../session/crypto/DecryptedAttachmentsManager';
import { deleteOpenGroupMessages } from '../../../interactions/conversation';
interface State {
// Message sending progress
@ -587,8 +588,6 @@ export class SessionConversation extends React.Component<Props, State> {
const doDelete = async () => {
let toDeleteLocally;
// VINCE TODO: MARK TO-DELETE MESSAGES AS READ
if (selectedConversation.isPublic) {
// Get our Moderator status
const ourDevicePubkey = UserUtils.getOurPubKeyStrFromCache();
@ -608,7 +607,7 @@ export class SessionConversation extends React.Component<Props, State> {
return;
}
toDeleteLocally = await conversationModel.deletePublicMessages(selectedMessages);
toDeleteLocally = await deleteOpenGroupMessages(selectedMessages, conversationModel);
if (toDeleteLocally.length === 0) {
// Message failed to delete from server, show error?
return;
@ -618,7 +617,7 @@ export class SessionConversation extends React.Component<Props, State> {
}
await Promise.all(
toDeleteLocally.map(async (message: any) => {
toDeleteLocally.map(async message => {
await conversationModel.removeMessage(message.id);
})
);

@ -11,6 +11,9 @@ export type OpenGroupV2Room = {
imageID?: string; // the url to the group's image
conversationId?: string; // the linked ConversationModel.id
lastMessageFetchedServerID?: number;
/**
* This value represents the rowId of the last message deleted. Not the id of the last message ID
*/
lastMessageDeletedServerID?: number;
token?: string; // currently, the token is on a per room basis
};

@ -5,6 +5,11 @@ import {
} from '../opengroup/utils/OpenGroupUtils';
import { getV2OpenGroupRoom } from '../data/opengroups';
import { ToastUtils } from '../session/utils';
import { ConversationModel } from '../models/conversation';
import { MessageModel } from '../models/message';
import { ApiV2 } from '../opengroup/opengroupV2';
import _ from 'lodash';
export async function copyPublicKey(convoId: string) {
if (convoId.match(openGroupPrefixRegex)) {
@ -35,3 +40,81 @@ export async function copyPublicKey(convoId: string) {
ToastUtils.pushCopiedToClipBoard();
}
export async function deleteOpenGroupMessages(
messages: Array<MessageModel>,
convo: ConversationModel
): Promise<Array<MessageModel>> {
if (!convo.isPublic()) {
throw new Error('cannot delete public message on a non public groups');
}
if (convo.isOpenGroupV2()) {
const roomInfos = convo.toOpenGroupV2();
// on v2 servers we can only remove a single message per request..
// so logic here is to delete each messages and get which one where not removed
const allDeletedResults = await Promise.all(
messages.map(async msg => {
const msgId = msg.get('serverId');
if (msgId) {
const isRemovedOnServer = await ApiV2.deleteSingleMessage(msgId, roomInfos);
return { message: msg, isRemovedOnServer };
} else {
window.log.warn('serverId not valid for deletePublicMessage');
return { message: msg, isRemovedOnServer: false };
}
})
);
if (allDeletedResults.every(m => m.isRemovedOnServer)) {
window.log.info('all those serverIds where removed');
} else {
if (allDeletedResults.some(m => m.isRemovedOnServer)) {
window.log.info('some of those serverIds where not removed');
} else {
window.log.info('failed to remove all those serverIds message');
}
}
// remove only the messag we managed to remove on the server
const msgToDeleteLocally = allDeletedResults
.filter(m => m.isRemovedOnServer)
.map(m => m.message);
return msgToDeleteLocally;
} else if (convo.isOpenGroupV1()) {
const channelAPI = await convo.getPublicSendData();
if (!channelAPI) {
throw new Error('Unable to get public channel API');
}
const invalidMessages = messages.filter(m => !m.attributes.serverId);
const pendingMessages = messages.filter(m => m.attributes.serverId);
let deletedServerIds = [];
let ignoredServerIds = [];
if (pendingMessages.length > 0) {
const result = await channelAPI.deleteMessages(
pendingMessages.map(m => m.attributes.serverId)
);
deletedServerIds = result.deletedIds;
ignoredServerIds = result.ignoredIds;
}
const toDeleteLocallyServerIds = _.union(deletedServerIds, ignoredServerIds);
let toDeleteLocally = messages.filter(m =>
toDeleteLocallyServerIds.includes(m.attributes.serverId)
);
toDeleteLocally = _.union(toDeleteLocally, invalidMessages);
await Promise.all(
toDeleteLocally.map(async m => {
await convo.removeMessage(m.id);
})
);
await convo.updateLastMessage();
return toDeleteLocally;
}
return [];
}

@ -4,7 +4,7 @@ import { getMessageQueue } from '../session';
import { ConversationController } from '../session/conversations';
import { ClosedGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage';
import { PubKey } from '../session/types';
import { UserUtils } from '../session/utils';
import { ToastUtils, UserUtils } from '../session/utils';
import { BlockedNumberController } from '../util';
import { MessageController } from '../session/messages';
import { leaveClosedGroup } from '../session/group';
@ -43,6 +43,7 @@ import { getV2OpenGroupRoom } from '../data/opengroups';
import { OpenGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil';
import { getOpenGroupV2FromConversationId } from '../opengroup/utils/OpenGroupUtils';
import { ApiV2 } from '../opengroup/opengroupV2';
export enum ConversationType {
GROUP = 'group',
@ -1324,48 +1325,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
});
}
public async deletePublicMessages(messages: Array<MessageModel>) {
if (this.isOpenGroupV2()) {
console.warn('FIXME deletePublicMessages');
throw new Error('deletePublicMessages todo');
}
const channelAPI = await this.getPublicSendData();
if (!channelAPI) {
throw new Error('Unable to get public channel API');
}
const invalidMessages = messages.filter(m => !m.attributes.serverId);
const pendingMessages = messages.filter(m => m.attributes.serverId);
let deletedServerIds = [];
let ignoredServerIds = [];
if (pendingMessages.length > 0) {
const result = await channelAPI.deleteMessages(
pendingMessages.map(m => m.attributes.serverId)
);
deletedServerIds = result.deletedIds;
ignoredServerIds = result.ignoredIds;
}
const toDeleteLocallyServerIds = _.union(deletedServerIds, ignoredServerIds);
let toDeleteLocally = messages.filter(m =>
toDeleteLocallyServerIds.includes(m.attributes.serverId)
);
toDeleteLocally = _.union(toDeleteLocally, invalidMessages);
await Promise.all(
toDeleteLocally.map(async m => {
await this.removeMessage(m.id);
})
);
await this.updateLastMessage();
return toDeleteLocally;
}
public async removeMessage(messageId: any) {
await dataRemoveMessage(messageId);
this.updateLastMessage();

@ -402,6 +402,23 @@ export const unbanUser = async (
return isOk;
};
export const deleteSingleMessage = async (
messageServerId: number,
roomInfos: OpenGroupRequestCommonType
): Promise<boolean> => {
const request: OpenGroupV2Request = {
method: 'DELETE',
room: roomInfos.roomId,
server: roomInfos.serverUrl,
isAuthRequired: true,
endpoint: `messages/${messageServerId}`,
};
const messageDeletedResult = await sendOpenGroupV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(messageDeletedResult) === 200;
console.warn('messageDeletedResult', messageDeletedResult);
return isOk;
};
export const getAllRoomInfos = async (roomInfos: OpenGroupRequestCommonType) => {
// room should not be required here
const request: OpenGroupV2Request = {

@ -57,13 +57,13 @@ const getCompactPollRequest = async (
room_id: roomId,
auth_token: token || '',
};
if (lastMessageDeletedServerID) {
roomRequestContent.from_deletion_server_id = lastMessageDeletedServerID;
}
if (lastMessageFetchedServerID) {
roomRequestContent.from_message_server_id = lastMessageFetchedServerID;
}
// if (lastMessageDeletedServerID) {
roomRequestContent.from_deletion_server_id = lastMessageDeletedServerID;
// }
// if (lastMessageFetchedServerID) {
roomRequestContent.from_message_server_id = lastMessageFetchedServerID || 1;
// }
console.warn('compactPoll, ', roomRequestContent);
return roomRequestContent;
} catch (e) {
@ -161,9 +161,11 @@ async function sendOpenGroupV2RequestCompactPoll(
return roomPollValidResults;
}
export type ParsedDeletions = Array<{ id: number; deleted_message_id: number }>;
export type ParsedRoomCompactPollResults = {
roomId: string;
deletions: Array<number>;
deletions: ParsedDeletions;
messages: Array<OpenGroupMessageV2>;
moderators: Array<string>;
statusCode: number;
@ -194,7 +196,7 @@ const parseCompactPollResult = async (
const validMessages = await parseMessages(rawMessages);
const moderators = rawMods.sort() as Array<string>;
const deletions = rawDeletions as Array<number>;
const deletions = rawDeletions as ParsedDeletions;
const statusCode = rawStatusCode as number;
return {

@ -2,7 +2,11 @@ import { AbortController } from 'abort-controller';
import { ConversationController } from '../../session/conversations';
import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils';
import { OpenGroupRequestCommonType } from './ApiUtil';
import { compactFetchEverything, ParsedRoomCompactPollResults } from './OpenGroupAPIV2CompactPoll';
import {
compactFetchEverything,
ParsedDeletions,
ParsedRoomCompactPollResults,
} from './OpenGroupAPIV2CompactPoll';
import _ from 'lodash';
import { ConversationModel } from '../../models/conversation';
import { getMessageIdsFromServerIds, removeMessage } from '../../data/data';
@ -10,7 +14,7 @@ import { getV2OpenGroupRoom, saveV2OpenGroupRoom } from '../../data/opengroups';
import { OpenGroupMessageV2 } from './OpenGroupMessageV2';
import { handleOpenGroupV2Message } from '../../receiver/receiver';
const pollForEverythingInterval = 4 * 1000;
const pollForEverythingInterval = 8 * 1000;
/**
* An OpenGroupServerPollerV2 polls for everything for a particular server. We should
@ -165,33 +169,40 @@ export class OpenGroupServerPoller {
}
const handleDeletions = async (
deletedIds: Array<number>,
deleted: ParsedDeletions,
conversationId: string,
convo?: ConversationModel
) => {
const allIdsRemoved = (deleted || []).map(d => d.deleted_message_id);
const allRowIds = (deleted || []).map(d => d.id);
const maxDeletedId = Math.max(...allRowIds);
try {
const maxDeletedId = Math.max(...deletedIds);
const messageIds = await getMessageIdsFromServerIds(deletedIds, conversationId);
if (!messageIds?.length) {
return;
}
const roomInfos = await getV2OpenGroupRoom(conversationId);
if (roomInfos && roomInfos.lastMessageDeletedServerID !== maxDeletedId) {
roomInfos.lastMessageDeletedServerID = maxDeletedId;
await saveV2OpenGroupRoom(roomInfos);
}
console.warn('We got deletion to do:', deleted, maxDeletedId);
const messageIds = await getMessageIdsFromServerIds(allIdsRemoved, conversationId);
await Promise.all(
messageIds.map(async id => {
(messageIds || []).map(async id => {
if (convo) {
await convo.removeMessage(id);
}
await removeMessage(id);
})
);
// we want to try to update our lastDeletedId
//
} catch (e) {
window.log.warn('handleDeletions failed:', e);
} finally {
try {
const roomInfos = await getV2OpenGroupRoom(conversationId);
if (roomInfos && roomInfos.lastMessageDeletedServerID !== maxDeletedId) {
roomInfos.lastMessageDeletedServerID = maxDeletedId;
await saveV2OpenGroupRoom(roomInfos);
}
} catch (e) {
window.log.warn('handleDeletions updating roomInfos failed:', e);
}
}
};
@ -234,6 +245,7 @@ const handleCompactPollResults = async (
serverUrl: string,
results: Array<ParsedRoomCompactPollResults>
) => {
console.warn('compoll res', results);
await Promise.all(
results.map(async res => {
const convoId = getOpenGroupV2ConversationId(serverUrl, res.roomId);
@ -241,6 +253,7 @@ const handleCompactPollResults = async (
// we want to do deletions even if we somehow lost the convo.
if (res.deletions.length) {
console.warn('res.deletions', res.deletions);
// new deletions
await handleDeletions(res.deletions, convoId, convo);
}

Loading…
Cancel
Save