feat(client): forwarding messages

This commit is contained in:
teidesu 2021-04-24 19:00:11 +03:00
parent 007343fb09
commit 0d3490ad7b
2 changed files with 418 additions and 83 deletions

View file

@ -53,6 +53,7 @@ import { uploadFile } from './methods/files/upload-file'
import { deleteMessages } from './methods/messages/delete-messages' import { deleteMessages } from './methods/messages/delete-messages'
import { editMessage } from './methods/messages/edit-message' import { editMessage } from './methods/messages/edit-message'
import { _findMessageInUpdate } from './methods/messages/find-in-update' import { _findMessageInUpdate } from './methods/messages/find-in-update'
import { forwardMessages } from './methods/messages/forward-messages'
import { getHistory } from './methods/messages/get-history' import { getHistory } from './methods/messages/get-history'
import { getMessages } from './methods/messages/get-messages' import { getMessages } from './methods/messages/get-messages'
import { iterHistory } from './methods/messages/iter-history' import { iterHistory } from './methods/messages/iter-history'
@ -981,6 +982,106 @@ export interface TelegramClient extends BaseTelegramClient {
replyMarkup?: ReplyMarkup replyMarkup?: ReplyMarkup
} }
): Promise<Message> ): Promise<Message>
/**
* Forward a single message.
*
* To forward with a caption, use another overload that takes an array of IDs.
*
* @param toChatId Destination chat ID, username, phone, `"me"` or `"self"`
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
* @param message Message ID
* @param params Additional sending parameters
* @returns Newly sent, forwarded messages in the destination chat
*/
forwardMessages(
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
message: number,
params?: {
/**
* Whether to forward this message silently.
*/
silent?: boolean
/**
* If set, the message will be scheduled to this date.
* When passing a number, a UNIX time in ms is expected.
*/
schedule?: Date | number
}
): Promise<Message>
/**
* Forward one or more messages, optionally including a caption message.
*
* If a caption message was sent, it will be the first message in the resulting array.
*
* @param toChatId Destination chat ID, username, phone, `"me"` or `"self"`
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
* @param messages Message IDs
* @param params Additional sending parameters
* @returns
* Newly sent, forwarded messages in the destination chat.
* If a caption message was provided, it will be the first message in the array.
*/
forwardMessages(
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
messages: number[],
params?: {
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
caption?: string
/**
* Optionally, a media caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
captionMedia?: InputMediaLike
/**
* Parse mode to use to parse entities in caption.
* Defaults to current default parse mode (if any).
*
* Passing `null` will explicitly disable formatting.
*/
parseMode?: string | null
/**
* List of formatting entities in caption to use instead
* of parsing via a parse mode.
*
* **Note:** Passing this makes the method ignore {@link parseMode}
*/
entities?: tl.TypeMessageEntity[]
/**
* Whether to forward silently (also applies to caption message).
*/
silent?: boolean
/**
* If set, the forwarding will be scheduled to this date
* (also applies to caption message).
* When passing a number, a UNIX time in ms is expected.
*/
schedule?: Date | number
/**
* Whether to clear draft after sending this message (only used for caption)
*
* Defaults to `false`
*/
clearDraft?: boolean
}
): Promise<MaybeArray<Message>>
/** /**
* Retrieve a chunk of the chat history. * Retrieve a chunk of the chat history.
* *
@ -1059,12 +1160,6 @@ export interface TelegramClient extends BaseTelegramClient {
messageIds: number[], messageIds: number[],
fromReply?: boolean fromReply?: boolean
): Promise<Message[]> ): Promise<Message[]>
getMessages(
chatId: InputPeerLike,
messageIds: MaybeArray<number>,
fromReply?: boolean
): Promise<MaybeArray<Message>>
/** /**
* Iterate through a chat history sequentially. * Iterate through a chat history sequentially.
* *
@ -1610,8 +1705,6 @@ export interface TelegramClient extends BaseTelegramClient {
* @param ids Users' identifiers. Can be ID, username, phone number, `"me"`, `"self"` or TL object * @param ids Users' identifiers. Can be ID, username, phone number, `"me"`, `"self"` or TL object
*/ */
getUsers(ids: InputPeerLike[]): Promise<User[]> getUsers(ids: InputPeerLike[]): Promise<User[]>
getUsers(ids: MaybeArray<InputPeerLike>): Promise<MaybeArray<User>>
/** /**
* Get the `InputPeer` of a known peer id. * Get the `InputPeer` of a known peer id.
* Useful when an `InputPeer` is needed. * Useful when an `InputPeer` is needed.
@ -1650,85 +1743,86 @@ export class TelegramClient extends BaseTelegramClient {
this._cpts = {} this._cpts = {}
} }
acceptTos = acceptTos as TelegramClient['acceptTos'] acceptTos = acceptTos
checkPassword = checkPassword as TelegramClient['checkPassword'] checkPassword = checkPassword
getPasswordHint = getPasswordHint as TelegramClient['getPasswordHint'] getPasswordHint = getPasswordHint
logOut = logOut as TelegramClient['logOut'] logOut = logOut
recoverPassword = recoverPassword as TelegramClient['recoverPassword'] recoverPassword = recoverPassword
resendCode = resendCode as TelegramClient['resendCode'] resendCode = resendCode
run = run as TelegramClient['run'] run = run
sendCode = sendCode as TelegramClient['sendCode'] sendCode = sendCode
sendRecoveryCode = sendRecoveryCode as TelegramClient['sendRecoveryCode'] sendRecoveryCode = sendRecoveryCode
signInBot = signInBot as TelegramClient['signInBot'] signInBot = signInBot
signIn = signIn as TelegramClient['signIn'] signIn = signIn
signUp = signUp as TelegramClient['signUp'] signUp = signUp
startTest = startTest as TelegramClient['startTest'] startTest = startTest
start = start as TelegramClient['start'] start = start
addChatMembers = addChatMembers as TelegramClient['addChatMembers'] addChatMembers = addChatMembers
archiveChats = archiveChats as TelegramClient['archiveChats'] archiveChats = archiveChats
createChannel = createChannel as TelegramClient['createChannel'] createChannel = createChannel
createGroup = createGroup as TelegramClient['createGroup'] createGroup = createGroup
createSupergroup = createSupergroup as TelegramClient['createSupergroup'] createSupergroup = createSupergroup
deleteChannel = deleteChannel as TelegramClient['deleteChannel'] deleteChannel = deleteChannel
deleteSupergroup = deleteChannel as TelegramClient['deleteSupergroup'] deleteSupergroup = deleteChannel
deleteChatPhoto = deleteChatPhoto as TelegramClient['deleteChatPhoto'] deleteChatPhoto = deleteChatPhoto
deleteGroup = deleteGroup as TelegramClient['deleteGroup'] deleteGroup = deleteGroup
deleteHistory = deleteHistory as TelegramClient['deleteHistory'] deleteHistory = deleteHistory
getChatMember = getChatMember as TelegramClient['getChatMember'] getChatMember = getChatMember
getChatMembers = getChatMembers as TelegramClient['getChatMembers'] getChatMembers = getChatMembers
getChatPreview = getChatPreview as TelegramClient['getChatPreview'] getChatPreview = getChatPreview
getChat = getChat as TelegramClient['getChat'] getChat = getChat
getFullChat = getFullChat as TelegramClient['getFullChat'] getFullChat = getFullChat
iterChatMembers = iterChatMembers as TelegramClient['iterChatMembers'] iterChatMembers = iterChatMembers
joinChat = joinChat as TelegramClient['joinChat'] joinChat = joinChat
leaveChat = leaveChat as TelegramClient['leaveChat'] leaveChat = leaveChat
saveDraft = saveDraft as TelegramClient['saveDraft'] saveDraft = saveDraft
setChatDefaultPermissions = setChatDefaultPermissions as TelegramClient['setChatDefaultPermissions'] setChatDefaultPermissions = setChatDefaultPermissions
setChatDescription = setChatDescription as TelegramClient['setChatDescription'] setChatDescription = setChatDescription
setChatPhoto = setChatPhoto as TelegramClient['setChatPhoto'] setChatPhoto = setChatPhoto
setChatTitle = setChatTitle as TelegramClient['setChatTitle'] setChatTitle = setChatTitle
setChatUsername = setChatUsername as TelegramClient['setChatUsername'] setChatUsername = setChatUsername
setSlowMode = setSlowMode as TelegramClient['setSlowMode'] setSlowMode = setSlowMode
unarchiveChats = unarchiveChats as TelegramClient['unarchiveChats'] unarchiveChats = unarchiveChats
createFolder = createFolder as TelegramClient['createFolder'] createFolder = createFolder
deleteFolder = deleteFolder as TelegramClient['deleteFolder'] deleteFolder = deleteFolder
editFolder = editFolder as TelegramClient['editFolder'] editFolder = editFolder
getDialogs = getDialogs as TelegramClient['getDialogs'] getDialogs = getDialogs
getFolders = getFolders as TelegramClient['getFolders'] getFolders = getFolders
downloadAsBuffer = downloadAsBuffer as TelegramClient['downloadAsBuffer'] downloadAsBuffer = downloadAsBuffer
downloadToFile = downloadToFile as TelegramClient['downloadToFile'] downloadToFile = downloadToFile
downloadAsIterable = downloadAsIterable as TelegramClient['downloadAsIterable'] downloadAsIterable = downloadAsIterable
downloadAsStream = downloadAsStream as TelegramClient['downloadAsStream'] downloadAsStream = downloadAsStream
uploadFile = uploadFile as TelegramClient['uploadFile'] uploadFile = uploadFile
deleteMessages = deleteMessages as TelegramClient['deleteMessages'] deleteMessages = deleteMessages
editMessage = editMessage as TelegramClient['editMessage'] editMessage = editMessage
protected _findMessageInUpdate = _findMessageInUpdate protected _findMessageInUpdate = _findMessageInUpdate
getHistory = getHistory as TelegramClient['getHistory'] forwardMessages = forwardMessages
getMessages = getMessages as TelegramClient['getMessages'] getHistory = getHistory
iterHistory = iterHistory as TelegramClient['iterHistory'] getMessages = getMessages
iterHistory = iterHistory
protected _parseEntities = _parseEntities protected _parseEntities = _parseEntities
pinMessage = pinMessage as TelegramClient['pinMessage'] pinMessage = pinMessage
searchGlobal = searchGlobal as TelegramClient['searchGlobal'] searchGlobal = searchGlobal
searchMessages = searchMessages as TelegramClient['searchMessages'] searchMessages = searchMessages
sendDice = sendDice as TelegramClient['sendDice'] sendDice = sendDice
sendLocation = sendLocation as TelegramClient['sendLocation'] sendLocation = sendLocation
sendMedia = sendMedia as TelegramClient['sendMedia'] sendMedia = sendMedia
sendPhoto = sendPhoto as TelegramClient['sendPhoto'] sendPhoto = sendPhoto
sendText = sendText as TelegramClient['sendText'] sendText = sendText
unpinMessage = unpinMessage as TelegramClient['unpinMessage'] unpinMessage = unpinMessage
registerParseMode = registerParseMode as TelegramClient['registerParseMode'] registerParseMode = registerParseMode
unregisterParseMode = unregisterParseMode as TelegramClient['unregisterParseMode'] unregisterParseMode = unregisterParseMode
getParseMode = getParseMode as TelegramClient['getParseMode'] getParseMode = getParseMode
setDefaultParseMode = setDefaultParseMode as TelegramClient['setDefaultParseMode'] setDefaultParseMode = setDefaultParseMode
protected _fetchUpdatesState = _fetchUpdatesState protected _fetchUpdatesState = _fetchUpdatesState
protected _loadStorage = _loadStorage protected _loadStorage = _loadStorage
protected _saveStorage = _saveStorage protected _saveStorage = _saveStorage
dispatchUpdate = dispatchUpdate as TelegramClient['dispatchUpdate'] dispatchUpdate = dispatchUpdate
protected _handleUpdate = _handleUpdate protected _handleUpdate = _handleUpdate
catchUp = catchUp as TelegramClient['catchUp'] catchUp = catchUp
blockUser = blockUser as TelegramClient['blockUser'] blockUser = blockUser
getCommonChats = getCommonChats as TelegramClient['getCommonChats'] getCommonChats = getCommonChats
getMe = getMe as TelegramClient['getMe'] getMe = getMe
getUsers = getUsers as TelegramClient['getUsers'] getUsers = getUsers
resolvePeer = resolvePeer as TelegramClient['resolvePeer'] resolvePeer = resolvePeer
} }

View file

@ -0,0 +1,241 @@
import { TelegramClient } from '../../client'
import {
InputMediaLike,
InputPeerLike,
Message,
MtCuteArgumentError, MtCuteTypeAssertionError,
} from '../../types'
import { MaybeArray } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { createUsersChatsIndex, normalizeToInputPeer } from '../../utils/peer-utils'
import { normalizeDate, randomUlong } from '../../utils/misc-utils'
/**
* Forward a single message.
*
* To forward with a caption, use another overload that takes an array of IDs.
*
* @param toChatId Destination chat ID, username, phone, `"me"` or `"self"`
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
* @param message Message ID
* @param params Additional sending parameters
* @returns Newly sent, forwarded messages in the destination chat
* @internal
*/
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
message: number,
params?: {
/**
* Whether to forward this message silently.
*/
silent?: boolean
/**
* If set, the message will be scheduled to this date.
* When passing a number, a UNIX time in ms is expected.
*/
schedule?: Date | number
}
): Promise<Message>
/**
* Forward one or more messages, optionally including a caption message.
*
* If a caption message was sent, it will be the first message in the resulting array.
*
* @param toChatId Destination chat ID, username, phone, `"me"` or `"self"`
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
* @param messages Message IDs
* @param params Additional sending parameters
* @returns
* Newly sent, forwarded messages in the destination chat.
* If a caption message was provided, it will be the first message in the array.
* @internal
*/
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
messages: number[],
params?: {
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
caption?: string
/**
* Optionally, a media caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
captionMedia?: InputMediaLike
/**
* Parse mode to use to parse entities in caption.
* Defaults to current default parse mode (if any).
*
* Passing `null` will explicitly disable formatting.
*/
parseMode?: string | null
/**
* List of formatting entities in caption to use instead
* of parsing via a parse mode.
*
* **Note:** Passing this makes the method ignore {@link parseMode}
*/
entities?: tl.TypeMessageEntity[]
/**
* Whether to forward silently (also applies to caption message).
*/
silent?: boolean
/**
* If set, the forwarding will be scheduled to this date
* (also applies to caption message).
* When passing a number, a UNIX time in ms is expected.
*/
schedule?: Date | number
/**
* Whether to clear draft after sending this message (only used for caption)
*
* Defaults to `false`
*/
clearDraft?: boolean
}
): Promise<MaybeArray<Message>>
/** @internal */
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
messages: MaybeArray<number>,
params?: {
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
caption?: string
/**
* Optionally, a media caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
*
* You can either pass `caption` or `captionMedia`, passing both will
* result in an error
*/
captionMedia?: InputMediaLike
/**
* Parse mode to use to parse entities in caption.
* Defaults to current default parse mode (if any).
*
* Passing `null` will explicitly disable formatting.
*/
parseMode?: string | null
/**
* List of formatting entities in caption to use instead
* of parsing via a parse mode.
*
* **Note:** Passing this makes the method ignore {@link parseMode}
*/
entities?: tl.TypeMessageEntity[]
/**
* Whether to send this message silently.
*/
silent?: boolean
/**
* If set, the message will be scheduled to this date.
* When passing a number, a UNIX time in ms is expected.
*/
schedule?: Date | number
/**
* Whether to clear draft after sending this message (only used for caption)
*
* Defaults to `false`
*/
clearDraft?: boolean
}
): Promise<MaybeArray<Message>> {
if (!params) params = {}
const isSingle = !Array.isArray(messages)
if (isSingle) messages = [messages as number]
const toPeer = normalizeToInputPeer(await this.resolvePeer(toChatId))
let captionMessage: Message | null = null
if (params.caption) {
if (params.captionMedia)
throw new MtCuteArgumentError(
'You can either pass `caption` or `captionMedia`'
)
captionMessage = await this.sendText(toPeer, params.caption, {
parseMode: params.parseMode,
entities: params.entities,
silent: params.silent,
schedule: params.schedule,
clearDraft: params.clearDraft,
})
} else if (params.captionMedia) {
captionMessage = await this.sendMedia(toPeer, params.captionMedia, {
parseMode: params.parseMode,
silent: params.silent,
schedule: params.schedule,
clearDraft: params.clearDraft,
})
}
const res = await this.call({
_: 'messages.forwardMessages',
toPeer,
fromPeer: normalizeToInputPeer(await this.resolvePeer(fromChatId)),
id: messages as number[],
silent: params.silent,
scheduleDate: normalizeDate(params.schedule),
randomId: [...Array((messages as number[]).length)].map(() =>
randomUlong()
),
})
if (!(res._ === 'updates' || res._ === 'updatesCombined'))
throw new MtCuteTypeAssertionError(
'forwardMessages',
'updates | updatesCombined',
res._
)
this._handleUpdate(res, true)
const { users, chats } = createUsersChatsIndex(res)
const forwarded: Message[] = []
res.updates.forEach((upd) => {
if (upd._ === 'updateNewMessage' || upd._ == 'updateNewChannelMessage' || upd._ === 'updateNewScheduledMessage') {
forwarded.push(new Message(this, upd.message, users, chats))
}
})
if (isSingle) return forwarded[0]
if (captionMessage) forwarded.unshift(captionMessage)
return forwarded
}