Skip to content

Commit 88a08d0

Browse files
committed
added custom commands
1 parent 5fe5bd4 commit 88a08d0

File tree

7 files changed

+325
-2
lines changed

7 files changed

+325
-2
lines changed

handlers/commands/addCommand.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
// DB
4+
const { isAdmin } = require('../../stores/user');
5+
const { addCommand } = require('../../stores/command');
6+
7+
// Bot
8+
const { replyOptions } = require('../../bot/options');
9+
10+
const addCommandHandler = async ({ chat, message, reply }) => {
11+
const user = message.from;
12+
if (chat.type !== 'private') {
13+
return null;
14+
}
15+
if (!await isAdmin(user)) {
16+
return reply('ℹ️ <b>Sorry, only admins access this command.</b>',
17+
replyOptions);
18+
}
19+
await addCommand({ id: user.id });
20+
return reply('Enter a name for the command.\n\nFor example: <b>rules</b>',
21+
replyOptions);
22+
};
23+
24+
module.exports = addCommandHandler;

handlers/commands/commands.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict';
22

3+
// DB
4+
const { listCommands } = require('../../stores/command');
5+
36
const commandReference = `\
47
<b>Master commands</b>:
58
<code>/admin</code> - Makes the user admin.
@@ -21,11 +24,25 @@ const commandReference = `\
2124
<code>/report</code> - Reports the replied-to message to admins.
2225
`;
2326

24-
const commandReferenceHandler = ({ chat, replyWithHTML }) => {
27+
const actions = `\n
28+
/addcommand - to create custom commands.
29+
/removecommand <code>&lt;name&gt;</code> - to remove a custom command.`;
30+
31+
const commandReferenceHandler = async ({ chat, replyWithHTML }) => {
2532
if (chat.type !== 'private') {
2633
return null;
2734
}
28-
return replyWithHTML(commandReference);
35+
const customCommands = await listCommands();
36+
const customCommandsText = customCommands.length
37+
? '\n<b>Custom commands:</b>\n' +
38+
customCommands
39+
.filter(command => command.isActive)
40+
.sort((a, b) => a.role < b.role)
41+
.map(command => `[${command.role}] <code>/${command.name}</code>`)
42+
.join('\n')
43+
: '';
44+
45+
return replyWithHTML(commandReference + customCommandsText + actions);
2946
};
3047

3148
module.exports = commandReferenceHandler;

handlers/commands/removeCommand.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
// Utils
4+
const { loadJSON } = require('../../utils/json');
5+
6+
// Config
7+
const { masterID } = loadJSON('config.json');
8+
9+
// DB
10+
const { isAdmin } = require('../../stores/user');
11+
const { getCommand, removeCommand } = require('../../stores/command');
12+
13+
// Bot
14+
const { replyOptions } = require('../../bot/options');
15+
16+
const removeCommandHandler = async ({ chat, message, reply }) => {
17+
const user = message.from;
18+
const { text } = message;
19+
if (chat.type !== 'private') {
20+
return null;
21+
}
22+
if (!await isAdmin(user)) {
23+
return reply('ℹ️ <b>Sorry, only admins access this command.</b>',
24+
replyOptions);
25+
}
26+
const [ , commandName ] = text.split(' ');
27+
if (!commandName) {
28+
return reply(
29+
'Enter a command name to remove.\n\n' +
30+
'For example:\n/removecommand <b>rules</b>',
31+
replyOptions);
32+
}
33+
34+
const command = await getCommand({ name: commandName });
35+
if (!command) {
36+
return reply('ℹ️ <b>Command couldn\'t be found.</b>',
37+
replyOptions);
38+
}
39+
40+
if (command.role === 'Master' && user.id !== masterID) {
41+
return reply('ℹ️ <b>Sorry, only master can remove this command.</b>',
42+
replyOptions);
43+
}
44+
45+
await removeCommand({ name: commandName });
46+
return reply(
47+
`✅ <code>/${commandName}</code> ` +
48+
'<b>has been removed successfully.</b>',
49+
replyOptions);
50+
};
51+
52+
module.exports = removeCommandHandler;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
'use strict';
2+
3+
const { Markup } = require('telegraf');
4+
5+
// Bot
6+
const { replyOptions } = require('../../bot/options');
7+
8+
// DB
9+
const { isAdmin } = require('../../stores/user');
10+
const {
11+
getCommand,
12+
removeCommand,
13+
updateCommand
14+
} = require('../../stores/command');
15+
16+
const addCustomCmdHandler = async ({ chat, message, reply }, next) => {
17+
const { text, photo, document, video, audio } = message;
18+
const { id } = message.from;
19+
20+
if (text && /^\/\w+/.test(text)) {
21+
await removeCommand({ id, isActive: false });
22+
return next();
23+
}
24+
25+
const command = await getCommand({ id, isActive: false });
26+
if (chat.type !== 'private' ||
27+
!await isAdmin(message.from) ||
28+
!command ||
29+
!command.state) {
30+
return next();
31+
}
32+
33+
const { state } = command;
34+
if (state === 'add') {
35+
if (!/^(?=\D)\w+$/.test(text)) {
36+
reply('Please send a valid command.');
37+
return next();
38+
}
39+
if (await getCommand({ isActive: true, name: text })) {
40+
reply(
41+
'ℹ️ <b>This command already exists.</b>\n\n' +
42+
'/commands - to see the list of commands.\n' +
43+
'/addcommand - to add a command.\n' +
44+
'/removecommand <code>&lt;name&gt;</code>' +
45+
' - to remove a command.',
46+
replyOptions);
47+
return next();
48+
}
49+
await updateCommand({ id, name: text, state: 'role' });
50+
reply('Who can use this command?', Markup.keyboard([
51+
[ 'Master', 'Admins', 'Everyone' ]
52+
])
53+
.oneTime()
54+
.resize()
55+
.extra());
56+
return next();
57+
}
58+
59+
if (state === 'role') {
60+
if (text !== 'Master' && text !== 'Admins' && text !== 'Everyone') {
61+
reply('Please send a valid role.', Markup.keyboard([
62+
[ 'Master', 'Admins', 'Everyone' ]
63+
])
64+
.oneTime()
65+
.resize()
66+
.extra());
67+
return next();
68+
}
69+
await updateCommand({ id, role: text, state: 'content' });
70+
reply(
71+
'Send the content you wish to be shown when the command is used.' +
72+
'.\n\nSupported contents:\n- <b>Text (HTML)</b>\n- <b>Photo</b>' +
73+
'\n- <b>Video</b>\n- <b>Document</b>\n- <b>Audio</b>',
74+
replyOptions);
75+
return next();
76+
}
77+
78+
if (state === 'content') {
79+
let newCommand;
80+
if (text) {
81+
newCommand = { content: text, type: 'text' };
82+
}
83+
if (photo) {
84+
newCommand = {
85+
content: photo[photo.length - 1].file_id,
86+
type: 'photo'
87+
};
88+
}
89+
if (document) {
90+
newCommand = { content: document.file_id, type: 'document' };
91+
}
92+
if (video) {
93+
newCommand = { content: video.file_id, type: 'video' };
94+
}
95+
if (audio) {
96+
newCommand = { content: audio.file_id, type: 'audio' };
97+
}
98+
if (message.caption) {
99+
newCommand.caption = message.caption;
100+
}
101+
await Promise.all([
102+
updateCommand(Object.assign(
103+
{},
104+
newCommand,
105+
{ id, isActive: true, state: null })),
106+
]);
107+
reply(
108+
'✅ <b>New command has been created successfully.</b>\n\n' +
109+
'This command can be used in groups now. ' +
110+
'Custom commands can reply other messages too.\n\n' +
111+
'/commands - to see the list of commands.\n' +
112+
'/addcommand - to add a new command.\n' +
113+
'/removecomand <code>&lt;name&gt;</code> - to remove a command.',
114+
replyOptions);
115+
return next();
116+
}
117+
return next();
118+
};
119+
120+
module.exports = addCustomCmdHandler;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
3+
// Utils
4+
const { loadJSON } = require('../../utils/json');
5+
6+
// Config
7+
const { masterID } = loadJSON('config.json');
8+
9+
// DB
10+
const { getCommand } = require('../../stores/command');
11+
const { isAdmin } = require('../../stores/user');
12+
13+
const runCustomCmdHandler = async (ctx, next) => {
14+
const { message } = ctx;
15+
const user = message.from;
16+
const isCommand = message.entities &&
17+
message.entities.filter(entity => entity.type === 'bot_command');
18+
if (!isCommand || !isCommand.length) {
19+
return next();
20+
}
21+
22+
const commandName = message.text.split(' ')[0].replace('/', '');
23+
const command = await getCommand({ isActive: true, name: commandName });
24+
25+
if (!command) {
26+
return next();
27+
}
28+
29+
const { caption, content, role, type } = command;
30+
const replyTo = message.reply_to_message
31+
? { reply_to_message_id: message.reply_to_message.message_id }
32+
: {};
33+
const options = Object.assign(replyTo, caption ? { caption } : {});
34+
if (
35+
role === 'Master' &&
36+
user.id !== masterID ||
37+
role === 'Admins' &&
38+
!await isAdmin(user)
39+
) {
40+
return next();
41+
}
42+
43+
if (type === 'text') {
44+
ctx.replyWithHTML(content, options);
45+
return next();
46+
}
47+
if (type === 'photo') {
48+
ctx.replyWithPhoto(content, options);
49+
return next();
50+
}
51+
if (type === 'video') {
52+
ctx.replyWithVideo(content, replyTo);
53+
return next();
54+
}
55+
if (type === 'document') {
56+
ctx.replyWithDocument(content, replyTo);
57+
return next();
58+
}
59+
if (type === 'audio') {
60+
ctx.replyWithAudio(content, replyTo);
61+
return next();
62+
}
63+
return next();
64+
};
65+
66+
module.exports = runCustomCmdHandler;

index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ const kickBannedHandler = require('./handlers/middlewares/kickBanned');
1818
const addUserHandler = require('./handlers/middlewares/addUser');
1919
const removeLinksHandler = require('./handlers/middlewares/removeLinks');
2020
const checkUsernameHandler = require('./handlers/middlewares/checkUsername');
21+
const addCustomCmdHandler = require('./handlers/middlewares/addCustomCmd');
22+
const runCustomCmdHandler = require('./handlers/middlewares/runCustomCmd');
2123
const antibotHandler = require('./handlers/middlewares/antibot');
2224
const addedToGroupHandler = require('./handlers/middlewares/addedToGroup');
2325

@@ -36,6 +38,8 @@ const staffHandler = require('./handlers/commands/staff');
3638
const linkHandler = require('./handlers/commands/link');
3739
const groupsHandler = require('./handlers/commands/groups');
3840
const commandReferenceHandler = require('./handlers/commands/commands');
41+
const addCommandHandler = require('./handlers/commands/addCommand');
42+
const removeCommandHandler = require('./handlers/commands/removeCommand');
3943
const helpHandler = require('./handlers/commands/help');
4044

4145
bot.on('new_chat_members', addedToGroupHandler);
@@ -45,6 +49,8 @@ bot.use(kickBannedHandler);
4549
bot.on('message', addUserHandler);
4650
bot.on('message', removeLinksHandler);
4751
bot.on('message', checkUsernameHandler);
52+
bot.on('message', addCustomCmdHandler);
53+
bot.on('message', runCustomCmdHandler);
4854
bot.on('new_chat_members', antibotHandler);
4955
bot.on([ 'new_chat_members', 'left_chat_member' ], deleteAfter(2 * 60 * 1000));
5056
bot.command('admin', adminHandler);
@@ -62,6 +68,8 @@ bot.command('staff', staffHandler);
6268
bot.command('link', linkHandler);
6369
bot.command('groups', groupsHandler);
6470
bot.command('commands', commandReferenceHandler);
71+
bot.command('addcommand', addCommandHandler);
72+
bot.command('removecommand', removeCommandHandler);
6573
bot.command([ 'start', 'help' ], helpHandler);
6674

6775
bot.catch(logError);

stores/command.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
const Datastore = require('nedb-promise');
4+
5+
const Command = new Datastore({
6+
autoload: true,
7+
filename: 'data/Command.db',
8+
});
9+
10+
Command.ensureIndex({
11+
fieldName: 'name',
12+
unique: true,
13+
});
14+
15+
const addCommand = command =>
16+
Command.update(
17+
{ id: command.id, isActive: false },
18+
{ id: command.id, isActive: false, state: 'add', },
19+
{ upsert: true });
20+
21+
const updateCommand = (data) =>
22+
Command.update({ id: data.id, isActive: false }, { $set: data });
23+
24+
const removeCommand = command => Command.remove(command);
25+
26+
const getCommand = (data) => Command.findOne(data);
27+
28+
const listCommands = () => Command.find({ isActive: true });
29+
30+
module.exports = {
31+
addCommand,
32+
getCommand,
33+
listCommands,
34+
removeCommand,
35+
updateCommand,
36+
};

0 commit comments

Comments
 (0)