diff --git a/lib/actions/entry-actions.js b/lib/actions/entry-actions.js --- a/lib/actions/entry-actions.js +++ b/lib/actions/entry-actions.js @@ -1,8 +1,6 @@ // @flow -import invariant from 'invariant'; import * as React from 'react'; -import uuid from 'uuid'; import { extractKeyserverIDFromID, @@ -10,17 +8,9 @@ } 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 { - dmOperationSpecificationTypes, - type OutboundDMOperationSpecification, -} from '../shared/dm-ops/dm-op-types.js'; import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import { getNextLocalID } from '../shared/message-utils.js'; -import { - type DMCreateEntryOperation, - type DMEditEntryOperation, - type DMDeleteEntryOperation, -} from '../types/dm-ops.js'; +import { threadSpecs } from '../shared/threads/thread-specs.js'; import type { RawEntryInfo, CalendarQuery, @@ -37,14 +27,7 @@ } from '../types/entry-types.js'; import type { HistoryRevisionInfo } from '../types/history-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types'; -import { - thickThreadTypes, - threadTypeIsThick, -} from '../types/thread-types-enum.js'; -import { - dateFromString, - dateString as stringFromDate, -} from '../utils/date-utils.js'; +import { dateFromString } from '../utils/date-utils.js'; import { useSelector } from '../utils/redux-utils.js'; const fetchEntriesActionTypes = Object.freeze({ @@ -216,52 +199,11 @@ const keyserverCall = useKeyserverCall(createEntry); return React.useCallback( - async (input: UseCreateEntryInput) => { - if (!threadTypeIsThick(input.threadInfo.type)) { - const result = await keyserverCall(input.createEntryInfo); - return result; - } - - invariant(viewerID, 'viewerID must be set'); - const entryID = uuid.v4(); - - const { createEntryInfo, threadInfo } = input; - const op: DMCreateEntryOperation = { - type: 'create_entry', - threadID: threadInfo.id, - creatorID: viewerID, - time: createEntryInfo.timestamp, - entryID: uuid.v4(), - entryDate: createEntryInfo.date, - text: createEntryInfo.text, - messageID: uuid.v4(), - }; - const opSpecification: OutboundDMOperationSpecification = { - type: dmOperationSpecificationTypes.OUTBOUND, - op, - recipients: { - type: 'all_thread_members', - threadID: - threadInfo.type === thickThreadTypes.THICK_SIDEBAR && - threadInfo.parentThreadID - ? threadInfo.parentThreadID - : threadInfo.id, - }, - }; - - await processAndSendDMOperation(opSpecification); - - return { - entryID, - newMessageInfos: [], - threadID: createEntryInfo.threadID, - localID: createEntryInfo.localID, - updatesResult: { - viewerUpdates: [], - userInfos: [], - }, - }; - }, + (input: UseCreateEntryInput) => + threadSpecs[input.threadInfo.type].protocol.createCalendarEntry( + { input, viewerID }, + { processAndSendDMOperation, keyserverCreateEntry: keyserverCall }, + ), [keyserverCall, processAndSendDMOperation, viewerID], ); } @@ -313,55 +255,15 @@ const entryInfos = useSelector(state => state.entryStore.entryInfos); return React.useCallback( - async (input: UseSaveEntryInput) => { - if (!threadTypeIsThick(input.threadInfo.type)) { - const result = await keyserverCall(input.saveEntryInfo); - return result; - } - const { saveEntryInfo, threadInfo } = input; - const prevEntry = entryInfos[saveEntryInfo.entryID]; - - invariant(viewerID, 'viewerID must be set'); - - const op: DMEditEntryOperation = { - type: 'edit_entry', - threadID: threadInfo.id, - creatorID: viewerID, - creationTime: prevEntry.creationTime, - time: saveEntryInfo.timestamp, - entryID: saveEntryInfo.entryID, - entryDate: stringFromDate( - prevEntry.year, - prevEntry.month, - prevEntry.day, - ), - text: saveEntryInfo.text, - messageID: uuid.v4(), - }; - const opSpecification: OutboundDMOperationSpecification = { - type: dmOperationSpecificationTypes.OUTBOUND, - op, - recipients: { - type: 'all_thread_members', - threadID: - threadInfo.type === thickThreadTypes.THICK_SIDEBAR && - threadInfo.parentThreadID - ? threadInfo.parentThreadID - : threadInfo.id, + (input: UseSaveEntryInput) => + threadSpecs[input.threadInfo.type].protocol.editCalendarEntry( + { + input, + viewerID, + originalEntry: entryInfos[input.saveEntryInfo.entryID], }, - }; - - await processAndSendDMOperation(opSpecification); - - return { - entryID: saveEntryInfo.entryID, - newMessageInfos: [], - updatesResult: { - viewerUpdates: [], - userInfos: [], - }, - }; - }, + { processAndSendDMOperation, keyserverEditEntry: keyserverCall }, + ), [keyserverCall, processAndSendDMOperation, viewerID, entryInfos], ); } @@ -413,56 +315,15 @@ const entryInfos = useSelector(state => state.entryStore.entryInfos); return React.useCallback( - async (input: UseDeleteEntryInput) => { - if (!threadTypeIsThick(input.threadInfo.type)) { - const result = await keyserverCall(input.deleteEntryInfo); - return result; - } - const { deleteEntryInfo, threadInfo } = input; - const prevEntry = entryInfos[deleteEntryInfo.entryID]; - - invariant(viewerID, 'viewerID must be set'); - - const op: DMDeleteEntryOperation = { - type: 'delete_entry', - threadID: threadInfo.id, - creatorID: viewerID, - creationTime: prevEntry.creationTime, - time: Date.now(), - entryID: deleteEntryInfo.entryID, - entryDate: stringFromDate( - prevEntry.year, - prevEntry.month, - prevEntry.day, - ), - prevText: deleteEntryInfo.prevText, - messageID: uuid.v4(), - }; - - const opSpecification: OutboundDMOperationSpecification = { - type: dmOperationSpecificationTypes.OUTBOUND, - op, - recipients: { - type: 'all_thread_members', - threadID: - threadInfo.type === thickThreadTypes.THICK_SIDEBAR && - threadInfo.parentThreadID - ? threadInfo.parentThreadID - : threadInfo.id, - }, - }; - - await processAndSendDMOperation(opSpecification); - - return { - threadID: threadInfo.id, - newMessageInfos: [], - updatesResult: { - viewerUpdates: [], - userInfos: [], + (input: UseDeleteEntryInput) => + threadSpecs[input.threadInfo.type].protocol.deleteCalendarEntry( + { + input, + viewerID, + originalEntry: entryInfos[input.deleteEntryInfo.entryID], }, - }; - }, + { processAndSendDMOperation, keyserverDeleteEntry: keyserverCall }, + ), [keyserverCall, processAndSendDMOperation, viewerID, entryInfos], ); } diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js --- a/lib/shared/threads/protocols/dm-thread-protocol.js +++ b/lib/shared/threads/protocols/dm-thread-protocol.js @@ -6,26 +6,36 @@ import type { TunnelbrokerSocketState } from '../../../tunnelbroker/tunnelbroker-context.js'; import type { DMChangeThreadSettingsOperation, + DMCreateEntryOperation, + DMDeleteEntryOperation, + DMEditEntryOperation, DMSendEditMessageOperation, DMThreadSettingsChanges, } from '../../../types/dm-ops.js'; import { thickThreadTypes } from '../../../types/thread-types-enum.js'; import type { ChangeThreadSettingsPayload } from '../../../types/thread-types.js'; +import { dateString as stringFromDate } from '../../../utils/date-utils.js'; import { SendMessageError } from '../../../utils/errors.js'; import { dmOperationSpecificationTypes, type OutboundDMOperationSpecification, } from '../../dm-ops/dm-op-types.js'; -import { - type ProtocolSendTextMessageInput, - type SendMultimediaMessageUtils, - type SendTextMessageUtils, - type ThreadProtocol, - type ProtocolSendMultimediaMessageInput, - type ProtocolEditTextMessageInput, - type EditTextMessageUtils, - type ProtocolChangeThreadSettingsInput, - type ChangeThreadSettingsUtils, +import type { + ProtocolSendTextMessageInput, + SendMultimediaMessageUtils, + SendTextMessageUtils, + ThreadProtocol, + ProtocolSendMultimediaMessageInput, + ProtocolEditTextMessageInput, + EditTextMessageUtils, + ProtocolChangeThreadSettingsInput, + ChangeThreadSettingsUtils, + ProtocolCreateEntryInput, + CreateEntryUtils, + ProtocolDeleteEntryInput, + DeleteEntryUtils, + ProtocolEditEntryInput, + EditEntryUtils, } from '../thread-spec.js'; const dmThreadProtocol: ThreadProtocol = Object.freeze({ @@ -245,6 +255,144 @@ calendarIsOnline: (tunnelbrokerSocketState: TunnelbrokerSocketState) => !!tunnelbrokerSocketState.connected, + + createCalendarEntry: async ( + protocolInput: ProtocolCreateEntryInput, + utils: CreateEntryUtils, + ) => { + const { viewerID, input } = protocolInput; + + invariant(viewerID, 'viewerID must be set'); + const entryID = uuid.v4(); + + const { createEntryInfo, threadInfo } = input; + const op: DMCreateEntryOperation = { + type: 'create_entry', + threadID: threadInfo.id, + creatorID: viewerID, + time: createEntryInfo.timestamp, + entryID: uuid.v4(), + entryDate: createEntryInfo.date, + text: createEntryInfo.text, + messageID: uuid.v4(), + }; + const opSpecification: OutboundDMOperationSpecification = { + type: dmOperationSpecificationTypes.OUTBOUND, + op, + recipients: { + type: 'all_thread_members', + threadID: + threadInfo.type === thickThreadTypes.THICK_SIDEBAR && + threadInfo.parentThreadID + ? threadInfo.parentThreadID + : threadInfo.id, + }, + }; + + await utils.processAndSendDMOperation(opSpecification); + + return { + entryID, + newMessageInfos: [], + threadID: createEntryInfo.threadID, + localID: createEntryInfo.localID, + updatesResult: { + viewerUpdates: [], + userInfos: [], + }, + }; + }, + + deleteCalendarEntry: async ( + protocolInput: ProtocolDeleteEntryInput, + utils: DeleteEntryUtils, + ) => { + const { viewerID, input, originalEntry: prevEntry } = protocolInput; + const { deleteEntryInfo, threadInfo } = input; + + invariant(viewerID, 'viewerID must be set'); + + const op: DMDeleteEntryOperation = { + type: 'delete_entry', + threadID: threadInfo.id, + creatorID: viewerID, + creationTime: prevEntry.creationTime, + time: Date.now(), + entryID: deleteEntryInfo.entryID, + entryDate: stringFromDate(prevEntry.year, prevEntry.month, prevEntry.day), + prevText: deleteEntryInfo.prevText, + messageID: uuid.v4(), + }; + + const opSpecification: OutboundDMOperationSpecification = { + type: dmOperationSpecificationTypes.OUTBOUND, + op, + recipients: { + type: 'all_thread_members', + threadID: + threadInfo.type === thickThreadTypes.THICK_SIDEBAR && + threadInfo.parentThreadID + ? threadInfo.parentThreadID + : threadInfo.id, + }, + }; + + await utils.processAndSendDMOperation(opSpecification); + + return { + threadID: threadInfo.id, + newMessageInfos: [], + updatesResult: { + viewerUpdates: [], + userInfos: [], + }, + }; + }, + + editCalendarEntry: async ( + protocolInput: ProtocolEditEntryInput, + utils: EditEntryUtils, + ) => { + const { viewerID, input, originalEntry: prevEntry } = protocolInput; + const { saveEntryInfo, threadInfo } = input; + + invariant(viewerID, 'viewerID must be set'); + + const op: DMEditEntryOperation = { + type: 'edit_entry', + threadID: threadInfo.id, + creatorID: viewerID, + creationTime: prevEntry.creationTime, + time: saveEntryInfo.timestamp, + entryID: saveEntryInfo.entryID, + entryDate: stringFromDate(prevEntry.year, prevEntry.month, prevEntry.day), + text: saveEntryInfo.text, + messageID: uuid.v4(), + }; + const opSpecification: OutboundDMOperationSpecification = { + type: dmOperationSpecificationTypes.OUTBOUND, + op, + recipients: { + type: 'all_thread_members', + threadID: + threadInfo.type === thickThreadTypes.THICK_SIDEBAR && + threadInfo.parentThreadID + ? threadInfo.parentThreadID + : threadInfo.id, + }, + }; + + await utils.processAndSendDMOperation(opSpecification); + + return { + entryID: saveEntryInfo.entryID, + newMessageInfos: [], + updatesResult: { + viewerUpdates: [], + userInfos: [], + }, + }; + }, }); export { dmThreadProtocol }; diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -31,16 +31,22 @@ blobHashFromBlobServiceURI, isBlobServiceURI, } from '../../../utils/blob-service.js'; -import { - type ThreadProtocol, - type ProtocolSendTextMessageInput, - type SendTextMessageUtils, - type ProtocolSendMultimediaMessageInput, - type SendMultimediaMessageUtils, - type ProtocolEditTextMessageInput, - type EditTextMessageUtils, - type ProtocolChangeThreadSettingsInput, - type ChangeThreadSettingsUtils, +import type { + ThreadProtocol, + ProtocolSendTextMessageInput, + SendTextMessageUtils, + ProtocolSendMultimediaMessageInput, + SendMultimediaMessageUtils, + ProtocolEditTextMessageInput, + EditTextMessageUtils, + ProtocolChangeThreadSettingsInput, + ChangeThreadSettingsUtils, + ProtocolCreateEntryInput, + CreateEntryUtils, + ProtocolDeleteEntryInput, + DeleteEntryUtils, + ProtocolEditEntryInput, + EditEntryUtils, } from '../thread-spec.js'; const keyserverThreadProtocol: ThreadProtocol = Object.freeze({ @@ -179,6 +185,21 @@ tunnelbrokerSocketState: TunnelbrokerSocketState, isKeyserverConnected: boolean, ) => isKeyserverConnected, + + createCalendarEntry: ( + protocolInput: ProtocolCreateEntryInput, + utils: CreateEntryUtils, + ) => utils.keyserverCreateEntry(protocolInput.input.createEntryInfo), + + deleteCalendarEntry: ( + protocolInput: ProtocolDeleteEntryInput, + utils: DeleteEntryUtils, + ) => utils.keyserverDeleteEntry(protocolInput.input.deleteEntryInfo), + + editCalendarEntry: ( + protocolInput: ProtocolEditEntryInput, + utils: EditEntryUtils, + ) => utils.keyserverEditEntry(protocolInput.input.saveEntryInfo), }); function mediaIDIsKeyserverID(mediaID: string): boolean { diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -1,5 +1,10 @@ // @flow +import type { + UseCreateEntryInput, + UseDeleteEntryInput, + UseSaveEntryInput, +} from '../../actions/entry-actions.js'; import { type ProcessHolders } from '../../actions/holder-actions.js'; import { type LegacySendMultimediaMessageInput, @@ -10,6 +15,15 @@ import { type MediaMetadataReassignmentAction } from '../../actions/upload-actions.js'; import type { ProcessOutboundP2PMessagesResult } from '../../tunnelbroker/peer-to-peer-context.js'; import type { TunnelbrokerSocketState } from '../../tunnelbroker/tunnelbroker-context.js'; +import type { + CreateEntryInfo, + CreateEntryPayload, + DeleteEntryInfo, + DeleteEntryResult, + RawEntryInfo, + SaveEntryInfo, + SaveEntryResult, +} from '../../types/entry-types.js'; import type { SendMessageResult, SendMessagePayload, @@ -89,6 +103,35 @@ +keyserverChangeThreadSettings: UpdateThreadRequest => Promise, }; +export type ProtocolCreateEntryInput = { + +input: UseCreateEntryInput, + +viewerID: ?string, +}; +export type CreateEntryUtils = { + +processAndSendDMOperation: OutboundDMOperationSpecification => Promise, + +keyserverCreateEntry: CreateEntryInfo => Promise, +}; + +export type ProtocolDeleteEntryInput = { + +input: UseDeleteEntryInput, + +viewerID: ?string, + +originalEntry: RawEntryInfo, +}; +export type DeleteEntryUtils = { + +processAndSendDMOperation: OutboundDMOperationSpecification => Promise, + +keyserverDeleteEntry: DeleteEntryInfo => Promise, +}; + +export type ProtocolEditEntryInput = { + +input: UseSaveEntryInput, + +viewerID: ?string, + +originalEntry: RawEntryInfo, +}; +export type EditEntryUtils = { + +processAndSendDMOperation: OutboundDMOperationSpecification => Promise, + +keyserverEditEntry: SaveEntryInfo => Promise, +}; + export type ThreadProtocol = { +sendTextMessage: ( message: ProtocolSendTextMessageInput, @@ -111,6 +154,18 @@ tunnelbrokerSocketState: TunnelbrokerSocketState, isKeyserverConnected: boolean, ) => boolean, + +createCalendarEntry: ( + input: ProtocolCreateEntryInput, + utils: CreateEntryUtils, + ) => Promise, + +deleteCalendarEntry: ( + input: ProtocolDeleteEntryInput, + utils: DeleteEntryUtils, + ) => Promise, + +editCalendarEntry: ( + input: ProtocolEditEntryInput, + utils: EditEntryUtils, + ) => Promise, }; export type ThreadSpec = {