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 @@ -146,6 +146,7 @@ time: Date.now(), userIDs: memberIDs, newRole: request.role, + roleName: threadInfo.roles[request.role].name, }; const newMessageInfos = await createMessages(viewer, [messageData]); diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js --- a/lib/shared/message-utils.js +++ b/lib/shared/message-utils.js @@ -44,6 +44,7 @@ import type { UserInfos } from '../types/user-types.js'; import { type EntityText, + ET, useEntityTextAsString, } from '../utils/entity-text.js'; @@ -624,6 +625,17 @@ return item; } +function constructChangeRoleEntityText( + affectedUsers: EntityText | string, + roleName: ?string, +): EntityText { + if (!roleName) { + return ET`assigned ${affectedUsers} a new role`; + } + + return ET`assigned ${affectedUsers} the \"${roleName}\" role`; +} + export { localIDPrefix, messageKey, @@ -651,4 +663,5 @@ useMessageCreationSideEffectsFunc, getPinnedContentFromMessage, modifyItemForResultScreen, + constructChangeRoleEntityText, }; diff --git a/lib/shared/messages/change-role-message-spec.js b/lib/shared/messages/change-role-message-spec.js --- a/lib/shared/messages/change-role-message-spec.js +++ b/lib/shared/messages/change-role-message-spec.js @@ -9,6 +9,7 @@ type RobotextParams, } from './message-spec.js'; import { joinResult } from './utils.js'; +import type { PlatformDetails } from '../../types/device-types.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { MessageInfo, @@ -20,6 +21,7 @@ type RawChangeRoleMessageInfo, rawChangeRoleMessageInfoValidator, } from '../../types/messages/change-role.js'; +import type { RawUnsupportedMessageInfo } from '../../types/messages/unsupported'; import type { NotifTexts } from '../../types/notif-types.js'; import type { ThreadInfo } from '../../types/thread-types.js'; import type { RelativeUserInfo } from '../../types/user-types.js'; @@ -28,8 +30,11 @@ type EntityText, pluralizeEntityText, } from '../../utils/entity-text.js'; +import { entityTextToRawString } from '../../utils/entity-text.js'; import { values } from '../../utils/objects.js'; +import { constructChangeRoleEntityText } from '../message-utils.js'; import { notifRobotextForMessageInfo } from '../notif-utils.js'; +import { NEXT_CODE_VERSION, hasMinCodeVersion } from '../version-utils.js'; export const changeRoleMessageSpec: MessageSpec< ChangeRoleMessageData, @@ -42,6 +47,7 @@ return JSON.stringify({ userIDs: data.userIDs, newRole: data.newRole, + roleName: data.roleName, }); }, @@ -59,6 +65,7 @@ creatorID: row.creatorID.toString(), userIDs: content.userIDs, newRole: content.newRole, + roleName: content.roleName, }; }, @@ -79,6 +86,7 @@ creatorID: clientDBMessageInfo.user, userIDs: content.userIDs, newRole: content.newRole, + roleName: content.roleName, }; return rawChangeRoleMessageInfo; }, @@ -97,6 +105,7 @@ time: rawMessageInfo.time, members, newRole: rawMessageInfo.newRole, + roleName: rawMessageInfo.roleName, }; }, @@ -122,9 +131,22 @@ const { threadInfo } = params; invariant(threadInfo, 'ThreadInfo should be set for CHANGE_ROLE message'); - const roleName = threadInfo.roles[messageInfo.newRole].name; - return ET`${creator} assigned ${affectedUsers} the \"${roleName}\" role`; + const threadRoleName = threadInfo.roles[messageInfo.newRole]?.name; + const messageInfoRoleName = messageInfo.roleName; + + const roleName = threadRoleName ?? messageInfoRoleName; + invariant( + roleName, + 'roleName should either be derived from threadInfo or messageInfo', + ); + + const constructedEntityText = constructChangeRoleEntityText( + affectedUsers, + roleName, + ); + + return ET`${creator} ${constructedEntityText}`; }, async notificationTexts( @@ -162,6 +184,43 @@ }; }, + shimUnsupportedMessageInfo( + rawMessageInfo: RawChangeRoleMessageInfo, + platformDetails: ?PlatformDetails, + ): RawChangeRoleMessageInfo | RawUnsupportedMessageInfo { + if (hasMinCodeVersion(platformDetails, { native: NEXT_CODE_VERSION })) { + return rawMessageInfo; + } + + const { id, userIDs } = rawMessageInfo; + invariant(id !== null && id !== undefined, 'id should be set on server'); + + const affectedUsers = userIDs.length === 1 ? 'a member' : 'some members'; + const roleName = rawMessageInfo.roleName; + + const constructedEntityText = constructChangeRoleEntityText( + affectedUsers, + roleName, + ); + const stringifiedEntityText = entityTextToRawString(constructedEntityText); + + return { + type: messageTypes.UNSUPPORTED, + id, + threadID: rawMessageInfo.threadID, + creatorID: rawMessageInfo.creatorID, + time: rawMessageInfo.time, + robotext: stringifiedEntityText, + unsupportedMessageInfo: rawMessageInfo, + }; + }, + + unshimMessageInfo( + unwrapped: RawChangeRoleMessageInfo, + ): RawChangeRoleMessageInfo { + return unwrapped; + }, + notificationCollapseKey(rawMessageInfo: RawChangeRoleMessageInfo): string { return joinResult( rawMessageInfo.type, diff --git a/lib/types/messages/change-role.js b/lib/types/messages/change-role.js --- a/lib/types/messages/change-role.js +++ b/lib/types/messages/change-role.js @@ -7,17 +7,18 @@ import type { RelativeUserInfo } from '../user-types.js'; export type ChangeRoleMessageData = { - type: 6, - threadID: string, - creatorID: string, - time: number, - userIDs: string[], - newRole: string, + +type: 6, + +threadID: string, + +creatorID: string, + +time: number, + +userIDs: string[], + +newRole: string, + +roleName?: string, // Older clients will not have this field }; export type RawChangeRoleMessageInfo = { ...ChangeRoleMessageData, - id: string, + +id: string, }; export const rawChangeRoleMessageInfoValidator: TInterface = @@ -29,14 +30,16 @@ userIDs: t.list(t.String), newRole: tID, id: tID, + roleName: t.maybe(t.String), }); export type ChangeRoleMessageInfo = { - type: 6, - id: string, - threadID: string, - creator: RelativeUserInfo, - time: number, - members: RelativeUserInfo[], - newRole: string, + +type: 6, + +id: string, + +threadID: string, + +creator: RelativeUserInfo, + +time: number, + +members: RelativeUserInfo[], + +newRole: string, + +roleName?: string, // Older clients will not have this field };