feat(client): deleteUserHistory method, also properly handle messages.affectedHistory

i suppose? this is an incredibly bad hack but i guess it works so who cares?
This commit is contained in:
teidesu 2021-05-10 14:27:57 +03:00
parent c678a0ef6a
commit f3e4a34eab
7 changed files with 125 additions and 17 deletions

View file

@ -26,6 +26,7 @@ import { deleteChannel } from './methods/chats/delete-channel'
import { deleteChatPhoto } from './methods/chats/delete-chat-photo'
import { deleteGroup } from './methods/chats/delete-group'
import { deleteHistory } from './methods/chats/delete-history'
import { deleteUserHistory } from './methods/chats/delete-user-history'
import { getChatMember } from './methods/chats/get-chat-member'
import { getChatMembers } from './methods/chats/get-chat-members'
import { getChatPreview } from './methods/chats/get-chat-preview'
@ -662,6 +663,16 @@ export interface TelegramClient extends BaseTelegramClient {
mode?: 'delete' | 'clear' | 'revoke',
maxId?: number
): Promise<void>
/**
* Delete all messages of a user in a supergroup
*
* @param chatId Chat ID
* @param userId User ID
*/
deleteUserHistory(
chatId: InputPeerLike,
userId: InputPeerLike
): Promise<void>
/**
* Get information about a single chat member
*
@ -1271,7 +1282,7 @@ export interface TelegramClient extends BaseTelegramClient {
* > **Note**: each administrator has their own primary invite link,
* > and bots by default don't have one.
*
* @param chatId Chat ID
* @param chatId Chat IDs
*/
exportInviteLink(chatId: InputPeerLike): Promise<ChatInviteLink>
/**
@ -1369,7 +1380,7 @@ export interface TelegramClient extends BaseTelegramClient {
chatId: InputPeerLike,
ids: MaybeArray<number>,
revoke?: boolean
): Promise<boolean>
): Promise<void>
/**
* Edit sent inline message text, media and reply markup.
*
@ -2670,6 +2681,7 @@ export class TelegramClient extends BaseTelegramClient {
deleteChatPhoto = deleteChatPhoto
deleteGroup = deleteGroup
deleteHistory = deleteHistory
deleteUserHistory = deleteUserHistory
getChatMember = getChatMember
getChatMembers = getChatMembers
getChatPreview = getChatPreview

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types'
import { normalizeToInputPeer } from '../../utils/peer-utils'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import { createDummyUpdate } from '../../utils/updates-utils'
import { tl } from '@mtcute/tl'
/**
* Delete communication history (for private chats
@ -23,11 +25,20 @@ export async function deleteHistory(
mode: 'delete' | 'clear' | 'revoke' = 'delete',
maxId = 0
): Promise<void> {
await this.call({
const peer = normalizeToInputPeer(await this.resolvePeer(chat))
const res = await this.call({
_: 'messages.deleteHistory',
justClear: mode === 'clear',
revoke: mode === 'revoke',
peer: normalizeToInputPeer(await this.resolvePeer(chat)),
peer,
maxId
})
const channel = normalizeToInputChannel(peer)
if (channel) {
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId))
} else {
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount))
}
}

View file

@ -0,0 +1,41 @@
import { TelegramClient } from '../../client'
import { InputPeerLike, MtCuteInvalidPeerTypeError } from '../../types'
import {
normalizeToInputChannel,
normalizeToInputUser,
} from '../../utils/peer-utils'
import { tl } from '@mtcute/tl'
import { createDummyUpdate } from '../../utils/updates-utils'
/**
* Delete all messages of a user in a supergroup
*
* @param chatId Chat ID
* @param userId User ID
* @internal
*/
export async function deleteUserHistory(
this: TelegramClient,
chatId: InputPeerLike,
userId: InputPeerLike
): Promise<void> {
const channel = normalizeToInputChannel(await this.resolvePeer(chatId))
if (!channel) throw new MtCuteInvalidPeerTypeError(chatId, 'channel')
const user = normalizeToInputUser(await this.resolvePeer(userId))
if (!user) throw new MtCuteInvalidPeerTypeError(userId, 'user')
const res = await this.call({
_: 'channels.deleteUserHistory',
channel,
userId: user,
})
this._handleUpdate(
createDummyUpdate(
res.pts,
res.ptsCount,
(channel as tl.RawInputChannel).channelId
)
)
}

View file

@ -2,6 +2,8 @@ import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types'
import { MaybeArray } from '@mtcute/core'
import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils'
import { createDummyUpdate } from '../../utils/updates-utils'
import { tl } from '@mtcute/tl'
/**
* Delete messages, including service messages.
@ -16,28 +18,29 @@ export async function deleteMessages(
chatId: InputPeerLike,
ids: MaybeArray<number>,
revoke = true
): Promise<boolean> {
): Promise<void> {
if (!Array.isArray(ids)) ids = [ids]
const peer = await this.resolvePeer(chatId)
const inputPeer = normalizeToInputPeer(peer)
let res
let upd
if (inputPeer._ === 'inputPeerChannel') {
res = await this.call({
const channel = normalizeToInputChannel(peer)!
const res = await this.call({
_: 'channels.deleteMessages',
channel: normalizeToInputChannel(peer)!,
channel,
id: ids
})
upd = createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId)
} else {
res = await this.call({
const res = await this.call({
_: 'messages.deleteMessages',
id: ids,
revoke
})
upd = createDummyUpdate(res.pts, res.ptsCount)
}
this._pts = res.pts
return !!res.ptsCount
this._handleUpdate(upd)
}

View file

@ -10,6 +10,7 @@ import { extractChannelIdFromUpdate } from '../utils/misc-utils'
import { Lock } from '../utils/lock'
import bigInt from 'big-integer'
import { MAX_CHANNEL_ID } from '@mtcute/core'
import { isDummyUpdate, isDummyUpdates } from '../utils/updates-utils'
const debug = require('debug')('mtcute:upds')
@ -488,7 +489,7 @@ export function _handleUpdate(
}
}
if (!noDispatch) {
if (!isDummyUpdate(upd) && !noDispatch) {
this.dispatchUpdate(upd, users, chats)
}
@ -502,8 +503,10 @@ export function _handleUpdate(
}
}
if (!isDummyUpdates(update)) {
// this._seq = update.seq
this._date = update.date
}
} else if (update._ === 'updateShort') {
const upd = update.update
if (upd._ === 'updateDcOptions' && this._config) {

View file

@ -25,7 +25,7 @@ export function extractChannelIdFromUpdate(
upd: tl.TypeUpdate
): number | undefined {
// holy shit
return 'channelId' in upd
const res = 'channelId' in upd
? upd.channelId
: 'message' in upd &&
typeof upd.message !== 'string' &&
@ -34,6 +34,8 @@ export function extractChannelIdFromUpdate(
'channelId' in upd.message.peerId
? upd.message.peerId.channelId
: undefined
if (res === 0) return undefined
return res
}
export function normalizeDate(

View file

@ -0,0 +1,36 @@
import { tl } from '@mtcute/tl'
// dummy updates which are used for methods that return messages.affectedHistory.
// that is not an update, but it carries info about pts, and we need to handle it
/** @internal */
export function createDummyUpdate(pts: number, ptsCount: number, channelId = 0): tl.TypeUpdates {
return {
_: 'updates',
seq: 0,
date: 0,
chats: [],
users: [],
updates: [
{
_: 'updatePinnedChannelMessages',
channelId,
pts,
ptsCount,
// since message id cant be negative, using negative 42
// here makes it distinctive from real updates
messages: [-42]
}
]
}
}
/** @internal */
export function isDummyUpdate(upd: tl.TypeUpdate): boolean {
return upd._ === 'updatePinnedChannelMessages' && upd.messages.length === 1 && upd.messages[0] === -42
}
/** @internal */
export function isDummyUpdates(upd: tl.TypeUpdates): boolean {
return upd._ === 'updates' && upd.updates.length === 1 && isDummyUpdate(upd.updates[0])
}