From a0bb6003792140bbd7e963539fbbd4dd73e289bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20W=C4=85sowicz?= Date: Wed, 4 Sep 2024 11:56:31 +0200 Subject: [PATCH] Implement updating DM thread subscription Summary: This differential implements synchronizing thread subscription in dm threads. Test Plan: 1. Create dm thread and add another user. (Use UI button implemented by Kamil) 2. Play around with changing thread subscription and sending notifs. Reviewers: kamil, tomek Reviewed By: tomek Subscribers: ashoat Differential Revision: https://phab.comm.dev/D13236 --- lib/actions/user-actions.js | 59 +++++++++++++++++-- .../dm-ops/change-thread-subscription.js | 9 +++ .../thread-settings-notifications-utils.js | 2 +- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js index afc1d6b2bd..62c8b9553b 100644 --- a/lib/actions/user-actions.js +++ b/lib/actions/user-actions.js @@ -26,6 +26,9 @@ import { getPrekeyValueFromBlob, } from '../shared/crypto-utils.js'; import { fetchLatestDeviceList } from '../shared/device-list-utils.js'; +import type { OutboundDMOperationSpecification } from '../shared/dm-ops/dm-op-utils'; +import { dmOperationSpecificationTypes } from '../shared/dm-ops/dm-op-utils.js'; +import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; import threadWatcher from '../shared/thread-watcher.js'; import { @@ -54,6 +57,7 @@ import type { UpdateUserAvatarRequest, UpdateUserAvatarResponse, } from '../types/avatar-types.js'; +import type { DMChangeThreadSubscriptionOperation } from '../types/dm-ops'; import type { RawEntryInfo, CalendarQuery } from '../types/entry-types.js'; import type { UserIdentitiesResponse, @@ -63,6 +67,7 @@ import type { RawMessageInfo, MessageTruncationStatuses, } from '../types/message-types.js'; +import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types'; import type { GetOlmSessionInitializationDataResponse } from '../types/olm-session-types.js'; import type { UserSearchResult, @@ -73,6 +78,10 @@ import type { SubscriptionUpdateRequest, SubscriptionUpdateResult, } from '../types/subscription-types.js'; +import { + thickThreadTypes, + threadTypeIsThick, +} from '../types/thread-types-enum.js'; import type { RawThreadInfos } from '../types/thread-types.js'; import { userActionsP2PMessageTypes, @@ -1200,10 +1209,52 @@ const updateSubscription = }; }; -function useUpdateSubscription(): ( - input: SubscriptionUpdateRequest, -) => Promise { - return useKeyserverCall(updateSubscription); +function useUpdateSubscription( + threadInfo: ThreadInfo, +): (input: SubscriptionUpdateRequest) => Promise { + const processAndSendDMOperation = useProcessAndSendDMOperation(); + const viewerID = useSelector( + state => state.currentUserInfo && state.currentUserInfo.id, + ); + const keyserverCall = useKeyserverCall(updateSubscription); + + return React.useCallback( + async (input: SubscriptionUpdateRequest) => { + if (!threadTypeIsThick(threadInfo.type)) { + return await keyserverCall(input); + } + + invariant(viewerID, 'viewerID must be set'); + const subscription = { + ...threadInfo.currentUser.subscription, + ...input.updatedFields, + }; + const op: DMChangeThreadSubscriptionOperation = { + type: 'change_thread_subscription', + time: Date.now(), + threadID: threadInfo.id, + creatorID: viewerID, + subscription, + }; + + 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, subscription }; + }, + [keyserverCall, processAndSendDMOperation, viewerID, threadInfo], + ); } const setUserSettingsActionTypes = Object.freeze({ diff --git a/lib/shared/dm-ops/change-thread-subscription.js b/lib/shared/dm-ops/change-thread-subscription.js index 91f02a1cbb..2897956b0e 100644 --- a/lib/shared/dm-ops/change-thread-subscription.js +++ b/lib/shared/dm-ops/change-thread-subscription.js @@ -42,10 +42,18 @@ const changeThreadSubscriptionSpec: DMOperationSpec member.id !== creatorID, ); const membersUpdate = [...otherMemberInfos, updatedCreatorMemberInfo]; + const currentUserUpdate = + viewerID === creatorID + ? { + ...threadInfo.currentUser, + subscription, + } + : threadInfo.currentUser; const threadInfoUpdate = { ...threadInfo, members: membersUpdate, + currentUser: currentUserUpdate, timestamps: { ...threadInfo.timestamps, members: { @@ -57,6 +65,7 @@ const changeThreadSubscriptionSpec: DMOperationSpec = [ { type: updateTypes.UPDATE_THREAD, diff --git a/lib/shared/thread-settings-notifications-utils.js b/lib/shared/thread-settings-notifications-utils.js index 05631c48fa..2f3fab1fcf 100644 --- a/lib/shared/thread-settings-notifications-utils.js +++ b/lib/shared/thread-settings-notifications-utils.js @@ -102,7 +102,7 @@ function useThreadSettingsNotifications( const dispatchActionPromise = useDispatchActionPromise(); - const callUpdateSubscription = useUpdateSubscription(); + const callUpdateSubscription = useUpdateSubscription(threadInfo); const updateSubscriptionPromise = React.useCallback(async () => { const res = await callUpdateSubscription({