diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js --- a/keyserver/src/updaters/thread-updaters.js +++ b/keyserver/src/updaters/thread-updaters.js @@ -1,5 +1,7 @@ // @flow +import { getRustAPI } from 'rust-node-addon'; + import { specialRoles } from 'lib/permissions/special-roles.js'; import { getRolePermissionBlobs } from 'lib/permissions/thread-permissions.js'; import { filteredThreadIDs } from 'lib/selectors/calendar-filter-selectors.js'; @@ -48,6 +50,7 @@ import { fetchCommunityFarcasterChannelTag } from '../fetchers/community-fetchers.js'; import { checkIfInviteLinkIsValid } from '../fetchers/link-fetchers.js'; import { fetchMessageInfoByID } from '../fetchers/message-fetchers.js'; +import { fetchRoles } from '../fetchers/role-fetchers.js'; import { fetchThreadInfos, fetchServerThreadInfos, @@ -66,6 +69,9 @@ verifyUserOrCookieIDs, } from '../fetchers/user-fetchers.js'; import type { Viewer } from '../session/viewer.js'; +import { verifyUserLoggedIn } from '../user/login.js'; +import { neynarClient } from '../utils/fc-cache.js'; +import { getContentSigningKey } from '../utils/olm-utils.js'; import RelationshipChangeset from '../utils/relationship-changeset.js'; type UpdateRoleOptions = { @@ -825,6 +831,11 @@ throw new ServerError('not_logged_in'); } + const communityFarcasterChannelTagPromise = fetchCommunityFarcasterChannelTag( + viewer, + request.threadID, + ); + const permissionPromise = (async () => { if (request.inviteLinkSecret) { return await checkIfInviteLinkIsValid( @@ -839,9 +850,6 @@ threadPermissions.JOIN_THREAD, ); - const communityFarcasterChannelTagPromise = - fetchCommunityFarcasterChannelTag(viewer, request.threadID); - const [threadPermission, communityFarcasterChannelTag] = await Promise.all([ threadPermissionPromise, communityFarcasterChannelTagPromise, @@ -850,10 +858,13 @@ return threadPermission || !!communityFarcasterChannelTag; })(); - const [isMember, hasPermission] = await Promise.all([ - fetchViewerIsMember(viewer, request.threadID), - permissionPromise, - ]); + const [isMember, hasPermission, communityFarcasterChannelTag] = + await Promise.all([ + fetchViewerIsMember(viewer, request.threadID), + permissionPromise, + communityFarcasterChannelTagPromise, + ]); + if (!hasPermission) { throw new ServerError('invalid_parameters'); } @@ -882,7 +893,16 @@ } } - const changeset = await changeRole(request.threadID, [viewer.userID], null, { + let role = null; + if (communityFarcasterChannelTag) { + role = await fetchUserRoleForThread( + viewer, + request.threadID, + communityFarcasterChannelTag, + ); + } + + const changeset = await changeRole(request.threadID, [viewer.userID], role, { defaultSubscription: request.defaultSubscription, }); @@ -912,6 +932,50 @@ }; } +async function fetchUserRoleForThread( + viewer: Viewer, + threadID: string, + communityFarcasterChannelTag: string, +): Promise { + const [rustAPI, identityInfo, deviceID] = await Promise.all([ + getRustAPI(), + verifyUserLoggedIn(), + getContentSigningKey(), + ]); + + const response = await rustAPI.findUserIdentities( + identityInfo.userId, + deviceID, + identityInfo.accessToken, + [viewer.userID], + ); + + const { farcasterID } = response.identities[viewer.userID]; + + if (!farcasterID) { + return null; + } + + const ledChannels = + await neynarClient?.fetchLedFarcasterChannels(farcasterID); + + if ( + !ledChannels || + !ledChannels.some(channel => channel.id === communityFarcasterChannelTag) + ) { + return null; + } + + const roleInfos = await fetchRoles(threadID); + for (const roleInfo of roleInfos) { + if (roleInfo.specialRole === specialRoles.ADMIN_ROLE) { + return roleInfo.id; + } + } + + return null; +} + async function toggleMessagePinForThread( viewer: Viewer, request: ToggleMessagePinRequest,