Page MenuHomePhabricator

D7148.id24496.diff
No OneTemporary

D7148.id24496.diff

diff --git a/keyserver/src/fetchers/message-fetchers.js b/keyserver/src/fetchers/message-fetchers.js
--- a/keyserver/src/fetchers/message-fetchers.js
+++ b/keyserver/src/fetchers/message-fetchers.js
@@ -720,6 +720,9 @@
if (row.type === messageTypes.SIDEBAR_SOURCE) {
const content = JSON.parse(row.content);
requiredIDs.add(content.sourceMessageID);
+ } else if (row.type === messageTypes.TOGGLE_PIN) {
+ const content = JSON.parse(row.content);
+ requiredIDs.add(content.targetMessageID);
}
}
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,6 +1,7 @@
// @flow
import { filteredThreadIDs } from 'lib/selectors/calendar-filter-selectors.js';
+import { getPinnedContentFromMessage } from 'lib/shared/message-utils.js';
import {
threadHasAdminRole,
roleIsAdminRole,
@@ -43,7 +44,10 @@
import { createUpdates } from '../creators/update-creator.js';
import { dbQuery, SQL } from '../database/database.js';
import { fetchEntryInfos } from '../fetchers/entry-fetchers.js';
-import { fetchMessageInfos } from '../fetchers/message-fetchers.js';
+import {
+ fetchMessageInfos,
+ fetchMessageInfoByID,
+} from '../fetchers/message-fetchers.js';
import {
fetchThreadInfos,
fetchServerThreadInfos,
@@ -848,16 +852,17 @@
): Promise<void> {
const { messageID, action } = request;
- const threadQuery = SQL`SELECT thread FROM messages WHERE id = ${messageID}`;
- const [threadResult] = await dbQuery(threadQuery);
- const threadID = threadResult[0].thread.toString();
+ const targetMessage = await fetchMessageInfoByID(viewer, messageID);
+ if (!targetMessage) {
+ throw new ServerError('invalid_parameters');
+ }
+ const { threadID } = targetMessage;
const hasPermission = await checkThreadPermission(
viewer,
threadID,
threadPermissions.MANAGE_PINS,
);
-
if (!hasPermission) {
throw new ServerError('invalid_credentials');
}
@@ -872,6 +877,18 @@
`;
await dbQuery(togglePinQuery);
+
+ const messageData = {
+ type: messageTypes.TOGGLE_PIN,
+ threadID,
+ targetMessageID: messageID,
+ action,
+ pinnedContent: getPinnedContentFromMessage(targetMessage),
+ creatorID: viewer.userID,
+ time: Date.now(),
+ };
+
+ await createMessages(viewer, [messageData]);
}
export {
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
@@ -10,6 +10,7 @@
import { messageSpecs } from './messages/message-specs.js';
import { threadIsGroupChat } from './thread-utils.js';
import { useStringForUser } from '../hooks/ens-cache.js';
+import { contentStringForMediaArray } from '../media/media-utils.js';
import { userIDsToRelativeUserInfos } from '../selectors/user-selectors.js';
import { type PlatformDetails, isWebPlatform } from '../types/device-types.js';
import type { Media } from '../types/media-types.js';
@@ -569,6 +570,20 @@
return messageSpec.useCreationSideEffectsFunc();
}
+function getPinnedContentFromMessage(targetMessage: RawMessageInfo): string {
+ let pinnedContent;
+ if (
+ targetMessage.type === messageTypes.IMAGES ||
+ targetMessage.type === messageTypes.MULTIMEDIA
+ ) {
+ pinnedContent = contentStringForMediaArray(targetMessage.media);
+ } else {
+ pinnedContent = 'a message';
+ }
+
+ return pinnedContent;
+}
+
export {
localIDPrefix,
messageKey,
@@ -593,4 +608,5 @@
mergeThreadMessageInfos,
useMessagePreview,
useMessageCreationSideEffectsFunc,
+ getPinnedContentFromMessage,
};
diff --git a/lib/shared/messages/message-specs.js b/lib/shared/messages/message-specs.js
--- a/lib/shared/messages/message-specs.js
+++ b/lib/shared/messages/message-specs.js
@@ -19,6 +19,7 @@
import { restoreEntryMessageSpec } from './restore-entry-message-spec.js';
import { sidebarSourceMessageSpec } from './sidebar-source-message-spec.js';
import { textMessageSpec } from './text-message-spec.js';
+import { togglePinMessageSpec } from './toggle-pin-message-spec.js';
import { unsupportedMessageSpec } from './unsupported-message-spec.js';
import { updateRelationshipMessageSpec } from './update-relationship-message-spec.js';
import { messageTypes, type MessageType } from '../../types/message-types.js';
@@ -47,4 +48,5 @@
[messageTypes.CREATE_SIDEBAR]: createSidebarMessageSpec,
[messageTypes.REACTION]: reactionMessageSpec,
[messageTypes.EDIT_MESSAGE]: editMessageSpec,
+ [messageTypes.TOGGLE_PIN]: togglePinMessageSpec,
});
diff --git a/lib/shared/messages/toggle-pin-message-spec.js b/lib/shared/messages/toggle-pin-message-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/messages/toggle-pin-message-spec.js
@@ -0,0 +1,159 @@
+// @flow
+
+import invariant from 'invariant';
+
+import type {
+ MessageSpec,
+ RobotextParams,
+ RawMessageInfoFromServerDBRowParams,
+} from './message-spec.js';
+import type { PlatformDetails } from '../../types/device-types';
+import { messageTypes } from '../../types/message-types.js';
+import type { ClientDBMessageInfo } from '../../types/message-types.js';
+import type {
+ TogglePinMessageData,
+ TogglePinMessageInfo,
+ RawTogglePinMessageInfo,
+} from '../../types/messages/toggle-pin.js';
+import type { RawUnsupportedMessageInfo } from '../../types/messages/unsupported';
+import type { RelativeUserInfo } from '../../types/user-types.js';
+import { ET, type EntityText } from '../../utils/entity-text.js';
+import { getPinnedContentFromClientDBMessageInfo } from '../../utils/message-ops-utils.js';
+import { getPinnedContentFromMessage } from '../message-utils.js';
+import { hasMinCodeVersion } from '../version-utils.js';
+
+export const togglePinMessageSpec: MessageSpec<
+ TogglePinMessageData,
+ RawTogglePinMessageInfo,
+ TogglePinMessageInfo,
+> = Object.freeze({
+ messageContentForServerDB(
+ data: TogglePinMessageData | RawTogglePinMessageInfo,
+ ): string {
+ return JSON.stringify({
+ action: data.action,
+ threadID: data.threadID,
+ targetMessageID: data.targetMessageID,
+ });
+ },
+
+ messageContentForClientDB(data: RawTogglePinMessageInfo): string {
+ return this.messageContentForServerDB(data);
+ },
+
+ rawMessageInfoFromServerDBRow(
+ row: Object,
+ params: RawMessageInfoFromServerDBRowParams,
+ ): RawTogglePinMessageInfo {
+ const content = JSON.parse(row.content);
+ const { derivedMessages } = params;
+ const targetMessage = derivedMessages.get(content.targetMessageID);
+ invariant(targetMessage, 'targetMessage should be defined');
+
+ return {
+ type: messageTypes.TOGGLE_PIN,
+ id: row.id.toString(),
+ threadID: row.threadID.toString(),
+ targetMessageID: content.targetMessageID.toString(),
+ action: content.action,
+ pinnedContent: getPinnedContentFromMessage(targetMessage),
+ time: row.time,
+ creatorID: row.creatorID.toString(),
+ };
+ },
+
+ rawMessageInfoFromClientDB(
+ clientDBMessageInfo: ClientDBMessageInfo,
+ ): RawTogglePinMessageInfo {
+ invariant(
+ clientDBMessageInfo.content !== undefined &&
+ clientDBMessageInfo.content !== null,
+ 'content must be defined for TogglePin',
+ );
+ const content = JSON.parse(clientDBMessageInfo.content);
+ const pinnedContent =
+ getPinnedContentFromClientDBMessageInfo(clientDBMessageInfo);
+
+ const rawTogglePinMessageInfo: RawTogglePinMessageInfo = {
+ type: messageTypes.TOGGLE_PIN,
+ id: clientDBMessageInfo.id,
+ threadID: clientDBMessageInfo.thread,
+ targetMessageID: content.targetMessageID,
+ action: content.action,
+ pinnedContent,
+ time: parseInt(clientDBMessageInfo.time),
+ creatorID: clientDBMessageInfo.user,
+ };
+ return rawTogglePinMessageInfo;
+ },
+
+ createMessageInfo(
+ rawMessageInfo: RawTogglePinMessageInfo,
+ creator: RelativeUserInfo,
+ ): TogglePinMessageInfo {
+ return {
+ type: messageTypes.TOGGLE_PIN,
+ id: rawMessageInfo.id,
+ threadID: rawMessageInfo.threadID,
+ targetMessageID: rawMessageInfo.targetMessageID,
+ action: rawMessageInfo.action,
+ pinnedContent: rawMessageInfo.pinnedContent,
+ creator,
+ time: rawMessageInfo.time,
+ };
+ },
+
+ rawMessageInfoFromMessageData(
+ messageData: TogglePinMessageData,
+ id: ?string,
+ ): RawTogglePinMessageInfo {
+ invariant(id, 'RawTogglePinMessageInfo needs id');
+ return { ...messageData, id };
+ },
+
+ robotext(
+ messageInfo: TogglePinMessageInfo,
+ params: RobotextParams,
+ ): EntityText {
+ const creator = ET.user({ userInfo: messageInfo.creator });
+ const action = messageInfo.action === 'pin' ? 'pinned' : 'unpinned';
+ const pinnedContent = messageInfo.pinnedContent;
+ const preposition = messageInfo.action === 'pin' ? 'in' : 'from';
+ return ET`${creator} ${action} ${pinnedContent} ${preposition} ${ET.thread({
+ display: 'alwaysDisplayShortName',
+ threadID: messageInfo.threadID,
+ threadType: params.threadInfo?.type,
+ parentThreadID: params.threadInfo?.parentThreadID,
+ })}`;
+ },
+
+ shimUnsupportedMessageInfo(
+ rawMessageInfo: RawTogglePinMessageInfo,
+ platformDetails: ?PlatformDetails,
+ ): RawTogglePinMessageInfo | RawUnsupportedMessageInfo {
+ // TODO: Change before landing
+ if (hasMinCodeVersion(platformDetails, 10000)) {
+ return rawMessageInfo;
+ }
+ const { id } = rawMessageInfo;
+ invariant(id !== null && id !== undefined, 'id should be set on server');
+
+ return {
+ type: messageTypes.UNSUPPORTED,
+ id,
+ threadID: rawMessageInfo.threadID,
+ creatorID: rawMessageInfo.creatorID,
+ time: rawMessageInfo.time,
+ robotext: 'toggled a message pin',
+ unsupportedMessageInfo: rawMessageInfo,
+ };
+ },
+
+ unshimMessageInfo(
+ unwrapped: RawTogglePinMessageInfo,
+ ): RawTogglePinMessageInfo {
+ return unwrapped;
+ },
+
+ generatesNotifs: async () => undefined,
+});
diff --git a/lib/types/message-types.js b/lib/types/message-types.js
--- a/lib/types/message-types.js
+++ b/lib/types/message-types.js
@@ -94,6 +94,11 @@
TextMessageData,
TextMessageInfo,
} from './messages/text.js';
+import type {
+ TogglePinMessageData,
+ TogglePinMessageInfo,
+ RawTogglePinMessageInfo,
+} from './messages/toggle-pin.js';
import type {
RawUnsupportedMessageInfo,
UnsupportedMessageInfo,
@@ -137,6 +142,7 @@
CREATE_SIDEBAR: 18,
REACTION: 19,
EDIT_MESSAGE: 20,
+ TOGGLE_PIN: 21,
});
export type MessageType = $Values<typeof messageTypes>;
export function assertMessageType(ourMessageType: number): MessageType {
@@ -161,7 +167,8 @@
ourMessageType === 17 ||
ourMessageType === 18 ||
ourMessageType === 19 ||
- ourMessageType === 20,
+ ourMessageType === 20 ||
+ ourMessageType === 21,
'number is not MessageType enum',
);
return ourMessageType;
@@ -253,7 +260,8 @@
| SidebarSourceMessageData
| CreateSidebarMessageData
| ReactionMessageData
- | EditMessageData;
+ | EditMessageData
+ | TogglePinMessageData;
export type MultimediaMessageData = ImagesMessageData | MediaMessageData;
@@ -279,7 +287,8 @@
| RawRestoreEntryMessageInfo
| RawUpdateRelationshipMessageInfo
| RawCreateSidebarMessageInfo
- | RawUnsupportedMessageInfo;
+ | RawUnsupportedMessageInfo
+ | RawTogglePinMessageInfo;
export type RawSidebarSourceMessageInfo = {
...SidebarSourceMessageData,
id: string,
@@ -328,7 +337,8 @@
| RestoreEntryMessageInfo
| UnsupportedMessageInfo
| UpdateRelationshipMessageInfo
- | CreateSidebarMessageInfo;
+ | CreateSidebarMessageInfo
+ | TogglePinMessageInfo;
export type PreviewableMessageInfo =
| RobotextMessageInfo
| MultimediaMessageInfo
diff --git a/lib/types/messages/toggle-pin.js b/lib/types/messages/toggle-pin.js
new file mode 100644
--- /dev/null
+++ b/lib/types/messages/toggle-pin.js
@@ -0,0 +1,29 @@
+// @flow
+
+import type { RelativeUserInfo } from '../user-types.js';
+
+export type TogglePinMessageData = {
+ +type: 21,
+ +threadID: string,
+ +targetMessageID: string,
+ +action: 'pin' | 'unpin',
+ +pinnedContent: string,
+ +creatorID: string,
+ +time: number,
+};
+
+export type RawTogglePinMessageInfo = {
+ ...TogglePinMessageData,
+ +id: string,
+};
+
+export type TogglePinMessageInfo = {
+ +type: 21,
+ +id: string,
+ +threadID: string,
+ +targetMessageID: string,
+ +action: 'pin' | 'unpin',
+ +pinnedContent: string,
+ +creator: RelativeUserInfo,
+ +time: number,
+};
diff --git a/lib/utils/message-ops-utils.js b/lib/utils/message-ops-utils.js
--- a/lib/utils/message-ops-utils.js
+++ b/lib/utils/message-ops-utils.js
@@ -2,6 +2,7 @@
import _keyBy from 'lodash/fp/keyBy.js';
+import { contentStringForMediaArray } from '../media/media-utils.js';
import { messageID } from '../shared/message-utils.js';
import { messageSpecs } from '../shared/messages/message-specs.js';
import type {
@@ -243,6 +244,21 @@
});
}
+function getPinnedContentFromClientDBMessageInfo(
+ clientDBMessageInfo: ClientDBMessageInfo,
+): string {
+ const { media_infos } = clientDBMessageInfo;
+
+ let pinnedContent;
+ if (!media_infos) {
+ pinnedContent = 'a message';
+ } else {
+ const media = translateClientDBMediaInfosToMedia(clientDBMessageInfo);
+ pinnedContent = contentStringForMediaArray(media);
+ }
+ return pinnedContent;
+}
+
export {
translateClientDBMediaInfoToImage,
translateRawMessageInfoToClientDBMessageInfo,
@@ -250,4 +266,5 @@
translateClientDBMessageInfosToRawMessageInfos,
convertMessageStoreOperationsToClientDBOperations,
translateClientDBMediaInfosToMedia,
+ getPinnedContentFromClientDBMessageInfo,
};

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 28, 9:19 PM (1 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2729028
Default Alt Text
D7148.id24496.diff (13 KB)

Event Timeline