Link: Fix opening forum topics (#5558)

This commit is contained in:
zubiden 2025-02-13 14:27:48 +01:00 committed by Alexander Zinchuk
parent bb5ec799a1
commit 0ac730a043
5 changed files with 109 additions and 53 deletions

View File

@ -1577,6 +1577,43 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
}
});
addActionHandler('openPrivateChannel', (global, actions, payload): ActionReturnType => {
const {
id, commentId, messageId, threadId, tabId = getCurrentTabId(),
} = payload;
const chat = selectChat(global, id);
if (!chat) {
actions.showNotification({
message: {
key: 'PrivateChannelInaccessible',
},
tabId,
});
return;
}
if (!commentId && !messageId && !threadId) {
actions.openChat({ id, tabId });
return;
}
if (commentId && messageId) {
actions.openThread({
isComments: true,
originChannelId: chat.id,
originMessageId: messageId,
tabId,
focusMessageId: commentId,
});
return;
}
openChatWithParams(global, actions, chat, {
messageId,
threadId,
}, tabId);
});
addActionHandler('togglePreHistoryHidden', async (global, actions, payload): Promise<void> => {
const {
chatId, isEnabled,
@ -3075,7 +3112,6 @@ async function openChatByUsername<T extends GlobalState>(
const {
username, threadId, channelPostId, startParam, ref, startAttach, attach, text,
} = params;
global = getGlobal();
const currentChat = selectCurrentChat(global, tabId);
// Attach in the current chat
@ -3120,10 +3156,61 @@ async function openChatByUsername<T extends GlobalState>(
return;
}
if (channelPostId) {
actions.focusMessage({
chatId: chat.id, threadId, messageId: channelPostId, tabId,
});
openChatWithParams(global, actions, chat, {
isCurrentChat,
threadId,
messageId: channelPostId,
startParam,
referrer,
startAttach,
attach,
text,
}, tabId);
}
async function openChatWithParams<T extends GlobalState>(
global: T,
actions: RequiredGlobalActions,
chat: ApiChat,
params: {
isCurrentChat?: boolean;
threadId?: ThreadId;
messageId?: number;
startParam?: string;
referrer?: string;
startAttach?: string;
attach?: string;
text?: string;
},
...[tabId = getCurrentTabId()]: TabArgs<T>
) {
const {
isCurrentChat, threadId, messageId, startParam, referrer, startAttach, attach, text,
} = params;
if (messageId) {
let isTopicProcessed = false;
// In forums, link to a topic start message should open the topic
if (chat.isForum && !threadId) {
let topic = selectTopics(global, chat.id)?.[messageId];
if (!topic) {
const topicResult = await callApi('fetchTopicById', { chat, topicId: messageId });
topic = topicResult?.topic;
}
if (topic) {
actions.openThread({
chatId: chat.id, threadId: topic.id, tabId,
});
isTopicProcessed = true;
}
}
if (!isTopicProcessed) {
actions.focusMessage({
chatId: chat.id, threadId, messageId, tabId,
});
}
} else if (!isCurrentChat) {
actions.openThread({ chatId: chat.id, threadId: threadId ?? MAIN_THREAD_ID, tabId });
}

View File

@ -88,22 +88,6 @@ addActionHandler('processOpenChatOrThread', (global, actions, payload): ActionRe
return updateCurrentMessageList(global, chatId, threadId, type, shouldReplaceHistory, shouldReplaceLast, tabId);
});
addActionHandler('openPrivateChannel', (global, actions, payload): ActionReturnType => {
const { id, tabId = getCurrentTabId() } = payload;
const chat = selectChat(global, id);
if (!chat) {
actions.showNotification({
message: {
key: 'PrivateChannelInaccessible',
},
tabId,
});
return;
}
actions.openChat({ id, tabId });
});
addActionHandler('openChatInNewTab', (global, actions, payload): ActionReturnType => {
const { chatId, threadId = MAIN_THREAD_ID } = payload;

View File

@ -1089,6 +1089,9 @@ export interface ActionPayloads {
} & WithTabId;
openPrivateChannel: {
id: string;
threadId?: ThreadId;
messageId?: number;
commentId?: number;
} & WithTabId;
loadFullChat: {
chatId: string;

View File

@ -18,7 +18,6 @@ interface PublicMessageLink {
isSingle: boolean;
threadId?: ThreadId;
commentId?: number;
mediaTimestamp?: string;
}
export interface PrivateMessageLink {
@ -28,7 +27,6 @@ export interface PrivateMessageLink {
isSingle: boolean;
threadId?: ThreadId;
commentId?: number;
mediaTimestamp?: string;
}
interface ShareLink {
@ -173,7 +171,7 @@ function parseTgLink(url: URL) {
switch (deepLinkType) {
case 'publicMessageLink': {
const {
domain, post, single, thread, comment, t,
domain, post, single, thread, comment,
} = queryParams;
return buildPublicMessageLink({
username: domain,
@ -181,12 +179,11 @@ function parseTgLink(url: URL) {
single,
threadId: thread,
commentId: comment,
mediaTimestamp: t,
});
}
case 'privateMessageLink': {
const {
channel, post, single, thread, comment, t,
channel, post, single, thread, comment,
} = queryParams;
return buildPrivateMessageLink({
channelId: channel,
@ -194,7 +191,6 @@ function parseTgLink(url: URL) {
single,
threadId: thread,
commentId: comment,
mediaTimestamp: t,
});
}
case 'shareLink':
@ -255,7 +251,7 @@ function parseHttpLink(url: URL) {
switch (deepLinkType) {
case 'publicMessageLink': {
const {
single, comment, t,
single, comment,
} = queryParams;
const {
username,
@ -276,12 +272,11 @@ function parseHttpLink(url: URL) {
single,
threadId: thread,
commentId: comment,
mediaTimestamp: t,
});
}
case 'privateMessageLink': {
const {
single, comment, t,
single, comment,
} = queryParams;
const {
channelId,
@ -302,7 +297,6 @@ function parseHttpLink(url: URL) {
single,
threadId: thread,
commentId: comment,
mediaTimestamp: t,
});
}
case 'shareLink': {
@ -463,7 +457,7 @@ function buildShareLink(params: BuilderParams<ShareLink>): BuilderReturnType<Sha
function buildPublicMessageLink(params: PublicMessageLinkBuilderParams): BuilderReturnType<PublicMessageLink> {
const {
messageId, threadId, commentId, username, single, mediaTimestamp,
messageId, threadId, commentId, username, single,
} = params;
if (!username || !isUsernameValid(username)) {
return undefined;
@ -484,13 +478,12 @@ function buildPublicMessageLink(params: PublicMessageLinkBuilderParams): Builder
isSingle: single === '',
threadId: threadId ? Number(threadId) : undefined,
commentId: commentId ? Number(commentId) : undefined,
mediaTimestamp,
};
}
function buildPrivateMessageLink(params: PrivateMessageLinkBuilderParams): BuilderReturnType<PrivateMessageLink> {
const {
messageId, threadId, commentId, channelId, single, mediaTimestamp,
messageId, threadId, commentId, channelId, single,
} = params;
if (!channelId || !isNumber(channelId)) {
return undefined;
@ -506,12 +499,11 @@ function buildPrivateMessageLink(params: PrivateMessageLinkBuilderParams): Build
}
return {
type: 'privateMessageLink',
channelId,
channelId: toChannelId(channelId),
messageId: Number(messageId),
isSingle: single === '',
threadId: threadId ? Number(threadId) : undefined,
commentId: commentId ? Number(commentId) : undefined,
mediaTimestamp,
};
}

View File

@ -1,10 +1,9 @@
import { getActions } from '../global';
import type { ApiChatType, ApiFormattedText } from '../api/types';
import type { DeepLinkMethod, PrivateMessageLink } from './deepLinkParser';
import type { DeepLinkMethod } from './deepLinkParser';
import { API_CHAT_TYPES, RE_TG_LINK } from '../config';
import { toChannelId } from '../global/helpers';
import { tryParseDeepLink } from './deepLinkParser';
import { IS_BAD_URL_PARSER } from './windowEnvironment';
@ -15,7 +14,12 @@ export const processDeepLink = (url: string): boolean => {
if (parsedLink) {
switch (parsedLink.type) {
case 'privateMessageLink':
handlePrivateMessageLink(parsedLink, actions);
actions.openPrivateChannel({
id: parsedLink.channelId,
threadId: parsedLink.threadId,
messageId: parsedLink.messageId,
commentId: parsedLink.commentId,
});
return true;
case 'publicMessageLink': {
actions.openChatByUsername({
@ -223,20 +227,6 @@ export function formatShareText(url?: string, text?: string, title?: string): Ap
};
}
function handlePrivateMessageLink(link: PrivateMessageLink, actions: ReturnType<typeof getActions>) {
const {
focusMessage,
} = actions;
const {
channelId, messageId, threadId,
} = link;
focusMessage({
chatId: toChannelId(channelId),
threadId,
messageId,
});
}
function parseChooseParameter(choose?: string) {
if (!choose) return undefined;
const types = choose.toLowerCase().split(' ');