Skip to content

Commit ce677ba

Browse files
committed
feat: add commands for pinning, unpinning, and fetching top users; improve wa command error handling
1 parent 310a178 commit ce677ba

8 files changed

Lines changed: 171 additions & 3 deletions

File tree

src/commands/block.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default async function (msg: Message) {
1919
return;
2020
}
2121

22-
if (/^--rem$/.test(msg.body)) {
22+
if (/^block\s--rem/.test(msg.body)) {
2323
for (const userId of msg.mentionedIds) {
2424
const lid = userId.split("@")[0];
2525

@@ -28,7 +28,7 @@ export default async function (msg: Message) {
2828
});
2929
}
3030

31-
await msg.react("");
31+
await msg.react("");
3232
return;
3333
}
3434

src/commands/meme.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Message, MessageMedia } from "whatsapp-web.js";
2+
import axios from "axios";
3+
import log from "../components/utils/log";
4+
import fs from "fs/promises";
5+
6+
export const info = {
7+
command: "meme",
8+
description: "Fetch a random meme image.",
9+
usage: "meme",
10+
example: "meme",
11+
role: "user",
12+
cooldown: 5000,
13+
};
14+
15+
export default async function (msg: Message) {
16+
if (!/^meme$/i.test(msg.body)) return;
17+
18+
await axios
19+
.get("https://api.popcat.xyz/meme")
20+
.then(async (response) => {
21+
await axios
22+
.get(response.data.content.image, {
23+
responseType: "arraybuffer",
24+
})
25+
.then(async (response) => {
26+
const tempDir = "./.temp";
27+
await fs.mkdir(tempDir, { recursive: true });
28+
29+
const tempPath = `${tempDir}/meme_${Date.now()}.png`;
30+
await fs.writeFile(tempPath, response.data);
31+
32+
const media = MessageMedia.fromFilePath(tempPath);
33+
await msg.reply(media);
34+
await fs.unlink(tempPath);
35+
})
36+
.catch(async (error) => {
37+
log.error("meme", `Error fetching image: ${error.message}`);
38+
await msg.reply("Error fetching image. Please try again later.");
39+
});
40+
})
41+
.catch(async (error) => {
42+
log.error("meme", `Error fetching data: ${error.message}`);
43+
await msg.reply("Error fetching data. Please try again later.");
44+
});
45+
}

src/commands/pin.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Message } from "whatsapp-web.js";
2+
import log from "../components/utils/log";
3+
4+
export const info = {
5+
command: "pin",
6+
description: "Pin a message for a long duration.",
7+
usage: "pin",
8+
example: "pin",
9+
role: "user",
10+
cooldown: 5000,
11+
};
12+
13+
export default async function (msg: Message) {
14+
if (!/^pin$/i.test(msg.body)) return;
15+
16+
if (!msg.hasQuotedMsg) {
17+
await msg.reply("Please reply to the message you want to pin.");
18+
return;
19+
}
20+
21+
const quotedMsg = await msg.getQuotedMessage();
22+
if (!quotedMsg.body) {
23+
await msg.reply("Please reply to a message with the new status or name.");
24+
return;
25+
}
26+
27+
await quotedMsg.pin(24 * 60 * 60 * 1000 * 1000);
28+
}

src/commands/top.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 log from "../components/utils/log";
3+
import { getUsers } from "../components/services/user";
4+
5+
export const info = {
6+
command: "top",
7+
description: "Get the top users of the bot.",
8+
usage: "top",
9+
example: "top",
10+
role: "user",
11+
cooldown: 5000,
12+
};
13+
14+
export default async function (msg: Message) {
15+
if (!/^top$/i.test(msg.body)) return;
16+
17+
const user = await getUsers();
18+
if (!user || user.length === 0) {
19+
await msg.reply("No users found.");
20+
return;
21+
}
22+
23+
const text = `
24+
\`Top Users:\`
25+
26+
${user
27+
.filter((u, index) => u.commandCount !== 0 && index < 20)
28+
.map((u, index) => {
29+
const displayName =
30+
u.name.length > 12 ? u.name.slice(0, 12) + "..." : u.name;
31+
return `${index + 1}. ${displayName} - ${u.commandCount} Points`;
32+
})
33+
.join("\n ")}
34+
`;
35+
36+
await msg.reply(text);
37+
}

src/commands/unpin.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Message } from "whatsapp-web.js";
2+
import log from "../components/utils/log";
3+
4+
export const info = {
5+
command: "unpin",
6+
description: "Unpin a previously pinned message.",
7+
usage: "unpin",
8+
example: "unpin",
9+
role: "user",
10+
cooldown: 5000,
11+
};
12+
13+
export default async function (msg: Message) {
14+
if (!/^unpin$/i.test(msg.body)) return;
15+
16+
if (!msg.hasQuotedMsg) {
17+
await msg.reply("Please reply to the message you want to upin.");
18+
return;
19+
}
20+
21+
const quotedMsg = await msg.getQuotedMessage();
22+
if (!quotedMsg.body) {
23+
await msg.reply("Please reply to a pinnmed message.");
24+
return;
25+
}
26+
27+
await quotedMsg.unpin();
28+
}

src/commands/wa.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export default async function (msg: Message) {
2727
}
2828

2929
const quotedMsg = await msg.getQuotedMessage();
30+
if (!quotedMsg.body) {
31+
await msg.reply("Please reply to a message with the new status or name.");
32+
return;
33+
}
3034
if (query === "status") {
3135
client.setStatus(quotedMsg.body);
3236
await msg.reply("Status updated successfully.");

src/components/events/message.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default async function message(msg: Message) {
2222
if (msg.timestamp < Date.now() / 1000 - 10) return;
2323

2424
if (
25-
msg.hasQuotedMsg ||
25+
// (msg.hasQuotedMsg && !msg.fromMe) ||
2626
msg.isForwarded ||
2727
msg.isGif ||
2828
msg.isStatus ||

src/components/services/user.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,29 @@ export async function getBlockUserCount(): Promise<number> {
9595
return 0;
9696
}
9797
}
98+
99+
export async function getUsers(): Promise<any[]> {
100+
try {
101+
const users = await prisma.user.groupBy({
102+
by: ["number", "name"],
103+
_sum: {
104+
commandCount: true,
105+
},
106+
orderBy: {
107+
_sum: {
108+
commandCount: "desc",
109+
},
110+
},
111+
});
112+
113+
// format
114+
return users.map((u) => ({
115+
name: u.name,
116+
number: u.number,
117+
commandCount: u._sum.commandCount,
118+
}));
119+
} catch (error) {
120+
log.error("Database", `Failed to get users.`, error);
121+
return [];
122+
}
123+
}

0 commit comments

Comments
 (0)