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 { deleteGroup } from './methods/chats/delete-group'
|
||||
import { deleteHistory } from './methods/chats/delete-history'
|
||||
import { getChatMember } from './methods/chats/get-chat-member'
|
||||
import { getChatPreview } from './methods/chats/get-chat-preview'
|
||||
import { getChat } from './methods/chats/get-chat'
|
||||
import { getFullChat } from './methods/chats/get-full-chat'
|
||||
|
@ -69,6 +70,7 @@ import { IMessageEntityParser } from './parser'
|
|||
import { Readable } from 'stream'
|
||||
import {
|
||||
Chat,
|
||||
ChatMember,
|
||||
ChatPreview,
|
||||
FileDownloadParameters,
|
||||
InputFileLike,
|
||||
|
@ -444,6 +446,19 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
): Promise<void> {
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
User,
|
||||
Chat,
|
||||
ChatPreview,
|
||||
ChatMember,
|
||||
TermsOfService,
|
||||
SentCode,
|
||||
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'
|
||||
|
||||
/**
|
||||
* Represents the rights of a normal user in a {@link Chat}.
|
||||
* Represents the permissions of a user in a {@link Chat}.
|
||||
*/
|
||||
export class ChatPermissions {
|
||||
readonly _bannedRights: tl.RawChatBannedRights
|
||||
|
@ -115,6 +115,9 @@ export class ChatPermissions {
|
|||
/**
|
||||
* UNIX date until which these permissions are valid,
|
||||
* or `null` if forever.
|
||||
*
|
||||
* For example, represents the time when the restrictions
|
||||
* will be lifted from a {@link ChatMember}
|
||||
*/
|
||||
get untilDate(): Date | null {
|
||||
return this._bannedRights.untilDate === 0
|
||||
|
|
|
@ -3,6 +3,7 @@ import { tl } from '@mtcute/tl'
|
|||
export * from './user'
|
||||
export * from './chat'
|
||||
export * from './chat-preview'
|
||||
export * from './chat-member'
|
||||
|
||||
/**
|
||||
* Peer types that have one-to-one relation to tl.Peer* types.
|
||||
|
|
Loading…
Reference in a new issue