Skip to content

Commit

Permalink
feat: add admin module(#62)
Browse files Browse the repository at this point in the history
Co-authored-by: Roj <[email protected]>
  • Loading branch information
ArnabXD and rojvv committed Mar 5, 2022
1 parent 67c5c0e commit 3931f92
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 4 deletions.
25 changes: 21 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"preversion": "echo \"export const version = \\\"\"$npm_new_version\"\\\"\" > src/constants.ts && git add src/constants.ts"
},
"dependencies": {
"@xorgram/methods": "^0.0.0-test.0",
"big-integer": "^1.6.51",
"dotenv": "^16.0.0",
"envalid": "^7.3.0",
Expand Down
92 changes: 92 additions & 0 deletions src/modules/admin/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Api, TelegramClient } from 'telegram'
import { NewMessageEvent } from 'telegram/events'
import { RPCError } from 'telegram/errors'

export const getUser = async (
event: NewMessageEvent,
client: TelegramClient,
args: string[],
getRank = false
) => {
let entity = {} as Api.User
let rank = 'Admin'
const reply = await event.message.getReplyMessage()
if (reply) {
const sender = await reply.getSender()
if (sender && sender instanceof Api.User) {
entity = sender
}
if (getRank && args[0]) {
rank = args[0]
}
} else if (args[0] !== undefined && args[0].length != 0) {
const _entity = await client.getEntity(args[0])
if (!(_entity instanceof Api.User)) {
await event.message.edit({
text: event.message.text + '\n' + 'Invalid user ID or username.'
})
return
}
entity = _entity
if (getRank && args[1]) {
rank = args[1]
}
}
return {
entity,
rank: rank
}
}

export const ExpectedErrors: { [key: string]: string } = {
// Edit Admin Rights
ADMINS_TOO_MUCH: 'There are too many admins.',
ADMIN_RANK_EMOJI_NOT_ALLOWED: 'The admin title cannot contain emojis.',
ADMIN_RANK_INVALID: 'The specified admin title is invalid.',
BOTS_TOO_MUCH: 'There are too many bots.',
BOT_CHANNELS_NA: 'Bots cannot edit admin privileges.',
BOT_GROUPS_BLOCKED: 'This bot cannot be added to groups.',
CHANNEL_INVALID: 'The provided channel is invalid.',
CHANNEL_PRIVATE: 'You have not joined this chat.',
CHAT_ADMIN_INVITE_REQUIRED: 'You do not have the rights to do this.',
CHAT_ADMIN_REQUIRED: 'You must be an admin to do this.',
CHAT_WRITE_FORBIDDEN: 'You cannot write in this chat.',
FRESH_CHANGE_ADMINS_FORBIDDEN: 'You cannot add or modify other admins yet.',
INPUT_USER_DEACTIVATED: 'The specified user was deleted.',
PEER_ID_INVALID: 'The provided ID is invalid.',
RIGHT_FORBIDDEN: 'Your rights do not allow you to do this.',
USERS_TOO_MUCH: 'The maximum number of users has been exceeded.',
USER_BLOCKED: 'User blocked.',
USER_CHANNELS_TOO_MUCH:
'One of the users you tried to add is in too many chats.',
USER_CREATOR: 'You cannot leave this channel, because you are its creator.',
USER_ID_INVALID: 'The provided user ID is invalid.',
USER_NOT_MUTUAL_CONTACT: 'The provided user is not a mutual contact.',
USER_PRIVACY_RESTRICTED:
'The user’s privacy settings do not allow you to do this.',
USER_RESTRICTED: 'You’re restricted, you cannot create channels or chats.',
// PIN
CHAT_NOT_MODIFIED: 'The pinned message was not modified.',
MESSAGE_ID_INVALID: 'Message ID invalid.',
PIN_RESTRICTED: 'You canot pin messages.',
USER_BANNED_IN_CHANNEL:
'You are banned from sending messages in supergroups/channels.'
}

export async function wrapRpcErrors(
event: NewMessageEvent,
func: () => Promise<void> | void
) {
try {
await func()
} catch (error) {
if (error instanceof RPCError && ExpectedErrors[error['errorMessage']]) {
await event.message.edit({
text: event.message.text + '\n' + ExpectedErrors[error['errorMessage']]
})
return
} else {
throw error
}
}
}
212 changes: 212 additions & 0 deletions src/modules/admin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import { Api } from 'telegram'
import { Methods } from '@xorgram/methods'
import { CommandHandler } from '../../handlers'
import { Module } from '../../module'
import { getUser, wrapRpcErrors } from './helpers'

const admin: Module = {
name: 'admin',
handlers: [
new CommandHandler('promote', async (client, event, args) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const user = await getUser(event, client, args, true)
if (!user) {
await event.message.edit({ text: 'User not found.' })
return
}
if (chat instanceof Api.Channel) {
const xor = new Methods(client)
await wrapRpcErrors(event, async () => {
await xor.promoteChatMember({
chatId: chat.id,
userId: user.entity,
rank: user.rank,
canChangeInfo: chat.adminRights?.changeInfo,
canDeleteMessages: chat.adminRights?.deleteMessages,
canEditMessages: chat.adminRights?.editMessages,
canInviteUsers: chat.adminRights?.inviteUsers,
canManageCalls: chat.adminRights?.manageCall,
canPinMessages: chat.adminRights?.pinMessages,
canPromoteMembers: chat.adminRights?.addAdmins,
canRestrictMembers: chat.adminRights?.banUsers
})
await event.message.edit({
text: event.message.text + '\n' + 'User promoted.'
})
})
} else {
await event.message.edit({
text: event.message.text + '\n' + 'Cannot promote here.'
})
}
}),
new CommandHandler('demote', async (client, event, args) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const user = await getUser(event, client, args)
if (!user) {
await event.message.edit({
text: event.message.text + '\n' + 'User not found.'
})
return
}
if (chat instanceof Api.Channel) {
const xor = new Methods(client)
await wrapRpcErrors(event, async () => {
await xor.promoteChatMember({
chatId: chat.id,
userId: user.entity,
rank: user.rank,
canManageChat: false
})
await event.message.edit({
text: event.message.text + '\n' + 'User demoted.'
})
})
} else {
await event.message.edit({
text: event.message.text + '\n' + 'Cannot demote here.'
})
}
}),
new CommandHandler('ban', async (client, event, args) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const user = await getUser(event, client, args)
if (!user) {
await event.message.edit({
text: event.message.text + '\n' + 'User not found.'
})
return
}
await wrapRpcErrors(event, async () => {
const xor = new Methods(client)
await xor.banChatMember({
chatId: chat.id,
userId: await client.getEntity(user.entity)
})
await event.message.edit({
text: event.message.text + '\n' + 'User banned.'
})
})
}),
new CommandHandler('unban', async (client, event, args) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const user = await getUser(event, client, args)
if (!user) {
await event.message.edit({
text: event.message.text + '\n' + 'User not found.'
})
return
}

await wrapRpcErrors(event, async () => {
const xor = new Methods(client)
await xor.unbanChatMember({
chatId: chat.id,
userId: await client.getEntity(user.entity)
})
await event.message.edit({
text: event.message.text + '\n' + 'User unbanned.'
})
})
}),
new CommandHandler('pin', async (client, event, args) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const reply = await event.message.getReplyMessage()
if (reply) {
const xor = new Methods(client)
await wrapRpcErrors(event, async () => {
await xor.pinChatMessage({
chatId: chat.id,
messageId: reply.id,
disableNotification: args[0] === 'silent'
})
await event.message.edit({
text: event.message.text + '\n' + 'Message pinned.'
})
})
} else {
await event.message.edit({
text: event.message.text + '\n' + 'Reply a the message to pin.'
})
}
}),
new CommandHandler('unpin', async (client, event) => {
const chat = await event.message.getChat()
if (!chat) {
return
}
const reply = await event.message.getReplyMessage()
if (reply) {
const xor = new Methods(client)
await wrapRpcErrors(event, async () => {
const resp = await xor.unpinChatMessage({
chatId: chat.id,
messageId: reply.id
})
if (resp instanceof Api.Updates) {
await event.message.edit({
text:
event.message.text + '\n' + resp.updates.length
? 'Message unpinned.'
: 'Message was not pinned.'
})
}
})
} else {
await event.message.edit({
text: event.message.text + '\n' + 'Reply a pinned message to unpin.'
})
}
})
],
help: `
**Introduction**
This module aims to make administering chats easy.
**Commands**
- promote
Promotes the requested user in a chat. Takes admin title as argument.
- demote
Demotes the requested user in a chat.
- ban
Bans the requested user from a chat.
- unban
Unbans the requested user from a chat.
*Note: The commands above work by replying to a user or passing their ID or handle as the first argument.*
- pin
Pins the replied message in a chat. Pass "silent" to not notify the members.
- unpin
Unpins the replied pinned message.
`
}

export default admin

0 comments on commit 3931f92

Please sign in to comment.