From 9e52d794a48a2f0cc480e9cb4789f5307c097ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Thu, 15 May 2025 17:48:36 +0200 Subject: [PATCH] Fix ephemeral messages disappearing when updating them (#8838) --- app/actions/websocket/posts.test.ts | 24 +++++++++++++++++++++++- app/actions/websocket/posts.ts | 8 ++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/actions/websocket/posts.test.ts b/app/actions/websocket/posts.test.ts index 48e0bb346..a1175d7b8 100644 --- a/app/actions/websocket/posts.test.ts +++ b/app/actions/websocket/posts.test.ts @@ -11,6 +11,7 @@ import {fetchPostAuthors} from '@actions/remote/post'; import {fetchThread} from '@actions/remote/thread'; import {fetchMissingProfilesByIds} from '@actions/remote/user'; import {Events, Screens} from '@constants'; +import {PostTypes} from '@constants/post'; import DatabaseManager from '@database/manager'; import {PostsInChannelModel} from '@database/models/server'; import {getChannelById, getMyChannel} from '@queries/servers/channel'; @@ -50,7 +51,7 @@ describe('WebSocket Post Actions', () => { let operator: ServerDataOperator; const post = TestHelper.fakePost({id: 'post1', channel_id: 'channel1', user_id: 'user1', create_at: 12345, message: 'hello'}); - const postModels = [TestHelper.fakePostModel({channelId: post.channel_id, userId: post.user_id, message: post.message, isPinned: true})]; + const postModels = [TestHelper.fakePostModel({channelId: post.channel_id, userId: post.user_id, message: post.message, isPinned: true, createAt: 12345})]; const myChannelModel = TestHelper.fakeMyChannelModel({id: 'channel1', manuallyUnread: false, messageCount: 4, mentionsCount: 0, lastViewedAt: 1}); const mockedGetPostById = jest.mocked(getPostById); @@ -81,6 +82,10 @@ describe('WebSocket Post Actions', () => { jest.clearAllMocks(); }); + afterEach(async () => { + await DatabaseManager.deleteServerDatabase(serverUrl); + }); + describe('handleNewPostEvent', () => { const msg = { data: { @@ -310,6 +315,23 @@ describe('WebSocket Post Actions', () => { expect(mockedGetPostById).not.toHaveBeenCalled(); expect(batchRecordsSpy).not.toHaveBeenCalled(); }); + + it('should not update create_at for ephemeral messages', async () => { + const batchRecordsSpy = jest.spyOn(operator, 'batchRecords').mockImplementation(jest.fn()); + const ephemeralMsg = { + data: {post: JSON.stringify( + TestHelper.fakePost({type: PostTypes.EPHEMERAL, create_at: 0}), + )}, + } as WebSocketMessage; + + mockedGetPostById.mockResolvedValueOnce(postModels[0]); + mockedFetchPostAuthors.mockResolvedValue({authors: []}); + mockedGetIsCRTEnabled.mockResolvedValue(false); + + await handlePostEdited(serverUrl, ephemeralMsg); + + expect(batchRecordsSpy).toHaveBeenCalledWith(expect.arrayContaining([expect.objectContaining({createAt: 12345})]), 'handlePostEdited'); + }); }); describe('handlePostDeleted', () => { diff --git a/app/actions/websocket/posts.ts b/app/actions/websocket/posts.ts index 2e98dc074..a0459404d 100644 --- a/app/actions/websocket/posts.ts +++ b/app/actions/websocket/posts.ts @@ -12,6 +12,7 @@ import {openChannelIfNeeded} from '@actions/remote/preference'; import {fetchThread} from '@actions/remote/thread'; import {fetchMissingProfilesByIds} from '@actions/remote/user'; import {ActionType, Events, Screens} from '@constants'; +import {PostTypes} from '@constants/post'; import DatabaseManager from '@database/manager'; import {getChannelById, getMyChannel} from '@queries/servers/channel'; import {getPostById} from '@queries/servers/post'; @@ -215,6 +216,13 @@ export async function handlePostEdited(serverUrl: string, msg: WebSocketMessage) return; } + if (post.type === PostTypes.EPHEMERAL && post.create_at === 0) { + // Updated ephemeral messages don't have a create_at value + // since the server has no persistence for ephemeral messages, + // so we need to use the old post's create_at value + post.create_at = oldPost.createAt; + } + if (oldPost.isPinned !== post.is_pinned) { fetchChannelStats(serverUrl, post.channel_id); }