diff --git a/lib/shared/messages/create-entry-message-spec.js b/lib/shared/messages/create-entry-message-spec.js index 889086672..da1659f81 100644 --- a/lib/shared/messages/create-entry-message-spec.js +++ b/lib/shared/messages/create-entry-message-spec.js @@ -1,184 +1,184 @@ // @flow import invariant from 'invariant'; import { messageTypes } from '../../types/message-types'; import type { MessageInfo, ClientDBMessageInfo, } from '../../types/message-types'; import type { CreateEntryMessageData, CreateEntryMessageInfo, RawCreateEntryMessageInfo, } from '../../types/messages/create-entry'; import type { NotifTexts } from '../../types/notif-types'; import type { ThreadInfo } from '../../types/thread-types'; import type { RelativeUserInfo } from '../../types/user-types'; import { prettyDate } from '../../utils/date-utils'; +import { ET, type EntityText } from '../../utils/entity-text'; import { robotextToRawString, robotextForMessageInfo, removeCreatorAsViewer, } from '../message-utils'; import { stringForUser } from '../user-utils'; import { pushTypes, type MessageSpec, type MessageTitleParam, type NotificationTextsParams, } from './message-spec'; import { joinResult } from './utils'; export const createEntryMessageSpec: MessageSpec< CreateEntryMessageData, RawCreateEntryMessageInfo, CreateEntryMessageInfo, > = Object.freeze({ messageContentForServerDB( data: CreateEntryMessageData | RawCreateEntryMessageInfo, ): string { return JSON.stringify({ entryID: data.entryID, date: data.date, text: data.text, }); }, messageContentForClientDB(data: RawCreateEntryMessageInfo): string { return this.messageContentForServerDB(data); }, messageTitle({ messageInfo, threadInfo, viewerContext, }: MessageTitleParam) { let validMessageInfo: CreateEntryMessageInfo = (messageInfo: CreateEntryMessageInfo); if (viewerContext === 'global_viewer') { validMessageInfo = removeCreatorAsViewer(validMessageInfo); } return robotextToRawString( robotextForMessageInfo(validMessageInfo, threadInfo), ); }, rawMessageInfoFromServerDBRow(row: Object): RawCreateEntryMessageInfo { const content = JSON.parse(row.content); return { type: messageTypes.CREATE_ENTRY, id: row.id.toString(), threadID: row.threadID.toString(), time: row.time, creatorID: row.creatorID.toString(), entryID: content.entryID, date: content.date, text: content.text, }; }, rawMessageInfoFromClientDB( clientDBMessageInfo: ClientDBMessageInfo, ): RawCreateEntryMessageInfo { invariant( clientDBMessageInfo.content !== undefined && clientDBMessageInfo.content !== null, 'content must be defined', ); const content = JSON.parse(clientDBMessageInfo.content); const rawCreateEntryMessageInfo: RawCreateEntryMessageInfo = { type: messageTypes.CREATE_ENTRY, id: clientDBMessageInfo.id, threadID: clientDBMessageInfo.thread, time: parseInt(clientDBMessageInfo.time), creatorID: clientDBMessageInfo.user, entryID: content.entryID, date: content.date, text: content.text, }; return rawCreateEntryMessageInfo; }, createMessageInfo( rawMessageInfo: RawCreateEntryMessageInfo, creator: RelativeUserInfo, ): CreateEntryMessageInfo { return { type: messageTypes.CREATE_ENTRY, id: rawMessageInfo.id, threadID: rawMessageInfo.threadID, creator, time: rawMessageInfo.time, entryID: rawMessageInfo.entryID, date: rawMessageInfo.date, text: rawMessageInfo.text, }; }, rawMessageInfoFromMessageData( messageData: CreateEntryMessageData, id: ?string, ): RawCreateEntryMessageInfo { invariant(id, 'RawCreateEntryMessageInfo needs id'); return { ...messageData, id }; }, - robotext(messageInfo: CreateEntryMessageInfo, creator: string): string { + robotext(messageInfo: CreateEntryMessageInfo): EntityText { const date = prettyDate(messageInfo.date); - return ( - `${creator} created an event scheduled for ${date}: ` + - `"${encodeURI(messageInfo.text)}"` - ); + const creator = ET.user({ userInfo: messageInfo.creator }); + const { text } = messageInfo; + return ET`${creator} created an event scheduled for ${date}: "${text}"`; }, notificationTexts( messageInfos: $ReadOnlyArray, threadInfo: ThreadInfo, params: NotificationTextsParams, ): NotifTexts { const hasCreateEntry = messageInfos.some( messageInfo => messageInfo.type === messageTypes.CREATE_ENTRY, ); const messageInfo = messageInfos[0]; if (!hasCreateEntry) { invariant( messageInfo.type === messageTypes.EDIT_ENTRY, 'messageInfo should be messageTypes.EDIT_ENTRY!', ); const body = `updated the text of an event in ` + `${params.notifThreadName(threadInfo)} scheduled for ` + `${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const prefix = stringForUser(messageInfo.creator); const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; } invariant( messageInfo.type === messageTypes.CREATE_ENTRY || messageInfo.type === messageTypes.EDIT_ENTRY, 'messageInfo should be messageTypes.CREATE_ENTRY/EDIT_ENTRY!', ); const prefix = stringForUser(messageInfo.creator); const body = `created an event in ${params.notifThreadName(threadInfo)} ` + `scheduled for ${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; }, notificationCollapseKey(rawMessageInfo: RawCreateEntryMessageInfo): string { return joinResult(rawMessageInfo.creatorID, rawMessageInfo.entryID); }, generatesNotifs: async () => pushTypes.NOTIF, }); diff --git a/lib/shared/messages/delete-entry-message-spec.js b/lib/shared/messages/delete-entry-message-spec.js index 4a94e05dc..b569c3dd1 100644 --- a/lib/shared/messages/delete-entry-message-spec.js +++ b/lib/shared/messages/delete-entry-message-spec.js @@ -1,158 +1,158 @@ // @flow import invariant from 'invariant'; import { messageTypes } from '../../types/message-types'; import type { MessageInfo, ClientDBMessageInfo, } from '../../types/message-types'; import type { DeleteEntryMessageData, DeleteEntryMessageInfo, RawDeleteEntryMessageInfo, } from '../../types/messages/delete-entry'; import type { NotifTexts } from '../../types/notif-types'; import type { ThreadInfo } from '../../types/thread-types'; import type { RelativeUserInfo } from '../../types/user-types'; import { prettyDate } from '../../utils/date-utils'; +import { ET, type EntityText } from '../../utils/entity-text'; import { robotextToRawString, robotextForMessageInfo, removeCreatorAsViewer, } from '../message-utils'; import { stringForUser } from '../user-utils'; import { pushTypes, type MessageSpec, type MessageTitleParam, type NotificationTextsParams, } from './message-spec'; import { assertSingleMessageInfo } from './utils'; export const deleteEntryMessageSpec: MessageSpec< DeleteEntryMessageData, RawDeleteEntryMessageInfo, DeleteEntryMessageInfo, > = Object.freeze({ messageContentForServerDB( data: DeleteEntryMessageData | RawDeleteEntryMessageInfo, ): string { return JSON.stringify({ entryID: data.entryID, date: data.date, text: data.text, }); }, messageContentForClientDB(data: RawDeleteEntryMessageInfo): string { return this.messageContentForServerDB(data); }, messageTitle({ messageInfo, threadInfo, viewerContext, }: MessageTitleParam) { let validMessageInfo: DeleteEntryMessageInfo = (messageInfo: DeleteEntryMessageInfo); if (viewerContext === 'global_viewer') { validMessageInfo = removeCreatorAsViewer(validMessageInfo); } return robotextToRawString( robotextForMessageInfo(validMessageInfo, threadInfo), ); }, rawMessageInfoFromServerDBRow(row: Object): RawDeleteEntryMessageInfo { const content = JSON.parse(row.content); return { type: messageTypes.DELETE_ENTRY, id: row.id.toString(), threadID: row.threadID.toString(), time: row.time, creatorID: row.creatorID.toString(), entryID: content.entryID, date: content.date, text: content.text, }; }, rawMessageInfoFromClientDB( clientDBMessageInfo: ClientDBMessageInfo, ): RawDeleteEntryMessageInfo { invariant( clientDBMessageInfo.content !== undefined && clientDBMessageInfo.content !== null, 'content must be defined', ); const content = JSON.parse(clientDBMessageInfo.content); const rawDeleteEntryMessageInfo: RawDeleteEntryMessageInfo = { type: messageTypes.DELETE_ENTRY, id: clientDBMessageInfo.id, threadID: clientDBMessageInfo.thread, time: parseInt(clientDBMessageInfo.time), creatorID: clientDBMessageInfo.user, entryID: content.entryID, date: content.date, text: content.text, }; return rawDeleteEntryMessageInfo; }, createMessageInfo( rawMessageInfo: RawDeleteEntryMessageInfo, creator: RelativeUserInfo, ): DeleteEntryMessageInfo { return { type: messageTypes.DELETE_ENTRY, id: rawMessageInfo.id, threadID: rawMessageInfo.threadID, creator, time: rawMessageInfo.time, entryID: rawMessageInfo.entryID, date: rawMessageInfo.date, text: rawMessageInfo.text, }; }, rawMessageInfoFromMessageData( messageData: DeleteEntryMessageData, id: ?string, ): RawDeleteEntryMessageInfo { invariant(id, 'RawDeleteEntryMessageInfo needs id'); return { ...messageData, id }; }, - robotext(messageInfo: DeleteEntryMessageInfo, creator: string): string { + robotext(messageInfo: DeleteEntryMessageInfo): EntityText { const date = prettyDate(messageInfo.date); - return ( - `${creator} deleted an event scheduled for ${date}: ` + - `"${encodeURI(messageInfo.text)}"` - ); + const creator = ET.user({ userInfo: messageInfo.creator }); + const { text } = messageInfo; + return ET`${creator} deleted an event scheduled for ${date}: "${text}"`; }, notificationTexts( messageInfos: $ReadOnlyArray, threadInfo: ThreadInfo, params: NotificationTextsParams, ): NotifTexts { const messageInfo = assertSingleMessageInfo(messageInfos); invariant( messageInfo.type === messageTypes.DELETE_ENTRY, 'messageInfo should be messageTypes.DELETE_ENTRY!', ); const prefix = stringForUser(messageInfo.creator); const body = `deleted an event in ${params.notifThreadName(threadInfo)} ` + `scheduled for ${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; }, generatesNotifs: async () => pushTypes.NOTIF, }); diff --git a/lib/shared/messages/edit-entry-message-spec.js b/lib/shared/messages/edit-entry-message-spec.js index 4615fc4ec..ec4806c1f 100644 --- a/lib/shared/messages/edit-entry-message-spec.js +++ b/lib/shared/messages/edit-entry-message-spec.js @@ -1,184 +1,184 @@ // @flow import invariant from 'invariant'; import { messageTypes } from '../../types/message-types'; import type { MessageInfo, ClientDBMessageInfo, } from '../../types/message-types'; import type { EditEntryMessageData, EditEntryMessageInfo, RawEditEntryMessageInfo, } from '../../types/messages/edit-entry'; import type { NotifTexts } from '../../types/notif-types'; import type { ThreadInfo } from '../../types/thread-types'; import type { RelativeUserInfo } from '../../types/user-types'; import { prettyDate } from '../../utils/date-utils'; +import { ET, type EntityText } from '../../utils/entity-text'; import { robotextToRawString, robotextForMessageInfo, removeCreatorAsViewer, } from '../message-utils'; import { stringForUser } from '../user-utils'; import { pushTypes, type MessageSpec, type MessageTitleParam, type NotificationTextsParams, } from './message-spec'; import { joinResult } from './utils'; export const editEntryMessageSpec: MessageSpec< EditEntryMessageData, RawEditEntryMessageInfo, EditEntryMessageInfo, > = Object.freeze({ messageContentForServerDB( data: EditEntryMessageData | RawEditEntryMessageInfo, ): string { return JSON.stringify({ entryID: data.entryID, date: data.date, text: data.text, }); }, messageContentForClientDB(data: RawEditEntryMessageInfo): string { return this.messageContentForServerDB(data); }, messageTitle({ messageInfo, threadInfo, viewerContext, }: MessageTitleParam) { let validMessageInfo: EditEntryMessageInfo = (messageInfo: EditEntryMessageInfo); if (viewerContext === 'global_viewer') { validMessageInfo = removeCreatorAsViewer(validMessageInfo); } return robotextToRawString( robotextForMessageInfo(validMessageInfo, threadInfo), ); }, rawMessageInfoFromServerDBRow(row: Object): RawEditEntryMessageInfo { const content = JSON.parse(row.content); return { type: messageTypes.EDIT_ENTRY, id: row.id.toString(), threadID: row.threadID.toString(), time: row.time, creatorID: row.creatorID.toString(), entryID: content.entryID, date: content.date, text: content.text, }; }, rawMessageInfoFromClientDB( clientDBMessageInfo: ClientDBMessageInfo, ): RawEditEntryMessageInfo { invariant( clientDBMessageInfo.content !== null && clientDBMessageInfo.content !== undefined, 'content must be defined', ); const content = JSON.parse(clientDBMessageInfo.content); const rawEditEntryMessageInfo: RawEditEntryMessageInfo = { type: messageTypes.EDIT_ENTRY, id: clientDBMessageInfo.id, threadID: clientDBMessageInfo.thread, time: parseInt(clientDBMessageInfo.time), creatorID: clientDBMessageInfo.user, entryID: content.entryID, date: content.date, text: content.text, }; return rawEditEntryMessageInfo; }, createMessageInfo( rawMessageInfo: RawEditEntryMessageInfo, creator: RelativeUserInfo, ): EditEntryMessageInfo { return { type: messageTypes.EDIT_ENTRY, id: rawMessageInfo.id, threadID: rawMessageInfo.threadID, creator, time: rawMessageInfo.time, entryID: rawMessageInfo.entryID, date: rawMessageInfo.date, text: rawMessageInfo.text, }; }, rawMessageInfoFromMessageData( messageData: EditEntryMessageData, id: ?string, ): RawEditEntryMessageInfo { invariant(id, 'RawEditEntryMessageInfo needs id'); return { ...messageData, id }; }, - robotext(messageInfo: EditEntryMessageInfo, creator: string): string { + robotext(messageInfo: EditEntryMessageInfo): EntityText { const date = prettyDate(messageInfo.date); - return ( - `${creator} updated the text of an event scheduled for ` + - `${date}: "${encodeURI(messageInfo.text)}"` - ); + const creator = ET.user({ userInfo: messageInfo.creator }); + const { text } = messageInfo; + return ET`${creator} updated the text of an event scheduled for ${date}: "${text}"`; }, notificationTexts( messageInfos: $ReadOnlyArray, threadInfo: ThreadInfo, params: NotificationTextsParams, ): NotifTexts { const hasCreateEntry = messageInfos.some( messageInfo => messageInfo.type === messageTypes.CREATE_ENTRY, ); const messageInfo = messageInfos[0]; if (!hasCreateEntry) { invariant( messageInfo.type === messageTypes.EDIT_ENTRY, 'messageInfo should be messageTypes.EDIT_ENTRY!', ); const body = `updated the text of an event in ` + `${params.notifThreadName(threadInfo)} scheduled for ` + `${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const prefix = stringForUser(messageInfo.creator); const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; } invariant( messageInfo.type === messageTypes.CREATE_ENTRY || messageInfo.type === messageTypes.EDIT_ENTRY, 'messageInfo should be messageTypes.CREATE_ENTRY/EDIT_ENTRY!', ); const prefix = stringForUser(messageInfo.creator); const body = `created an event in ${params.notifThreadName(threadInfo)} ` + `scheduled for ${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; }, notificationCollapseKey(rawMessageInfo: RawEditEntryMessageInfo): string { return joinResult(rawMessageInfo.creatorID, rawMessageInfo.entryID); }, generatesNotifs: async () => pushTypes.NOTIF, }); diff --git a/lib/shared/messages/restore-entry-message-spec.js b/lib/shared/messages/restore-entry-message-spec.js index 4fff5c7eb..db8c8dcf8 100644 --- a/lib/shared/messages/restore-entry-message-spec.js +++ b/lib/shared/messages/restore-entry-message-spec.js @@ -1,158 +1,158 @@ // @flow import invariant from 'invariant'; import { messageTypes } from '../../types/message-types'; import type { MessageInfo, ClientDBMessageInfo, } from '../../types/message-types'; import type { RawRestoreEntryMessageInfo, RestoreEntryMessageData, RestoreEntryMessageInfo, } from '../../types/messages/restore-entry'; import type { NotifTexts } from '../../types/notif-types'; import type { ThreadInfo } from '../../types/thread-types'; import type { RelativeUserInfo } from '../../types/user-types'; import { prettyDate } from '../../utils/date-utils'; +import { ET, type EntityText } from '../../utils/entity-text'; import { robotextToRawString, robotextForMessageInfo, removeCreatorAsViewer, } from '../message-utils'; import { stringForUser } from '../user-utils'; import { pushTypes, type MessageSpec, type MessageTitleParam, type NotificationTextsParams, } from './message-spec'; import { assertSingleMessageInfo } from './utils'; export const restoreEntryMessageSpec: MessageSpec< RestoreEntryMessageData, RawRestoreEntryMessageInfo, RestoreEntryMessageInfo, > = Object.freeze({ messageContentForServerDB( data: RestoreEntryMessageData | RawRestoreEntryMessageInfo, ): string { return JSON.stringify({ entryID: data.entryID, date: data.date, text: data.text, }); }, messageContentForClientDB(data: RawRestoreEntryMessageInfo): string { return this.messageContentForServerDB(data); }, messageTitle({ messageInfo, threadInfo, viewerContext, }: MessageTitleParam) { let validMessageInfo: RestoreEntryMessageInfo = (messageInfo: RestoreEntryMessageInfo); if (viewerContext === 'global_viewer') { validMessageInfo = removeCreatorAsViewer(validMessageInfo); } return robotextToRawString( robotextForMessageInfo(validMessageInfo, threadInfo), ); }, rawMessageInfoFromServerDBRow(row: Object): RawRestoreEntryMessageInfo { const content = JSON.parse(row.content); return { type: messageTypes.RESTORE_ENTRY, id: row.id.toString(), threadID: row.threadID.toString(), time: row.time, creatorID: row.creatorID.toString(), entryID: content.entryID, date: content.date, text: content.text, }; }, rawMessageInfoFromClientDB( clientDBMessageInfo: ClientDBMessageInfo, ): RawRestoreEntryMessageInfo { invariant( clientDBMessageInfo.content !== undefined && clientDBMessageInfo.content !== null, 'content must be defined', ); const content = JSON.parse(clientDBMessageInfo.content); const rawRestoreEntryMessageInfo: RawRestoreEntryMessageInfo = { type: messageTypes.RESTORE_ENTRY, id: clientDBMessageInfo.id, threadID: clientDBMessageInfo.thread, time: parseInt(clientDBMessageInfo.time), creatorID: clientDBMessageInfo.user, entryID: content.entryID, date: content.date, text: content.text, }; return rawRestoreEntryMessageInfo; }, createMessageInfo( rawMessageInfo: RawRestoreEntryMessageInfo, creator: RelativeUserInfo, ): RestoreEntryMessageInfo { return { type: messageTypes.RESTORE_ENTRY, id: rawMessageInfo.id, threadID: rawMessageInfo.threadID, creator, time: rawMessageInfo.time, entryID: rawMessageInfo.entryID, date: rawMessageInfo.date, text: rawMessageInfo.text, }; }, rawMessageInfoFromMessageData( messageData: RestoreEntryMessageData, id: ?string, ): RawRestoreEntryMessageInfo { invariant(id, 'RawRestoreEntryMessageInfo needs id'); return { ...messageData, id }; }, - robotext(messageInfo: RestoreEntryMessageInfo, creator: string): string { + robotext(messageInfo: RestoreEntryMessageInfo): EntityText { const date = prettyDate(messageInfo.date); - return ( - `${creator} restored an event scheduled for ${date}: ` + - `"${encodeURI(messageInfo.text)}"` - ); + const creator = ET.user({ userInfo: messageInfo.creator }); + const { text } = messageInfo; + return ET`${creator} restored an event scheduled for ${date}: "${text}"`; }, notificationTexts( messageInfos: $ReadOnlyArray, threadInfo: ThreadInfo, params: NotificationTextsParams, ): NotifTexts { const messageInfo = assertSingleMessageInfo(messageInfos); invariant( messageInfo.type === messageTypes.RESTORE_ENTRY, 'messageInfo should be messageTypes.RESTORE_ENTRY!', ); const prefix = stringForUser(messageInfo.creator); const body = `restored an event in ${params.notifThreadName(threadInfo)} ` + `scheduled for ${prettyDate(messageInfo.date)}: "${messageInfo.text}"`; const merged = `${prefix} ${body}`; return { merged, title: threadInfo.uiName, body, prefix, }; }, generatesNotifs: async () => pushTypes.NOTIF, });