Message: Generate sharing link on server (#4405)
This commit is contained in:
parent
b3e21e293a
commit
c0e82bdd0f
@ -35,7 +35,7 @@ export {
|
|||||||
reportMessages, sendMessageAction, fetchSeenBy, fetchSponsoredMessages, viewSponsoredMessage, fetchSendAs,
|
reportMessages, sendMessageAction, fetchSeenBy, fetchSponsoredMessages, viewSponsoredMessage, fetchSendAs,
|
||||||
saveDefaultSendAs, fetchUnreadReactions, readAllReactions, fetchUnreadMentions, readAllMentions, transcribeAudio,
|
saveDefaultSendAs, fetchUnreadReactions, readAllReactions, fetchUnreadMentions, readAllMentions, transcribeAudio,
|
||||||
closePoll, fetchExtendedMedia, translateText, fetchMessageViews, fetchDiscussionMessage, clickSponsoredMessage,
|
closePoll, fetchExtendedMedia, translateText, fetchMessageViews, fetchDiscussionMessage, clickSponsoredMessage,
|
||||||
fetchOutboxReadDate,
|
fetchOutboxReadDate, exportMessageLink,
|
||||||
deleteSavedHistory,
|
deleteSavedHistory,
|
||||||
} from './messages';
|
} from './messages';
|
||||||
|
|
||||||
|
|||||||
@ -1927,3 +1927,21 @@ export async function fetchOutboxReadDate({ chat, messageId }: { chat: ApiChat;
|
|||||||
|
|
||||||
return { date: result.date };
|
return { date: result.date };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function exportMessageLink({
|
||||||
|
id, chat, shouldIncludeThread, shouldIncludeGrouped,
|
||||||
|
}: {
|
||||||
|
id: number;
|
||||||
|
chat: ApiChat;
|
||||||
|
shouldIncludeThread?: boolean;
|
||||||
|
shouldIncludeGrouped?: boolean;
|
||||||
|
}) {
|
||||||
|
const result = await invokeRequest(new GramJs.channels.ExportMessageLink({
|
||||||
|
channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel,
|
||||||
|
id,
|
||||||
|
thread: shouldIncludeThread || undefined,
|
||||||
|
grouped: shouldIncludeGrouped || undefined,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return result?.link;
|
||||||
|
}
|
||||||
|
|||||||
@ -4,11 +4,18 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type {
|
|
||||||
ApiAvailableReaction, ApiChatReactions, ApiMessage, ApiReaction, ApiStickerSet, ApiStickerSetInfo, ApiThreadInfo,
|
|
||||||
} from '../../../api/types';
|
|
||||||
import type { MessageListType, TabState } from '../../../global/types';
|
import type { MessageListType, TabState } from '../../../global/types';
|
||||||
import type { IAlbum, IAnchorPosition } from '../../../types';
|
import type { IAlbum, IAnchorPosition, ThreadId } from '../../../types';
|
||||||
|
import {
|
||||||
|
type ApiAvailableReaction,
|
||||||
|
type ApiChatReactions,
|
||||||
|
type ApiMessage,
|
||||||
|
type ApiReaction,
|
||||||
|
type ApiStickerSet,
|
||||||
|
type ApiStickerSetInfo,
|
||||||
|
type ApiThreadInfo,
|
||||||
|
MAIN_THREAD_ID,
|
||||||
|
} from '../../../api/types';
|
||||||
|
|
||||||
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||||
import {
|
import {
|
||||||
@ -38,7 +45,6 @@ import {
|
|||||||
selectIsPremiumPurchaseBlocked,
|
selectIsPremiumPurchaseBlocked,
|
||||||
selectIsReactionPickerOpen,
|
selectIsReactionPickerOpen,
|
||||||
selectMessageCustomEmojiSets,
|
selectMessageCustomEmojiSets,
|
||||||
selectMessageLink,
|
|
||||||
selectMessageTranslations,
|
selectMessageTranslations,
|
||||||
selectRequestedChatTranslationLanguage,
|
selectRequestedChatTranslationLanguage,
|
||||||
selectRequestedMessageTranslationLanguage,
|
selectRequestedMessageTranslationLanguage,
|
||||||
@ -77,6 +83,7 @@ export type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
|
threadId?: ThreadId;
|
||||||
availableReactions?: ApiAvailableReaction[];
|
availableReactions?: ApiAvailableReaction[];
|
||||||
topReactions?: ApiReaction[];
|
topReactions?: ApiReaction[];
|
||||||
defaultTagReactions?: ApiReaction[];
|
defaultTagReactions?: ApiReaction[];
|
||||||
@ -120,13 +127,13 @@ type StateProps = {
|
|||||||
maxUniqueReactions?: number;
|
maxUniqueReactions?: number;
|
||||||
canPlayAnimatedEmojis?: boolean;
|
canPlayAnimatedEmojis?: boolean;
|
||||||
isReactionPickerOpen?: boolean;
|
isReactionPickerOpen?: boolean;
|
||||||
messageLink?: string;
|
|
||||||
isInSavedMessages?: boolean;
|
isInSavedMessages?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
|
|
||||||
const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||||
|
threadId,
|
||||||
availableReactions,
|
availableReactions,
|
||||||
topReactions,
|
topReactions,
|
||||||
defaultTagReactions,
|
defaultTagReactions,
|
||||||
@ -178,7 +185,6 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
canShowOriginal,
|
canShowOriginal,
|
||||||
canSelectLanguage,
|
canSelectLanguage,
|
||||||
isReactionPickerOpen,
|
isReactionPickerOpen,
|
||||||
messageLink,
|
|
||||||
isInSavedMessages,
|
isInSavedMessages,
|
||||||
onClose,
|
onClose,
|
||||||
onCloseAnimationEnd,
|
onCloseAnimationEnd,
|
||||||
@ -213,6 +219,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
openMessageReactionPicker,
|
openMessageReactionPicker,
|
||||||
openPremiumModal,
|
openPremiumModal,
|
||||||
loadOutboxReadDate,
|
loadOutboxReadDate,
|
||||||
|
copyMessageLink,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -459,7 +466,12 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleCopyLink = useLastCallback(() => {
|
const handleCopyLink = useLastCallback(() => {
|
||||||
copyTextToClipboard(messageLink!);
|
copyMessageLink({
|
||||||
|
chatId: message.chatId,
|
||||||
|
messageId: message.id,
|
||||||
|
shouldIncludeThread: threadId !== MAIN_THREAD_ID,
|
||||||
|
shouldIncludeGrouped: true, // TODO: Provide correct value when ability to target specific message is added
|
||||||
|
});
|
||||||
closeMenu();
|
closeMenu();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -728,11 +740,11 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
: undefined;
|
: undefined;
|
||||||
const canTranslate = !hasTranslation && selectCanTranslateMessage(global, message, detectedLanguage);
|
const canTranslate = !hasTranslation && selectCanTranslateMessage(global, message, detectedLanguage);
|
||||||
const isChatTranslated = selectRequestedChatTranslationLanguage(global, message.chatId);
|
const isChatTranslated = selectRequestedChatTranslationLanguage(global, message.chatId);
|
||||||
const messageLink = selectMessageLink(global, message.chatId, threadId, message.id);
|
|
||||||
|
|
||||||
const isInSavedMessages = selectIsChatWithSelf(global, message.chatId);
|
const isInSavedMessages = selectIsChatWithSelf(global, message.chatId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
threadId,
|
||||||
availableReactions,
|
availableReactions,
|
||||||
topReactions,
|
topReactions,
|
||||||
defaultTagReactions: defaultTags,
|
defaultTagReactions: defaultTags,
|
||||||
@ -777,7 +789,6 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isMessageTranslated: hasTranslation,
|
isMessageTranslated: hasTranslation,
|
||||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||||
isReactionPickerOpen: selectIsReactionPickerOpen(global),
|
isReactionPickerOpen: selectIsReactionPickerOpen(global),
|
||||||
messageLink,
|
|
||||||
isInSavedMessages,
|
isInSavedMessages,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -103,11 +103,7 @@ export function getMessageCopyOptions(
|
|||||||
options.push({
|
options.push({
|
||||||
label: 'lng_context_copy_message_link',
|
label: 'lng_context_copy_message_link',
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
handler: () => {
|
handler: onCopyLink,
|
||||||
onCopyLink();
|
|
||||||
|
|
||||||
afterEffect?.();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import {
|
|||||||
SUPPORTED_IMAGE_CONTENT_TYPES,
|
SUPPORTED_IMAGE_CONTENT_TYPES,
|
||||||
SUPPORTED_VIDEO_CONTENT_TYPES,
|
SUPPORTED_VIDEO_CONTENT_TYPES,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
|
import { copyTextToClipboard } from '../../../util/clipboard';
|
||||||
import { isDeepLink } from '../../../util/deepLinkParser';
|
import { isDeepLink } from '../../../util/deepLinkParser';
|
||||||
import { ensureProtocol } from '../../../util/ensureProtocol';
|
import { ensureProtocol } from '../../../util/ensureProtocol';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
@ -53,6 +54,7 @@ import {
|
|||||||
getIsSavedDialog,
|
getIsSavedDialog,
|
||||||
getUserFullName,
|
getUserFullName,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
|
isChatSuperGroup,
|
||||||
isDeletedUser,
|
isDeletedUser,
|
||||||
isMessageLocal,
|
isMessageLocal,
|
||||||
isServiceNotificationMessage,
|
isServiceNotificationMessage,
|
||||||
@ -1900,6 +1902,49 @@ addActionHandler('loadOutboxReadDate', async (global, actions, payload): Promise
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('copyMessageLink', async (global, actions, payload): Promise<void> => {
|
||||||
|
const {
|
||||||
|
chatId, messageId, shouldIncludeThread, shouldIncludeGrouped, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
|
if (!chat) {
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate('ErrorOccurred'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isChatChannel(chat) && !isChatSuperGroup(chat)) {
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate('lng_filters_link_private_error'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = await callApi('exportMessageLink', {
|
||||||
|
chat,
|
||||||
|
id: messageId,
|
||||||
|
shouldIncludeThread,
|
||||||
|
shouldIncludeGrouped,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!link) {
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate('ErrorOccurred'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyTextToClipboard(link);
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate('LinkCopied'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function countSortedIds(ids: number[], from: number, to: number) {
|
function countSortedIds(ids: number[], from: number, to: number) {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
|
|||||||
@ -1414,29 +1414,21 @@ export function selectCanTranslateMessage<T extends GlobalState>(
|
|||||||
&& !chatRequestedLanguage;
|
&& !chatRequestedLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectMessageLink<T extends GlobalState>(
|
export function selectTopicLink<T extends GlobalState>(
|
||||||
global: T, chatId: string, threadId?: ThreadId, messageId?: number,
|
global: T, chatId: string, topicId?: ThreadId,
|
||||||
) {
|
) {
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) {
|
if (!chat || !chat?.isForum) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatUsername = getMainUsername(chat);
|
const chatUsername = getMainUsername(chat);
|
||||||
|
|
||||||
const isChannelId = isChatChannel(chat) || isChatSuperGroup(chat);
|
const normalizedId = chatId.replace('-100', '');
|
||||||
const normalizedId = isChannelId ? chatId.replace('-100', '') : chatId.replace('-', '');
|
|
||||||
|
|
||||||
const chatPart = chatUsername || `c/${normalizedId}`;
|
const chatPart = chatUsername || `c/${normalizedId}`;
|
||||||
const threadPart = threadId && threadId !== MAIN_THREAD_ID ? `/${threadId}` : '';
|
const topicPart = topicId && topicId !== MAIN_THREAD_ID ? `/${topicId}` : '';
|
||||||
const messagePart = messageId ? `/${messageId}` : '';
|
return `${TME_LINK_PREFIX}${chatPart}${topicPart}`;
|
||||||
return `${TME_LINK_PREFIX}${chatPart}${threadPart}${messagePart}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectTopicLink<T extends GlobalState>(
|
|
||||||
global: T, chatId: string, topicId?: ThreadId,
|
|
||||||
) {
|
|
||||||
return selectMessageLink(global, chatId, topicId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectMessageReplyInfo<T extends GlobalState>(
|
export function selectMessageReplyInfo<T extends GlobalState>(
|
||||||
|
|||||||
@ -2054,6 +2054,12 @@ export interface ActionPayloads {
|
|||||||
markMentionsRead: {
|
markMentionsRead: {
|
||||||
messageIds: number[];
|
messageIds: number[];
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
copyMessageLink: {
|
||||||
|
chatId: string;
|
||||||
|
messageId: number;
|
||||||
|
shouldIncludeThread?: boolean;
|
||||||
|
shouldIncludeGrouped?: boolean;
|
||||||
|
} & WithTabId;
|
||||||
|
|
||||||
sendPollVote: {
|
sendPollVote: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
|
|||||||
@ -1455,6 +1455,7 @@ channels.joinChannel#24b524c5 channel:InputChannel = Updates;
|
|||||||
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
|
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
|
||||||
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
|
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
|
||||||
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
||||||
|
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
|
||||||
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates;
|
channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates;
|
||||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||||
|
|||||||
@ -202,6 +202,7 @@
|
|||||||
"channels.leaveChannel",
|
"channels.leaveChannel",
|
||||||
"channels.inviteToChannel",
|
"channels.inviteToChannel",
|
||||||
"channels.deleteChannel",
|
"channels.deleteChannel",
|
||||||
|
"channels.exportMessageLink",
|
||||||
"channels.toggleSignatures",
|
"channels.toggleSignatures",
|
||||||
"channels.editBanned",
|
"channels.editBanned",
|
||||||
"channels.readMessageContents",
|
"channels.readMessageContents",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user