From b162650bb6e650f5e8f9868fb60b347ed80405d5 Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:52:13 +0200 Subject: [PATCH] Message: Fix incorrect update handling (#6266) --- src/api/gramjs/methods/messages.ts | 8 +++---- src/api/types/updates.ts | 9 +++++++- src/global/actions/api/messages.ts | 2 +- src/global/actions/apiUpdaters/messages.ts | 25 ++++++++++++++++++---- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index 5b2cb43a3..db0edaca8 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -519,10 +519,10 @@ export function sendApiMessage( } sendApiUpdate({ - '@type': 'updateMessageSendFailed', + '@type': localMessage.isScheduled ? 'updateScheduledMessageSendFailed' : 'updateMessageSendFailed', chatId: chat.id, localId: localMessage.id, - error: error.message, + error: error.errorMessage, }); clearTimeout(timeout); } @@ -1915,10 +1915,10 @@ export async function forwardApiMessages(params: ForwardMessagesParams) { } catch (error: any) { Object.values(localMessages).forEach((localMessage) => { sendApiUpdate({ - '@type': 'updateMessageSendFailed', + '@type': localMessage.isScheduled ? 'updateScheduledMessageSendFailed' : 'updateMessageSendFailed', chatId: toChat.id, localId: localMessage.id, - error: error.message, + error: error.errorMessage, }); }); } diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index e66302c0f..e999465eb 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -319,6 +319,13 @@ export type ApiUpdateMessageSendFailed = { error: string; }; +export type ApiUpdateScheduledMessageSendFailed = { + '@type': 'updateScheduledMessageSendFailed'; + chatId: string; + localId: number; + error: string; +}; + export type ApiUpdateCommonBoxMessages = { '@type': 'updateCommonBoxMessages'; ids: number[]; @@ -865,7 +872,7 @@ export type ApiUpdate = ( ApiDeleteParticipantHistory | ApiUpdateMessageSendSucceeded | ApiUpdateMessageSendFailed | ApiUpdateServiceNotification | ApiDeleteContact | ApiUpdateUser | ApiUpdateUserStatus | ApiUpdateUserFullInfo | ApiUpdateVideoProcessingPending | ApiUpdatePeerSettings | - ApiUpdateAvatar | ApiUpdateMessageImage | ApiUpdateDraftMessage | + ApiUpdateAvatar | ApiUpdateMessageImage | ApiUpdateDraftMessage | ApiUpdateScheduledMessageSendFailed | ApiUpdateError | ApiUpdateResetContacts | ApiUpdateStartEmojiInteraction | ApiUpdateFavoriteStickers | ApiUpdateStickerSet | ApiUpdateStickerSets | ApiUpdateStickerSetsOrder | ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop | diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index 1896094a6..39d211679 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -1361,7 +1361,7 @@ addActionHandler('toggleTodoCompleted', (global, actions, payload): ActionReturn content: newContent, }; - global = updateWithLocalMedia(global, chatId, message.id, messageUpdate); + global = updateWithLocalMedia(global, chatId, message.id, false, messageUpdate); setGlobal(global); callApi('toggleTodoCompleted', { chat, messageId: message.id, completedIds, incompletedIds }); diff --git a/src/global/actions/apiUpdaters/messages.ts b/src/global/actions/apiUpdaters/messages.ts index 3b94066ba..560705f7b 100644 --- a/src/global/actions/apiUpdaters/messages.ts +++ b/src/global/actions/apiUpdaters/messages.ts @@ -104,7 +104,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { const { chatId, id, message, shouldForceReply, wasDrafted, poll, webPage, } = update; - global = updateWithLocalMedia(global, chatId, id, message); + global = updateWithLocalMedia(global, chatId, id, true, message); global = updateListedAndViewportIds(global, actions, message as ApiMessage); const newMessage = selectChatMessage(global, chatId, id)!; @@ -236,7 +236,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { chatId, id, message, poll, webPage, } = update; - global = updateWithLocalMedia(global, chatId, id, message, true); + global = updateWithLocalMedia(global, chatId, id, true, message, true); const scheduledIds = selectScheduledIds(global, chatId, MAIN_THREAD_ID) || []; global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'scheduledIds', unique([...scheduledIds, id])); @@ -284,7 +284,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { return; } - global = updateWithLocalMedia(global, chatId, id, message, true); + global = updateWithLocalMedia(global, chatId, id, false, message, true); const ids = Object.keys(selectChatScheduledMessages(global, chatId) || {}).map(Number).sort((a, b) => b - a); global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'scheduledIds', ids); @@ -330,7 +330,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { const chat = selectChat(global, chatId); - global = updateWithLocalMedia(global, chatId, id, message); + global = updateWithLocalMedia(global, chatId, id, false, message); const newMessage = selectChatMessage(global, chatId, id)!; @@ -879,6 +879,20 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { break; } + case 'updateScheduledMessageSendFailed': { + const { chatId, localId, error } = update; + + if (error.match(/CHAT_SEND_.+?FORBIDDEN/)) { + Object.values(global.byTabId).forEach(({ id: tabId }) => { + actions.showAllowedMessageTypesNotification({ chatId, tabId }); + }); + } + + global = updateScheduledMessage(global, chatId, localId, { sendingState: 'messageSendingStateFailed' }); + setGlobal(global); + break; + } + case 'updateMessageTranslations': { const { chatId, messageIds, toLanguageCode, translations, @@ -975,6 +989,7 @@ export function updateWithLocalMedia( global: RequiredGlobalState, chatId: string, id: number, + isNew: boolean, messageUpdate: Partial, isScheduled = false, ) { @@ -982,6 +997,8 @@ export function updateWithLocalMedia( ? selectScheduledMessage(global, chatId, id) : selectChatMessage(global, chatId, id); + if (!currentMessage && !isNew) return global; + // Preserve locally uploaded media. if (currentMessage && messageUpdate.content && !isLocalMessageId(id)) { const {