From 41ab86cd2d5cd25c382c2bed42d6cd9e0eb22dd9 Mon Sep 17 00:00:00 2001 From: Rahim Rahman Date: Wed, 30 Oct 2024 14:55:34 -0600 Subject: [PATCH] fix(MM-53762): missing file and reaction (#8284) * fix: missing file and reaction * update import * simplify code * update post test to show the changes fix emoji and reaction * clean up test --- .../handlers/post.test.ts | 161 ++++++++++++------ .../server_data_operator/handlers/post.ts | 4 +- 2 files changed, 112 insertions(+), 53 deletions(-) diff --git a/app/database/operator/server_data_operator/handlers/post.test.ts b/app/database/operator/server_data_operator/handlers/post.test.ts index ae5201f3d..5778e3413 100644 --- a/app/database/operator/server_data_operator/handlers/post.test.ts +++ b/app/database/operator/server_data_operator/handlers/post.test.ts @@ -21,58 +21,9 @@ Q.sortBy = jest.fn().mockImplementation((field) => { describe('*** Operator: Post Handlers tests ***', () => { let operator: ServerDataOperator; - beforeAll(async () => { - await DatabaseManager.init(['baseHandler.test.com']); - operator = DatabaseManager.serverDatabases['baseHandler.test.com']!.operator; - }); - - it('=> HandleDraft: should write to the the Draft table', async () => { - expect.assertions(1); - - const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const drafts = [ - { - channel_id: '4r9jmr7eqt8dxq3f9woypzurrychannelid', - files: [ - { - id: '322dxx', - user_id: 'user_id', - post_id: 'post_id', - create_at: 123, - update_at: 456, - delete_at: 789, - name: 'an_image', - extension: 'jpg', - size: 10, - mime_type: 'image', - width: 10, - height: 10, - has_preview_image: false, - clientId: 'clientId', - }, - ], - message: 'test draft message for post', - root_id: '', - update_at: Date.now(), - }, - ]; - - await operator.handleDraft({drafts, prepareRecordsOnly: false}); - - expect(spyOnHandleRecords).toHaveBeenCalledWith({ - buildKeyRecordBy: buildDraftKey, - fieldName: 'channel_id', - transformer: transformDraftRecord, - createOrUpdateRawValues: drafts, - tableName: 'Draft', - prepareRecordsOnly: false, - }, 'handleDraft'); - }); - - it('=> HandlePosts: should write to the Post and its sub-child tables', async () => { - // expect.assertions(12); - - const posts: Post[] = [ + let posts: Post[] = []; + beforeEach(() => { + posts = [ { id: '8swgtrrdiff89jnsiwiip3y1eoe', create_at: 1596032651747, @@ -218,6 +169,58 @@ describe('*** Operator: Post Handlers tests ***', () => { metadata: {}, }, ]; + }); + + beforeAll(async () => { + await DatabaseManager.init(['baseHandler.test.com']); + operator = DatabaseManager.serverDatabases['baseHandler.test.com']!.operator; + }); + + it('=> HandleDraft: should write to the the Draft table', async () => { + expect.assertions(1); + + const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); + const drafts = [ + { + channel_id: '4r9jmr7eqt8dxq3f9woypzurrychannelid', + files: [ + { + id: '322dxx', + user_id: 'user_id', + post_id: 'post_id', + create_at: 123, + update_at: 456, + delete_at: 789, + name: 'an_image', + extension: 'jpg', + size: 10, + mime_type: 'image', + width: 10, + height: 10, + has_preview_image: false, + clientId: 'clientId', + }, + ], + message: 'test draft message for post', + root_id: '', + update_at: 456, + }, + ]; + + await operator.handleDraft({drafts, prepareRecordsOnly: false}); + + expect(spyOnHandleRecords).toHaveBeenCalledWith({ + buildKeyRecordBy: buildDraftKey, + fieldName: 'channel_id', + transformer: transformDraftRecord, + createOrUpdateRawValues: drafts, + tableName: 'Draft', + prepareRecordsOnly: false, + }, 'handleDraft'); + }); + + it('=> HandlePosts: should write to the Post and its sub-child tables', async () => { + // expect.assertions(12); const order = [ '8swgtrrdiff89jnsiwiip3y1eoe', @@ -310,6 +313,60 @@ describe('*** Operator: Post Handlers tests ***', () => { expect(spyOnHandlePostsInChannel).toHaveBeenCalledTimes(1); expect(spyOnHandlePostsInChannel).toHaveBeenCalledWith(linkedPosts.slice(0, 3), actionType, true); }); + + it('=> HandlePosts: should properly parse metadata when the metadata is a string', async () => { + const postWithMetadata = posts[0]; + const updatedPosts: Post[] = [ + { + ...postWithMetadata, + + // @ts-expect-error metadata should be an object, but notifications are sending post with metadata as a string + metadata: JSON.stringify(postWithMetadata.metadata), + }, + ]; + + const order = [ + '8swgtrrdiff89jnsiwiip3y1eoe', + '8fcnk3p1jt8mmkaprgajoxz115a', + '3y3w3a6gkbg73bnj3xund9o5ic', + ]; + + const actionType = ActionType.POSTS.RECEIVED_IN_CHANNEL; + const spyOnHandleFiles = jest.spyOn(operator, 'handleFiles'); + const spyOnHandleReactions = jest.spyOn(operator, 'handleReactions'); + const spyOnHandleCustomEmojis = jest.spyOn(operator, 'handleCustomEmojis'); + + await operator.handlePosts({ + actionType, + order, + posts: updatedPosts, + previousPostId: '', + }); + + expect(spyOnHandleFiles).toHaveBeenCalledWith({ + files: [ + expect.objectContaining({id: postWithMetadata.metadata.files![0].id}), + ], + prepareRecordsOnly: true, + }); + + expect(spyOnHandleCustomEmojis).toHaveBeenCalledWith({ + prepareRecordsOnly: true, + emojis: [ + expect.objectContaining({id: postWithMetadata.metadata.emojis![0].id}), + ], + }); + + expect(spyOnHandleReactions).toHaveBeenCalledWith({ + postsReactions: [{ + post_id: '8swgtrrdiff89jnsiwiip3y1eoe', + reactions: [ + expect.objectContaining({emoji_name: postWithMetadata.metadata.reactions![0].emoji_name}), + ], + }], + prepareRecordsOnly: true, + }); + }); }); describe('*** Operator: merge chunks ***', () => { diff --git a/app/database/operator/server_data_operator/handlers/post.ts b/app/database/operator/server_data_operator/handlers/post.ts index 56c28571a..377aefd67 100644 --- a/app/database/operator/server_data_operator/handlers/post.ts +++ b/app/database/operator/server_data_operator/handlers/post.ts @@ -15,6 +15,7 @@ import { import {getRawRecordPairs, getUniqueRawsBy, getValidRecordsForUpdate} from '@database/operator/utils/general'; import {createPostsChain, getPostListEdges} from '@database/operator/utils/post'; import FileModel from '@typings/database/models/servers/file'; +import {safeParseJSON} from '@utils/helpers'; import {logWarning} from '@utils/log'; import type ServerDataOperatorBase from '.'; @@ -177,7 +178,8 @@ const PostHandler = >(supercla // Process the metadata of each post if (post?.metadata && Object.keys(post?.metadata).length > 0) { - const data = post.metadata; + // parsing into json since notifications are sending metadata as a string + const data = safeParseJSON(post.metadata) as PostMetadata; // Extracts reaction from post's metadata if (data.reactions) {