diff --git a/keyserver/src/database/migration-config.js b/keyserver/src/database/migration-config.js --- a/keyserver/src/database/migration-config.js +++ b/keyserver/src/database/migration-config.js @@ -823,6 +823,7 @@ ); }, ], + [65, updateRolesAndPermissionsForAllThreads], ]); const newDatabaseVersion: number = Math.max(...migrations.keys()); diff --git a/keyserver/src/fetchers/thread-fetchers.js b/keyserver/src/fetchers/thread-fetchers.js --- a/keyserver/src/fetchers/thread-fetchers.js +++ b/keyserver/src/fetchers/thread-fetchers.js @@ -9,7 +9,10 @@ getContainingThreadID, getCommunity, } from 'lib/shared/thread-utils.js'; -import { hasMinCodeVersion } from 'lib/shared/version-utils.js'; +import { + NEXT_CODE_VERSION, + hasMinCodeVersion, +} from 'lib/shared/version-utils.js'; import type { AvatarDBContent, ClientAvatar } from 'lib/types/avatar-types.js'; import type { RawMessageInfo, MessageInfo } from 'lib/types/message-types.js'; import type { RawThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; @@ -289,6 +292,13 @@ native: 336, web: 79, }); + const manageFarcasterChannelTagsPermissionUnsupported = !hasMinCodeVersion( + viewer.platformDetails, + { + native: NEXT_CODE_VERSION, + web: NEXT_CODE_VERSION, + }, + ); const threadInfos: { [string]: LegacyRawThreadInfo | RawThreadInfo, @@ -305,6 +315,8 @@ filterVoicedInAnnouncementChannelsPermission: codeVersionBelow283, minimallyEncodePermissions: minimallyEncodedPermissionsSupported, includeSpecialRoleFieldInRoles: specialRoleFieldSupported, + filterManageFarcasterChannelTagsPermission: + manageFarcasterChannelTagsPermissionUnsupported, }, ); if (threadInfo) { diff --git a/lib/permissions/minimally-encoded-thread-permissions-test-data.js b/lib/permissions/minimally-encoded-thread-permissions-test-data.js --- a/lib/permissions/minimally-encoded-thread-permissions-test-data.js +++ b/lib/permissions/minimally-encoded-thread-permissions-test-data.js @@ -97,6 +97,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, isSender: false, }, @@ -184,6 +188,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, isSender: true, }, @@ -293,6 +301,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, subscription: { home: true, @@ -470,6 +482,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, isSender: false, }, @@ -565,6 +581,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, isSender: true, }, @@ -682,6 +702,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, subscription: { home: true, diff --git a/lib/permissions/minimally-encoded-thread-permissions.js b/lib/permissions/minimally-encoded-thread-permissions.js --- a/lib/permissions/minimally-encoded-thread-permissions.js +++ b/lib/permissions/minimally-encoded-thread-permissions.js @@ -43,6 +43,7 @@ manage_pins: BigInt(19), manage_invite_links: BigInt(20), voiced_in_announcement_channels: BigInt(21), + manage_farcaster_channel_tags: BigInt(22), }); // `minimallyEncodedThreadPermissions` is used to map each permission diff --git a/lib/permissions/minimally-encoded-thread-permissions.test.js b/lib/permissions/minimally-encoded-thread-permissions.test.js --- a/lib/permissions/minimally-encoded-thread-permissions.test.js +++ b/lib/permissions/minimally-encoded-thread-permissions.test.js @@ -53,6 +53,7 @@ manage_pins: { value: false, source: null }, manage_invite_links: { value: false, source: null }, voiced_in_announcement_channels: { value: false, source: null }, + manage_farcaster_channel_tags: { value: false, source: null }, }; describe('minimallyEncodedThreadPermissions', () => { @@ -129,6 +130,7 @@ manage_pins: { value: false, source: null }, manage_invite_links: { value: false, source: null }, voiced_in_announcement_channels: { value: false, source: null }, + manage_farcaster_channel_tags: { value: false, source: null }, }; it('should decode ThreadPermissionsInfo from bitmask', () => { @@ -170,6 +172,7 @@ manage_pins: { value: false, source: null }, manage_invite_links: { value: false, source: null }, voiced_in_announcement_channels: { value: false, source: null }, + manage_farcaster_channel_tags: { value: false, source: null }, }); }); }); @@ -626,6 +629,10 @@ value: false, source: null, }, + manage_farcaster_channel_tags: { + value: false, + source: null, + }, }, subscription: { home: true, diff --git a/lib/permissions/thread-permissions.js b/lib/permissions/thread-permissions.js --- a/lib/permissions/thread-permissions.js +++ b/lib/permissions/thread-permissions.js @@ -298,6 +298,7 @@ [threadPermissions.MANAGE_PINS]: true, [threadPermissions.MANAGE_INVITE_LINKS]: true, [threadPermissions.VOICED_IN_ANNOUNCEMENT_CHANNELS]: true, + [threadPermissions.MANAGE_FARCASTER_CHANNEL_TAGS]: true, [descendantKnowOf]: true, [descendantVisible]: true, [topLevelDescendantJoinThread]: true, diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -818,6 +818,7 @@ +filterVoicedInAnnouncementChannelsPermission?: boolean, +minimallyEncodePermissions?: boolean, +includeSpecialRoleFieldInRoles?: boolean, + +filterManageFarcasterChannelTagsPermission?: boolean, }; function rawThreadInfoFromServerThreadInfo( @@ -835,6 +836,8 @@ const shouldMinimallyEncodePermissions = options?.minimallyEncodePermissions; const shouldIncludeSpecialRoleFieldInRoles = options?.includeSpecialRoleFieldInRoles; + const filterManageFarcasterChannelTagsPermission = + options?.filterManageFarcasterChannelTagsPermission; const filterThreadPermissions = _omitBy( (v, k) => @@ -858,7 +861,9 @@ threadPermissionPropagationPrefixes.DESCENDANT + threadPermissionFilterPrefixes.TOP_LEVEL + threadPermissions.VOICED_IN_ANNOUNCEMENT_CHANNELS, - ].includes(k)), + ].includes(k)) || + (filterManageFarcasterChannelTagsPermission && + [threadPermissions.MANAGE_FARCASTER_CHANNEL_TAGS].includes(k)), ); const members = []; diff --git a/lib/types/thread-permission-types.js b/lib/types/thread-permission-types.js --- a/lib/types/thread-permission-types.js +++ b/lib/types/thread-permission-types.js @@ -33,6 +33,7 @@ MANAGE_PINS: 'manage_pins', MANAGE_INVITE_LINKS: 'manage_invite_links', VOICED_IN_ANNOUNCEMENT_CHANNELS: 'voiced_in_announcement_channels', + MANAGE_FARCASTER_CHANNEL_TAGS: 'manage_farcaster_channel_tags', }); export type ThreadPermission = $Values; @@ -61,7 +62,8 @@ ourThreadPermissions === 'edit_thread_avatar' || ourThreadPermissions === 'manage_pins' || ourThreadPermissions === 'manage_invite_links' || - ourThreadPermissions === 'voiced_in_announcement_channels', + ourThreadPermissions === 'voiced_in_announcement_channels' || + ourThreadPermissions === 'manage_farcaster_channel_tags', 'string is not threadPermissions enum', ); return ourThreadPermissions; @@ -112,6 +114,7 @@ REACT_TO_MESSAGES: 'react_to_messages', EDIT_MESSAGES: 'edit_messages', MANAGE_INVITE_LINKS: 'manage_invite_links', + MANAGE_FARCASTER_CHANNEL_TAGS: 'manage_farcaster_channel_tags', }); export type UserSurfacedPermission = $Values; export const userSurfacedPermissionsSet: $ReadOnlySet = @@ -265,6 +268,17 @@ const manageInviteLinks = threadPermissions.MANAGE_INVITE_LINKS; const manageInviteLinksPermissions = new Set([manageInviteLinks]); +const manageFarcasterChannelTagsPermission = { + title: 'Manage farcaster channel tags', + description: 'Allows members to create and delete farcaster channel tags', + userSurfacedPermission: userSurfacedPermissions.MANAGE_FARCASTER_CHANNEL_TAGS, +}; +const manageFarcasterChannelTags = + threadPermissions.MANAGE_FARCASTER_CHANNEL_TAGS; +const manageFarcasterChannelTagsPermissions = new Set([ + manageFarcasterChannelTags, +]); + export type UserSurfacedPermissionOption = { +title: string, +description: string, @@ -285,6 +299,7 @@ reactToMessagePermission, editMessagePermission, manageInviteLinksPermission, + manageFarcasterChannelTagsPermission, ]); type ConfigurableCommunityPermission = { @@ -308,6 +323,8 @@ [userSurfacedPermissions.REACT_TO_MESSAGES]: reactToMessagePermissions, [userSurfacedPermissions.EDIT_MESSAGES]: editMessagePermissions, [userSurfacedPermissions.MANAGE_INVITE_LINKS]: manageInviteLinksPermissions, + [userSurfacedPermissions.MANAGE_FARCASTER_CHANNEL_TAGS]: + manageFarcasterChannelTagsPermissions, }); export type ThreadPermissionInfo = diff --git a/native/redux/persist.js b/native/redux/persist.js --- a/native/redux/persist.js +++ b/native/redux/persist.js @@ -131,6 +131,7 @@ import { persistMigrationToRemoveSelectRolePermissions } from './remove-select-role-permissions.js'; import type { AppState } from './state-types.js'; import { unshimClientDB } from './unshim-utils.js'; +import { updateRolesAndPermissions } from './update-roles-and-permissions.js'; import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import { commCoreModule } from '../native-modules.js'; import { defaultDeviceCameraInfo } from '../types/camera.js'; @@ -1289,6 +1290,13 @@ [messageTypes.UPDATE_RELATIONSHIP], handleReduxMigrationFailure, ), + [75]: (state: AppState) => { + updateClientDBThreadStoreThreadInfos( + state, + updateRolesAndPermissions, + handleReduxMigrationFailure, + ); + }, }; type PersistedReportStore = $Diff< @@ -1310,7 +1318,7 @@ storage: AsyncStorage, blacklist: persistBlacklist, debug: __DEV__, - version: 74, + version: 75, transforms: [ messageStoreMessagesBlocklistTransform, reportStoreTransform,