feat(client): getChatMember method and ChatMember class
This commit is contained in:
parent
82a9ec80ea
commit
89dafa570b
6 changed files with 352 additions and 1 deletions
|
@ -21,6 +21,7 @@ import { createSupergroup } from './methods/chats/create-supergroup'
|
||||||
import { deleteChannel } from './methods/chats/delete-channel'
|
import { deleteChannel } from './methods/chats/delete-channel'
|
||||||
import { deleteGroup } from './methods/chats/delete-group'
|
import { deleteGroup } from './methods/chats/delete-group'
|
||||||
import { deleteHistory } from './methods/chats/delete-history'
|
import { deleteHistory } from './methods/chats/delete-history'
|
||||||
|
import { getChatMember } from './methods/chats/get-chat-member'
|
||||||
import { getChatPreview } from './methods/chats/get-chat-preview'
|
import { getChatPreview } from './methods/chats/get-chat-preview'
|
||||||
import { getChat } from './methods/chats/get-chat'
|
import { getChat } from './methods/chats/get-chat'
|
||||||
import { getFullChat } from './methods/chats/get-full-chat'
|
import { getFullChat } from './methods/chats/get-full-chat'
|
||||||
|
@ -69,6 +70,7 @@ import { IMessageEntityParser } from './parser'
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
import {
|
import {
|
||||||
Chat,
|
Chat,
|
||||||
|
ChatMember,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
|
@ -444,6 +446,19 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return deleteHistory.apply(this, arguments)
|
return deleteHistory.apply(this, arguments)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Get information about a single chat member
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID or username
|
||||||
|
* @param userId User ID, username, phone number, `"me"` or `"self"`
|
||||||
|
* @throws MtCuteNotFoundError In case given user is not a participant of a given chat
|
||||||
|
*/
|
||||||
|
getChatMember(
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
userId: InputPeerLike
|
||||||
|
): Promise<ChatMember> {
|
||||||
|
return getChatMember.apply(this, arguments)
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Get preview information about a private chat.
|
* Get preview information about a private chat.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
User,
|
User,
|
||||||
Chat,
|
Chat,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
|
ChatMember,
|
||||||
TermsOfService,
|
TermsOfService,
|
||||||
SentCode,
|
SentCode,
|
||||||
MaybeDynamic,
|
MaybeDynamic,
|
||||||
|
|
78
packages/client/src/methods/chats/get-chat-member.ts
Normal file
78
packages/client/src/methods/chats/get-chat-member.ts
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import {
|
||||||
|
InputPeerLike,
|
||||||
|
MtCuteInvalidPeerTypeError,
|
||||||
|
} from '../../types'
|
||||||
|
import {
|
||||||
|
createUsersChatsIndex,
|
||||||
|
normalizeToInputChannel,
|
||||||
|
normalizeToInputPeer,
|
||||||
|
} from '../../utils/peer-utils'
|
||||||
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { ChatMember } from '../../types'
|
||||||
|
import { UserNotParticipantError } from '@mtcute/tl/errors'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a single chat member
|
||||||
|
*
|
||||||
|
* @param chatId Chat ID or username
|
||||||
|
* @param userId User ID, username, phone number, `"me"` or `"self"`
|
||||||
|
* @throws UserNotParticipantError In case given user is not a participant of a given chat
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function getChatMember(
|
||||||
|
this: TelegramClient,
|
||||||
|
chatId: InputPeerLike,
|
||||||
|
userId: InputPeerLike
|
||||||
|
): Promise<ChatMember> {
|
||||||
|
const user = normalizeToInputPeer(await this.resolvePeer(userId))
|
||||||
|
const chat = await this.resolvePeer(chatId)
|
||||||
|
const chatInput = normalizeToInputPeer(chat)
|
||||||
|
|
||||||
|
if (chatInput._ === 'inputPeerChat') {
|
||||||
|
const res = await this.call({
|
||||||
|
_: 'messages.getFullChat',
|
||||||
|
chatId: chatInput.chatId,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTypeIs(
|
||||||
|
'getChatMember (@ messages.getFullChat)',
|
||||||
|
res.fullChat,
|
||||||
|
'chatFull'
|
||||||
|
)
|
||||||
|
|
||||||
|
const members =
|
||||||
|
res.fullChat.participants._ === 'chatParticipantsForbidden'
|
||||||
|
? []
|
||||||
|
: res.fullChat.participants.participants
|
||||||
|
|
||||||
|
const { users } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
|
for (const m of members) {
|
||||||
|
if (
|
||||||
|
(user._ === 'inputPeerSelf' &&
|
||||||
|
(users[m.userId] as tl.RawUser).self) ||
|
||||||
|
(user._ === 'inputPeerUser' && m.userId === user.userId)
|
||||||
|
) {
|
||||||
|
return new ChatMember(this, m, users)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UserNotParticipantError()
|
||||||
|
} else if (chatInput._ === 'inputPeerChannel') {
|
||||||
|
const res = await this.call({
|
||||||
|
_: 'channels.getParticipant',
|
||||||
|
channel: normalizeToInputChannel(chat)!,
|
||||||
|
participant: user,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { users } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
|
return new ChatMember(
|
||||||
|
this,
|
||||||
|
res.participant,
|
||||||
|
users
|
||||||
|
)
|
||||||
|
} else throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
|
||||||
|
}
|
253
packages/client/src/types/peers/chat-member.ts
Normal file
253
packages/client/src/types/peers/chat-member.ts
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
import { makeInspectable } from '../utils'
|
||||||
|
import { TelegramClient } from '../../client'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { User } from './user'
|
||||||
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
|
import { ChatPermissions } from './chat-permissions'
|
||||||
|
|
||||||
|
export namespace ChatMember {
|
||||||
|
/**
|
||||||
|
* Status of the member:
|
||||||
|
* - `creator`: user is the creator of the chat
|
||||||
|
* - `admin`: user has admin rights in the chat
|
||||||
|
* - `member`: user is a normal member of the chat
|
||||||
|
* - `restricted`: user has some restrictions applied
|
||||||
|
* - `banned`: user was banned from the chat
|
||||||
|
* - `left`: user left the chat on their own
|
||||||
|
*/
|
||||||
|
export type Status =
|
||||||
|
| 'creator'
|
||||||
|
| 'admin'
|
||||||
|
| 'member'
|
||||||
|
| 'restricted'
|
||||||
|
| 'banned'
|
||||||
|
| 'left'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about one chat member
|
||||||
|
*/
|
||||||
|
export class ChatMember {
|
||||||
|
readonly client: TelegramClient
|
||||||
|
readonly raw: tl.TypeChatParticipant | tl.TypeChannelParticipant
|
||||||
|
|
||||||
|
/** Map of users in this object. Mainly for internal use */
|
||||||
|
readonly _users: Record<number, tl.TypeUser>
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
client: TelegramClient,
|
||||||
|
raw: tl.TypeChatParticipant | tl.TypeChannelParticipant,
|
||||||
|
users: Record<number, tl.TypeUser>,
|
||||||
|
) {
|
||||||
|
this.client = client
|
||||||
|
this.raw = raw
|
||||||
|
this._users = users
|
||||||
|
}
|
||||||
|
|
||||||
|
private _user?: User
|
||||||
|
/**
|
||||||
|
* Information about the user
|
||||||
|
*/
|
||||||
|
get user(): User {
|
||||||
|
if (this._user === undefined) {
|
||||||
|
if (
|
||||||
|
this.raw._ === 'channelParticipantBanned' ||
|
||||||
|
this.raw._ === 'channelParticipantLeft'
|
||||||
|
) {
|
||||||
|
assertTypeIs(
|
||||||
|
'ChatMember#user (raw.peer)',
|
||||||
|
this.raw.peer,
|
||||||
|
'peerUser'
|
||||||
|
)
|
||||||
|
this._user = new User(
|
||||||
|
this.client,
|
||||||
|
this._users[this.raw.peer.userId] as tl.RawUser
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._user = new User(
|
||||||
|
this.client,
|
||||||
|
this._users[this.raw.userId] as tl.RawUser
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._user
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the chat member status
|
||||||
|
*/
|
||||||
|
get status(): ChatMember.Status {
|
||||||
|
if (
|
||||||
|
this.raw._ === 'channelParticipant' ||
|
||||||
|
this.raw._ === 'channelParticipantSelf' ||
|
||||||
|
this.raw._ === 'chatParticipant'
|
||||||
|
) {
|
||||||
|
return 'member'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.raw._ === 'channelParticipantCreator' ||
|
||||||
|
this.raw._ === 'chatParticipantCreator'
|
||||||
|
) {
|
||||||
|
return 'creator'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.raw._ === 'channelParticipantAdmin' ||
|
||||||
|
this.raw._ === 'chatParticipantAdmin'
|
||||||
|
) {
|
||||||
|
return 'admin'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.raw._ === 'channelParticipantLeft') {
|
||||||
|
return 'left'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.raw._ === 'channelParticipantBanned') {
|
||||||
|
return this.raw.bannedRights.viewMessages ? 'banned' : 'restricted'
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
return 'member'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom title (for creators and admins).
|
||||||
|
*
|
||||||
|
* `null` for non-admins and in case custom title is not set.
|
||||||
|
*/
|
||||||
|
get title(): string | null {
|
||||||
|
return this.raw._ === 'channelParticipantCreator' ||
|
||||||
|
this.raw._ === 'channelParticipantAdmin'
|
||||||
|
? this.raw.rank ?? null
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date when the user has joined the chat.
|
||||||
|
*
|
||||||
|
* Not available for creators and left members
|
||||||
|
*/
|
||||||
|
get joinedDate(): Date | null {
|
||||||
|
return this.raw._ === 'channelParticipantCreator' ||
|
||||||
|
this.raw._ === 'chatParticipantCreator' ||
|
||||||
|
this.raw._ === 'channelParticipantLeft'
|
||||||
|
? null
|
||||||
|
: new Date(this.raw.date * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _invitedBy?: User | null
|
||||||
|
/**
|
||||||
|
* Information about whoever invited this member to the chat.
|
||||||
|
*
|
||||||
|
* Only available in the following cases:
|
||||||
|
* - `user` is yourself
|
||||||
|
* - `chat` is a legacy group
|
||||||
|
* - `chat` is a supergroup/channel, and `user` is an admin
|
||||||
|
*/
|
||||||
|
get invitedBy(): User | null {
|
||||||
|
if (this._invitedBy === undefined) {
|
||||||
|
if (
|
||||||
|
this.raw._ !== 'chatParticipantCreator' &&
|
||||||
|
this.raw._ !== 'channelParticipantCreator' &&
|
||||||
|
this.raw._ !== 'channelParticipant' &&
|
||||||
|
this.raw._ !== 'channelParticipantBanned' &&
|
||||||
|
this.raw._ !== 'channelParticipantLeft' &&
|
||||||
|
this.raw.inviterId
|
||||||
|
) {
|
||||||
|
this._invitedBy = new User(
|
||||||
|
this.client,
|
||||||
|
this._users[this.raw.inviterId] as tl.RawUser
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._invitedBy = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._invitedBy
|
||||||
|
}
|
||||||
|
|
||||||
|
private _promotedBy?: User | null
|
||||||
|
/**
|
||||||
|
* Information about whoever promoted this admin.
|
||||||
|
*
|
||||||
|
* Only available if `status = admin`.
|
||||||
|
*/
|
||||||
|
get promotedBy(): User | null {
|
||||||
|
if (this._promotedBy === undefined) {
|
||||||
|
if (this.raw._ === 'channelParticipantAdmin') {
|
||||||
|
this._promotedBy = new User(
|
||||||
|
this.client,
|
||||||
|
this._users[this.raw.promotedBy] as tl.RawUser
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._promotedBy = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._promotedBy
|
||||||
|
}
|
||||||
|
|
||||||
|
private _restrictedBy?: User | null
|
||||||
|
/**
|
||||||
|
* Information about whoever restricted this user.
|
||||||
|
*
|
||||||
|
* Only available if `status = restricted or status = banned`
|
||||||
|
*/
|
||||||
|
get restrictedBy(): User | null {
|
||||||
|
if (this._restrictedBy === undefined) {
|
||||||
|
if (this.raw._ === 'channelParticipantBanned') {
|
||||||
|
this._restrictedBy = new User(
|
||||||
|
this.client,
|
||||||
|
this._users[this.raw.kickedBy] as tl.RawUser
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this._restrictedBy = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._restrictedBy
|
||||||
|
}
|
||||||
|
|
||||||
|
private _restrictions?: ChatPermissions
|
||||||
|
/**
|
||||||
|
* For restricted and banned users,
|
||||||
|
* information about the restrictions
|
||||||
|
*/
|
||||||
|
get restrictions(): ChatPermissions | null {
|
||||||
|
if (this.raw._ !== 'channelParticipantBanned') return null
|
||||||
|
|
||||||
|
if (!this._restrictions) {
|
||||||
|
this._restrictions = new ChatPermissions(this.raw.bannedRights)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._restrictions
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this member is a part of the chat now.
|
||||||
|
*
|
||||||
|
* Makes sense only when `status = restricted or staus = banned`
|
||||||
|
*/
|
||||||
|
get isMember(): boolean {
|
||||||
|
return this.raw._ === 'channelParticipantBanned'
|
||||||
|
? !this.raw.left
|
||||||
|
: this.raw._ !== 'channelParticipantLeft'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For admins and creator of supergroup/channels,
|
||||||
|
* list of their admin permissions.
|
||||||
|
*
|
||||||
|
* Also contains whether this admin is anonymous.
|
||||||
|
*/
|
||||||
|
get permissions(): tl.RawChatAdminRights | null {
|
||||||
|
return this.raw._ === 'channelParticipantAdmin' ||
|
||||||
|
this.raw._ === 'channelParticipantCreator'
|
||||||
|
? this.raw.adminRights
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(ChatMember)
|
|
@ -2,7 +2,7 @@ import { tl } from '@mtcute/tl'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the rights of a normal user in a {@link Chat}.
|
* Represents the permissions of a user in a {@link Chat}.
|
||||||
*/
|
*/
|
||||||
export class ChatPermissions {
|
export class ChatPermissions {
|
||||||
readonly _bannedRights: tl.RawChatBannedRights
|
readonly _bannedRights: tl.RawChatBannedRights
|
||||||
|
@ -115,6 +115,9 @@ export class ChatPermissions {
|
||||||
/**
|
/**
|
||||||
* UNIX date until which these permissions are valid,
|
* UNIX date until which these permissions are valid,
|
||||||
* or `null` if forever.
|
* or `null` if forever.
|
||||||
|
*
|
||||||
|
* For example, represents the time when the restrictions
|
||||||
|
* will be lifted from a {@link ChatMember}
|
||||||
*/
|
*/
|
||||||
get untilDate(): Date | null {
|
get untilDate(): Date | null {
|
||||||
return this._bannedRights.untilDate === 0
|
return this._bannedRights.untilDate === 0
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { tl } from '@mtcute/tl'
|
||||||
export * from './user'
|
export * from './user'
|
||||||
export * from './chat'
|
export * from './chat'
|
||||||
export * from './chat-preview'
|
export * from './chat-preview'
|
||||||
|
export * from './chat-member'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Peer types that have one-to-one relation to tl.Peer* types.
|
* Peer types that have one-to-one relation to tl.Peer* types.
|
||||||
|
|
Loading…
Reference in a new issue