Skip to content

Commit 085b8fc

Browse files
committed
feat: add logout and test commands
1 parent 896ee9d commit 085b8fc

10 files changed

Lines changed: 152 additions & 46 deletions

File tree

.env.example

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ PORT=3000
1818
# automatically reloads commands as they are edited
1919
AUTO_RELOAD=false
2020

21-
# the phone number of the super admin, used for privileged commands
22-
# this should be a valid phone number in the format
23-
SUPER_ADMIN=09123456789
24-
2521
# the database connection URL
2622
DATABASE_URL=mysql://root@localhost:3306/project_canis
2723

src/commands/help.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { commands } from "../index";
44

55
export const info = {
66
command: "help",
7-
description: "List all available commands.",
8-
usage: "help",
9-
example: "help",
7+
description: "List available commands and their usage.",
8+
usage: "help [page] | [role]",
9+
example: "help admin",
1010
role: "user",
1111
cooldown: 5000,
1212
};

src/commands/logout.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Message } from "whatsapp-web.js";
2+
import { client } from "../components/client";
3+
import log from "../components/utils/log";
4+
5+
export const info = {
6+
command: "logout",
7+
description: "Log out the client from WhatsApp.",
8+
usage: "logout",
9+
example: "logout",
10+
role: "admin",
11+
cooldown: 5000,
12+
};
13+
14+
export default async function (msg: Message) {
15+
if (!/^logout\b/i.test(msg.body)) return;
16+
17+
try {
18+
await client.logout();
19+
log.info("Logout", "Client logged out successfully.");
20+
} catch (error) {
21+
log.error("Logout", "Failed to log out the client.", error);
22+
await msg.reply("An error occurred while trying to log out.");
23+
}
24+
}

src/commands/qrcode.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ export default async function (msg: Message) {
3535
await fs.writeFile(tempPath, response.data);
3636

3737
const media = MessageMedia.fromFilePath(tempPath);
38-
await msg.reply(media);
38+
await msg.reply(media, msg.from, {
39+
caption: query,
40+
});
3941
await fs.unlink(tempPath);
4042
})
4143
.catch(async (error) => {

src/commands/reload.ts

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const info = {
1010
command: "reload",
1111
description: "Reload a specific command or all commands.",
1212
usage: "reload [command]",
13-
example: "reload poli",
13+
example: "reload ai",
1414
role: "admin",
1515
cooldown: 5000,
1616
};
@@ -36,39 +36,53 @@ export default async function (msg: Message) {
3636
}
3737
}
3838

39-
if (!found) await msg.reply(`Failed to reload command "${query}".`);
40-
if (found) await msg.reply(`Reloaded command "${query}".`);
39+
if (!found)
40+
await msg.reply(
41+
`
42+
\`Failed to load\`
43+
${query}
44+
`
45+
);
46+
if (found)
47+
await msg.reply(
48+
`
49+
\`Successfully reloaded\`
50+
${query}
51+
`
52+
);
4153
return;
4254
}
4355

4456
// Reload all commands
4557
let count = 0;
58+
const newCommands: string[] = [];
59+
const removeCommands: string[] = [];
4660
const commandsPath = path.join(__dirname, "..", "commands");
61+
4762
fs.readdirSync(commandsPath).forEach((file) => {
4863
if (/\.js$|\.ts$/.test(file)) {
49-
const filePath = path.join(commandsPath, file);
50-
delete require.cache[require.resolve(filePath)];
51-
const commandModule = require(filePath);
52-
53-
if (
54-
typeof commandModule.default === "function" &&
55-
commandModule.info &&
56-
commandModule.info.command
57-
) {
58-
commands[commandModule.info.command] = {
59-
command: commandModule.info.command,
60-
description: commandModule.info.description || "No description",
61-
usage: commandModule.info.usage || "No usage",
62-
example: commandModule.info.example || "No example",
63-
role: commandModule.info.user || "user",
64-
cooldown: commandModule.info.cooldown || 5000,
65-
exec: commandModule.default,
66-
};
67-
count++;
68-
log.info("Loader", `Reloaded command: ${commandModule.info.command}`);
64+
const commandName = file.replace(/\.(js|ts)$/, "");
65+
if (!commands[commandName]) {
66+
newCommands.push(commandName);
67+
} else {
68+
removeCommands.push(commandName);
6969
}
70+
Loader(file);
71+
count++;
7072
}
7173
});
7274

73-
await msg.reply(`Reloaded ${count} commands.`);
75+
let text = `
76+
\`Reloaded\`
77+
${count} commands
78+
`;
79+
80+
if (newCommands.length > 0) {
81+
text += `
82+
\`Found new command(s)\`
83+
${newCommands.join(", ")}
84+
`;
85+
}
86+
87+
await msg.reply(text);
7488
}

src/commands/stats.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import log from "../components/utils/log";
33
import os from "os";
44
import si from "systeminformation";
55
import { getUserCount, getBlockUserCount } from "../components/services/user";
6+
import { client } from "../components/client";
7+
import { commands } from "../index";
68

79
export const info = {
810
command: "stats",
@@ -23,15 +25,25 @@ export default async function (msg: Message) {
2325
totalMemory: os.totalmem(),
2426
};
2527

26-
const [gpuInfo, osInfo, shell, networkInterfaces, userCount, blockUserCount] =
27-
await Promise.all([
28-
si.graphics(),
29-
si.osInfo(),
30-
si.shell(),
31-
si.networkInterfaces(),
32-
getUserCount(),
33-
getBlockUserCount(),
34-
]);
28+
const [
29+
gpuInfo,
30+
osInfo,
31+
shell,
32+
networkInterfaces,
33+
userCount,
34+
blockUserCount,
35+
whatsAppVersion,
36+
whatsAppState,
37+
] = await Promise.all([
38+
si.graphics(),
39+
si.osInfo(),
40+
si.shell(),
41+
si.networkInterfaces(),
42+
getUserCount(),
43+
getBlockUserCount(),
44+
client.getWWebVersion(),
45+
client.getState()
46+
]);
3547

3648
const statsMessage = `
3749
\`System Monitor\`
@@ -54,6 +66,9 @@ export default async function (msg: Message) {
5466
.map((iface) => `${iface.iface} ${iface.speed} Mbps`)
5567
.join(", ")}
5668
Node.js: ${process.version}
69+
WA: ${whatsAppVersion}
70+
WA State: ${whatsAppState}
71+
Commands: ${Object.keys(commands).length}
5772
Users: ${userCount}
5873
Blocked Users: ${blockUserCount}
5974
`;

src/commands/test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Message } from "whatsapp-web.js";
2+
import log from "../components/utils/log";
3+
4+
export const info = {
5+
command: "test",
6+
description: "A simple test command.",
7+
usage: "test",
8+
example: "test",
9+
role: "user",
10+
cooldown: 5000,
11+
};
12+
13+
export default async function (msg: Message) {
14+
if (!/^test\b/i.test(msg.body)) return;
15+
16+
await msg.reply("This is a test response.");
17+
}

src/commands/video.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ export default async function (msg: Message) {
6666
`${title}.mp4`
6767
);
6868

69-
await msg.reply(media, msg.from);
69+
await msg.reply(media, msg.from, {
70+
caption: `${title}`,
71+
});
7072
await fs.promises.unlink(tempPath);
7173
await fs.promises.unlink(tempPath + ".mp4");
7274
}

src/commands/wa.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Message } from "whatsapp-web.js";
2+
import { client } from "../components/client";
3+
4+
export const info = {
5+
command: "wa",
6+
description: "Set WhatsApp status or name.",
7+
usage: "wa [status | name]",
8+
example: "wa status",
9+
role: "admin",
10+
cooldown: 5000,
11+
};
12+
13+
export default async function (msg: Message) {
14+
const query = msg.body.replace(/^wa\b\s*/i, "").trim();
15+
if (query.length !== 0) {
16+
if (!/^(status|name)$/i.test(query)) {
17+
await msg.reply(
18+
"Invalid argument. Please use one of the following:\n\nstatus or name"
19+
);
20+
return;
21+
}
22+
}
23+
24+
if (msg.hasQuotedMsg) {
25+
await msg.reply("Please reply to a message to set the status or name.");
26+
return;
27+
}
28+
29+
const quotedMsg = await msg.getQuotedMessage();
30+
if (query === "status") {
31+
client.setStatus(quotedMsg.body);
32+
await msg.reply("Status updated successfully.");
33+
return;
34+
}
35+
client.setDisplayName(quotedMsg.body);
36+
await msg.reply("Name updated successfully.");
37+
}

src/components/events/message.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import Font from "../utils/font";
1616
const commandPrefix = process.env.COMMAND_PREFIX || "!";
1717
const commandPrefixLess = process.env.COMMAND_PREFIX_LESS === "true";
1818
const debug = process.env.DEBUG === "true";
19-
const superAdmin = process.env.SUPER_ADMIN || "";
2019

2120
export default async function message(msg: Message) {
2221
// ignore message if it is older than 10 seconds
@@ -61,19 +60,19 @@ export default async function message(msg: Message) {
6160
/*
6261
* Rate limit commands to prevent abuse.
6362
*/
64-
if (senderId !== superAdmin) {
63+
if (!msg.fromMe) {
6564
const rate = rateLimiter(msg.from);
6665
if (rate === null) return;
6766
if (!rate) {
68-
msg.reply("You are sending commands too fast. Please wait a minute.");
67+
msg.reply("Please wait a minute or so.");
6968
return;
7069
}
7170
}
7271

7372
/*
7473
* Role base restrictions.
7574
*/
76-
if (handler.role === "admin" && !msg.fromMe && senderId !== superAdmin) {
75+
if (handler.role === "admin" && !msg.fromMe) {
7776
return;
7877
}
7978

0 commit comments

Comments
 (0)