diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js --- a/keyserver/src/endpoints.js +++ b/keyserver/src/endpoints.js @@ -25,6 +25,7 @@ messageFetchResponder, multimediaMessageCreationResponder, reactionMessageCreationResponder, + editMessageCreationResponder, } from './responders/message-responders.js'; import { updateRelationshipsResponder } from './responders/relationship-responders.js'; import { @@ -87,6 +88,10 @@ responder: reactionMessageCreationResponder, requiredPolicies: baseLegalPolicies, }, + edit_message: { + responder: editMessageCreationResponder, + requiredPolicies: baseLegalPolicies, + }, create_report: { responder: reportCreationResponder, requiredPolicies: [], diff --git a/keyserver/src/responders/message-responders.js b/keyserver/src/responders/message-responders.js --- a/keyserver/src/responders/message-responders.js +++ b/keyserver/src/responders/message-responders.js @@ -15,11 +15,14 @@ type SendTextMessageRequest, type SendMultimediaMessageRequest, type SendReactionMessageRequest, + type SendEditMessageRequest, type FetchMessageInfosResponse, type FetchMessageInfosRequest, defaultNumberPerThread, type SendMessageResponse, + type SendEditMessageResponse, } from 'lib/types/message-types.js'; +import type { EditMessageData } from 'lib/types/messages/edit.js'; import type { ReactionMessageData } from 'lib/types/messages/reaction.js'; import type { TextMessageData } from 'lib/types/messages/text.js'; import { threadPermissions } from 'lib/types/thread-types.js'; @@ -286,9 +289,73 @@ return { newMessageInfo: rawMessageInfos[0] }; } +const editMessageRequestInputValidator = tShape({ + targetMessageID: t.String, + text: t.String, +}); +async function editMessageCreationResponder( + viewer: Viewer, + input: any, +): Promise { + const request: SendEditMessageRequest = input; + await validateInput(viewer, editMessageRequestInputValidator, input); + + const { targetMessageID, text: rawText } = request; + const text = trimMessage(rawText); + if (!targetMessageID || !text) { + throw new ServerError('invalid_parameters'); + } + + const targetMessageInfo = await fetchMessageInfoByID(viewer, targetMessageID); + if (!targetMessageInfo || !targetMessageInfo.id) { + throw new ServerError('invalid_parameters'); + } + + if (targetMessageInfo.type !== messageTypes.TEXT) { + throw new ServerError('invalid_parameters'); + } + + const { threadID } = targetMessageInfo; + const [serverThreadInfos, hasPermission] = await Promise.all([ + fetchServerThreadInfos(SQL`t.id = ${threadID}`), + checkThreadPermission(viewer, threadID, threadPermissions.EDIT_MESSAGE), + ]); + + const targetMessageThreadInfo = serverThreadInfos.threadInfos[threadID]; + if (targetMessageThreadInfo.sourceMessageID === targetMessageID) { + // We are editing first message of the sidebar + // If client wants to do that it sends id of the sourceMessage instead + throw new ServerError('invalid_parameters'); + } + + if (!hasPermission) { + throw new ServerError('invalid_parameters'); + } + + if (targetMessageInfo.creatorID !== viewer.id) { + throw new ServerError('invalid_parameters'); + } + + const messagesData = []; + const messageData: EditMessageData = { + type: messageTypes.EDIT_MESSAGE, + threadID, + creatorID: viewer.id, + time: Date.now(), + targetMessageID, + text, + }; + messagesData.push(messageData); + + const newMessageInfos = await createMessages(viewer, messagesData); + + return { newMessageInfos }; +} + export { textMessageCreationResponder, messageFetchResponder, multimediaMessageCreationResponder, reactionMessageCreationResponder, + editMessageCreationResponder, }; diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js --- a/lib/types/endpoints.js +++ b/lib/types/endpoints.js @@ -52,6 +52,7 @@ CREATE_MESSAGE_REPORT: 'create_message_report', CREATE_MULTIMEDIA_MESSAGE: 'create_multimedia_message', CREATE_REACTION_MESSAGE: 'create_reaction_message', + EDIT_MESSAGE: 'edit_message', CREATE_TEXT_MESSAGE: 'create_text_message', CREATE_THREAD: 'create_thread', DELETE_ENTRY: 'delete_entry', diff --git a/lib/types/message-types.js b/lib/types/message-types.js --- a/lib/types/message-types.js +++ b/lib/types/message-types.js @@ -563,6 +563,15 @@ +action: 'add_reaction' | 'remove_reaction', }; +export type SendEditMessageRequest = { + +targetMessageID: string, + +text: string, +}; + +export type SendEditMessageResponse = { + +newMessageInfos: $ReadOnlyArray, +}; + // Used for the message info included in log-in type actions export type GenericMessagesResult = { +messageInfos: RawMessageInfo[],