diff --git a/keyserver/src/creators/message-report-creator.js b/keyserver/src/creators/message-report-creator.js index 0c32fdf23..94c304952 100644 --- a/keyserver/src/creators/message-report-creator.js +++ b/keyserver/src/creators/message-report-creator.js @@ -1,151 +1,154 @@ // @flow import bots from 'lib/facts/bots.js'; import { createMessageQuote } from 'lib/shared/message-utils.js'; import { type MessageReportCreationRequest } from 'lib/types/message-report-types.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; import type { RawMessageInfo } from 'lib/types/message-types.js'; import type { ServerThreadInfo } from 'lib/types/thread-types.js'; import { ServerError } from 'lib/utils/errors.js'; import { promiseAll } from 'lib/utils/promises.js'; import createMessages from './message-creator.js'; import { createCommbotThread } from '../bots/commbot.js'; import { fetchMessageInfoByID } from '../fetchers/message-fetchers.js'; import { fetchPersonalThreadID, serverThreadInfoFromMessageInfo, } from '../fetchers/thread-fetchers.js'; import { fetchUsername, fetchKeyserverAdminID, } from '../fetchers/user-fetchers.js'; import type { Viewer } from '../session/viewer.js'; const { commbot } = bots; type MessageReportData = { +reportedMessageText: ?string, +reporterUsername: ?string, +commbotThreadID: string, +reportedThread: ?ServerThreadInfo, +reportedMessageAuthor: ?string, }; async function createMessageReport( viewer: Viewer, request: MessageReportCreationRequest, ): Promise { const keyserverAdminIDPromise = fetchKeyserverAdminID(); const { reportedMessageText, reporterUsername, commbotThreadID, reportedThread, reportedMessageAuthor, } = await fetchMessageReportData(viewer, request); const reportMessage = getCommbotMessage( reporterUsername, reportedMessageAuthor, reportedThread?.name, reportedMessageText, ); const time = Date.now(); const [messageResult, keyserverAdminID] = await Promise.all([ createMessages(viewer, [ { type: messageTypes.TEXT, threadID: commbotThreadID, creatorID: commbot.userID, time, text: reportMessage, }, ]), keyserverAdminIDPromise, ]); if (messageResult.length === 0) { throw new ServerError('message_report_failed'); } if (viewer.userID === keyserverAdminID) { return messageResult; } return []; } async function fetchMessageReportData( viewer: Viewer, request: MessageReportCreationRequest, ): Promise { const keyserverAdminIDPromise = fetchKeyserverAdminID(); - const reportedMessagePromise = fetchMessageInfoByID( - viewer, - request.messageID, - ); + const reportedMessagePromise = (async () => { + const { messageID } = request; + if (!messageID) { + return null; + } + return await fetchMessageInfoByID(viewer, messageID); + })(); const viewerUsernamePromise = fetchUsername(viewer.id); const keyserverAdminID = await keyserverAdminIDPromise; if (!keyserverAdminID) { throw new ServerError('keyserver_admin_not_found'); } const commbotThreadIDPromise = getCommbotThreadID(keyserverAdminID); const reportedMessage = await reportedMessagePromise; const reportedThreadPromise: Promise = reportedMessage ? serverThreadInfoFromMessageInfo(reportedMessage) : Promise.resolve(undefined); const reportedMessageAuthorID = reportedMessage?.creatorID; const reportedMessageAuthorPromise: Promise = reportedMessageAuthorID ? fetchUsername(reportedMessageAuthorID) : Promise.resolve(undefined); const reportedMessageText = reportedMessage?.type === 0 ? reportedMessage.text : null; const { viewerUsername, commbotThreadID, reportedThread, reportedMessageAuthor, } = await promiseAll({ viewerUsername: viewerUsernamePromise, commbotThreadID: commbotThreadIDPromise, reportedThread: reportedThreadPromise, reportedMessageAuthor: reportedMessageAuthorPromise, }); return { reportedMessageText, reporterUsername: viewerUsername, commbotThreadID, reportedThread, reportedMessageAuthor, }; } async function getCommbotThreadID(userID: string): Promise { const commbotThreadID = await fetchPersonalThreadID(userID, commbot.userID); return commbotThreadID ?? createCommbotThread(userID); } function getCommbotMessage( reporterUsername: ?string, messageAuthorUsername: ?string, threadName: ?string, message: ?string, ): string { reporterUsername = reporterUsername ?? '[null]'; const messageAuthor = messageAuthorUsername ? `${messageAuthorUsername}’s` : 'this'; const thread = threadName ? `chat titled "${threadName}"` : 'chat'; const reply = message ? createMessageQuote(message) : 'non-text message'; return ( `${reporterUsername} reported ${messageAuthor} message in ${thread}\n` + reply ); } export default createMessageReport; diff --git a/keyserver/src/responders/message-report-responder.js b/keyserver/src/responders/message-report-responder.js index 58ba28daa..b3d14688f 100644 --- a/keyserver/src/responders/message-report-responder.js +++ b/keyserver/src/responders/message-report-responder.js @@ -1,27 +1,27 @@ // @flow -import type { TInterface } from 'tcomb'; +import t, { type TInterface } from 'tcomb'; import { type MessageReportCreationRequest, type MessageReportCreationResult, } from 'lib/types/message-report-types.js'; import { tShape, tID } from 'lib/utils/validation-utils.js'; import createMessageReport from '../creators/message-report-creator.js'; import type { Viewer } from '../session/viewer.js'; export const messageReportCreationRequestInputValidator: TInterface = tShape({ - messageID: tID, + messageID: t.maybe(tID), }); async function messageReportCreationResponder( viewer: Viewer, request: MessageReportCreationRequest, ): Promise { const rawMessageInfos = await createMessageReport(viewer, request); return { messageInfo: rawMessageInfos[0] }; } export { messageReportCreationResponder }; diff --git a/lib/actions/message-report-actions.js b/lib/actions/message-report-actions.js index 6f69afcf3..785f2c9ba 100644 --- a/lib/actions/message-report-actions.js +++ b/lib/actions/message-report-actions.js @@ -1,41 +1,47 @@ // @flow -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import type { MessageReportCreationRequest, MessageReportCreationResult, } from '../types/message-report-types.js'; +import { authoritativeKeyserverID } from '../utils/authoritative-keyserver.js'; const sendMessageReportActionTypes = Object.freeze({ started: 'SEND_MESSAGE_REPORT_STARTED', success: 'SEND_MESSAGE_REPORT_SUCCESS', failed: 'SEND_MESSAGE_REPORT_FAILED', }); const sendMessageReport = ( callKeyserverEndpoint: CallKeyserverEndpoint, ): (( input: MessageReportCreationRequest, ) => Promise) => async input => { - const keyserverID = extractKeyserverIDFromID(input.messageID); - const requests = { [keyserverID]: input }; + const messageKeyserverID = input.messageID + ? extractKeyserverIDFromIDOptional(input.messageID) + : null; + const keyserverID: string = + messageKeyserverID ?? authoritativeKeyserverID(); + const messageID = messageKeyserverID ? input.messageID : null; + const requests = { [keyserverID]: { messageID } }; const responses = await callKeyserverEndpoint( 'create_message_report', requests, ); const response = responses[keyserverID]; return { messageInfo: response.messageInfo }; }; function useSendMessageReport(): ( input: MessageReportCreationRequest, ) => Promise { return useKeyserverCall(sendMessageReport); } export { sendMessageReportActionTypes, useSendMessageReport }; diff --git a/lib/types/message-report-types.js b/lib/types/message-report-types.js index 966344d59..066e34830 100644 --- a/lib/types/message-report-types.js +++ b/lib/types/message-report-types.js @@ -1,11 +1,11 @@ // @flow import type { RawMessageInfo } from './message-types.js'; export type MessageReportCreationRequest = { - +messageID: string, + +messageID: ?string, }; export type MessageReportCreationResult = { +messageInfo: ?RawMessageInfo, };