Skip to content

Commit 435d31a

Browse files
committed
Fix tests
1 parent 7462f40 commit 435d31a

26 files changed

+463
-256
lines changed

.eslintrc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@
4242
],
4343
"functional/prefer-readonly-type": "error",
4444
"functional/no-this-expression": "error",
45-
"functional/no-loop-statement": "error"
45+
"functional/no-loop-statement": "error",
46+
47+
"typescript-eslint/no-unsafe-assignment": "off",
48+
"typescript-eslint/no-unsafe-call": "off",
49+
"typescript-eslint/no-unsafe-member-access": "off"
4650
},
4751
"overrides": [
4852
{

count-messages.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Discord, { Intents } from 'discord.js';
1+
import Discord, { GatewayIntentBits } from 'discord.js';
22
import fetch from 'node-fetch';
33

44
import { getConfig } from './src/config';
@@ -23,11 +23,14 @@ async function init() {
2323
process.exit(0);
2424
}
2525

26-
const intents = new Intents([
27-
Intents.NON_PRIVILEGED, // include all non-privileged intents, would be better to specify which ones you actually need
28-
'GUILD_MEMBERS', // lets you request guild members (i.e. fixes the issue)
29-
]);
30-
const client = new Discord.Client({ ws: { intents } });
26+
const client = new Discord.Client({
27+
intents: [
28+
GatewayIntentBits.Guilds,
29+
GatewayIntentBits.GuildMessages,
30+
GatewayIntentBits.MessageContent,
31+
GatewayIntentBits.GuildMembers,
32+
],
33+
});
3134
await client.login(getConfig('DISCORD_BOT_TOKEN'));
3235

3336
const guild = await client.guilds.fetch(GUILD_ID);
@@ -42,11 +45,6 @@ async function init() {
4245
await members.reduce(async (acc, member) => {
4346
await acc;
4447

45-
if (member.deleted) {
46-
// console.log(`Skipping… member.deleted`);
47-
return acc;
48-
}
49-
5048
const existingMember = await statsCollection.findOne({
5149
memberId: member.id,
5250
});

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
},
2222
"keywords": [],
2323
"author": "Michał Miszczyszyn <[email protected]> (https://typeofweb.com/)",
24-
"license": "ISC",
24+
"license": "AGPL",
2525
"dependencies": {
2626
"@types/bluebird": "3.5.36",
2727
"algoliasearch": "4.14.2",
2828
"bluebird": "3.7.2",
2929
"bufferutil": "4.0.6",
30-
"discord.js": "12.5.3",
31-
"dotenv": "10.0.0",
30+
"discord.js": "14.3.0",
31+
"dotenv": "16.0.2",
3232
"isolated-vm": "4.4.1",
3333
"mongodb": "4.9.1",
3434
"monitorss": "6.14.11",

src/app.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
1-
import Discord from 'discord.js';
1+
import Discord, { GatewayIntentBits } from 'discord.js';
22
import MonitoRSS from 'monitorss';
33
import type { ClientConfig } from 'monitorss';
44
import Cache from 'node-cache';
55

66
import { handleCommand } from './commands';
77
import { KARMA_REGEX } from './commands/karma';
8-
import { getConfig } from './config';
9-
import { createHttpServer } from './http-server';
10-
import { InvalidUsageError } from './types';
11-
import { getWeekNumber, wrapErr } from './utils';
12-
import { getStatsCollection, initDb } from './db';
138
import { messageToReflinks } from './commands/reflink';
9+
import { getConfig } from './config';
1410
import { updateKarmaRoles } from './cron/roles/karma';
1511
import { updateStatsRoles } from './cron/roles/stats';
12+
import { getStatsCollection, initDb } from './db';
13+
import { createHttpServer } from './http-server';
1614
import { thx } from './thx';
15+
import { InvalidUsageError } from './types';
16+
import { getWeekNumber, wrapErr } from './utils';
1717

1818
const MESSAGE_COLLECTOR_CACHE_S = 60 * 60;
1919
const messageCollectorCache = new Cache({ stdTTL: MESSAGE_COLLECTOR_CACHE_S });
2020

21-
const client = new Discord.Client();
21+
const client = new Discord.Client({
22+
intents: [
23+
GatewayIntentBits.Guilds,
24+
GatewayIntentBits.GuildMessages,
25+
GatewayIntentBits.MessageContent,
26+
GatewayIntentBits.GuildMembers,
27+
],
28+
});
2229

2330
const settings: { readonly setPresence: boolean; readonly config: ClientConfig } = {
2431
setPresence: true,
@@ -77,7 +84,7 @@ function isCommand(msg: Discord.Message) {
7784
// const ROLE_MUTED_NAME = 'muted' as const;
7885
// const MAX_MENTIONS_PER_MESSAGE = 10;
7986

80-
client.on('message', async (msg) => {
87+
client.on('messageCreate', async (msg) => {
8188
if (msg.author.bot) {
8289
return;
8390
}
@@ -92,14 +99,15 @@ client.on('message', async (msg) => {
9299
// }
93100

94101
if (msg.content === `(╯°□°)╯︵ ┻━┻`) {
95-
return msg.channel.send(`┬─┬ノ( ◕◡◕ ノ)`);
102+
await msg.channel.send(`┬─┬ノ( ◕◡◕ ノ)`);
103+
return;
96104
}
97105

98106
if (isCommand(msg)) {
99107
try {
100-
const collector = msg.channel.createMessageCollector(
101-
(m: Discord.Message) => m.author.id === client.user?.id,
102-
);
108+
const collector = msg.channel.createMessageCollector({
109+
filter: (m: Discord.Message) => m.author.id === client.user?.id,
110+
});
103111
await handleCommand(msg);
104112
const ids = collector.collected.map((m) => m.id);
105113
messageCollectorCache.set(msg.id, ids);
@@ -111,16 +119,15 @@ client.on('message', async (msg) => {
111119
console.error(err);
112120
void msg.reply('przepraszam, ale coś poszło nie tak…');
113121
}
114-
} finally {
115-
return msg.channel.stopTyping(true);
116122
}
117123
}
118124

119125
void updateMessagesCount(msg.member?.id, msg.member?.displayName).catch(console.error);
120126

121127
const maybeReflinks = messageToReflinks(msg.content);
122128
if (maybeReflinks.length > 0) {
123-
return msg.reply(maybeReflinks);
129+
await msg.reply(maybeReflinks.join('\n'));
130+
return;
124131
}
125132

126133
await thx(msg);
@@ -156,7 +163,7 @@ async function updateMessagesCount(
156163
}
157164

158165
function revertCommand(msg: Discord.Message) {
159-
if (!messageCollectorCache.has(msg.id) || msg.channel.type === 'dm') {
166+
if (!messageCollectorCache.has(msg.id) || msg.channel.type === Discord.ChannelType.DM) {
160167
return undefined;
161168
}
162169
// eslint-disable-next-line functional/prefer-readonly-type

src/commands/index.spec.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
import * as Discord from 'discord.js';
2-
import Sinon from 'sinon';
31
import { expect } from 'chai';
2+
import type * as Discord from 'discord.js';
3+
import Sinon from 'sinon';
44

55
import { getMessageMock } from '../../test/mocks';
6+
67
import { handleCommand } from '.';
78

89
describe('index', () => {
910
describe('handleCommand', () => {
1011
it('should show help message', async () => {
1112
const msg = getMessageMock('msg', { content: '!help' });
1213
const memberMock = {
13-
hasPermission: Sinon.spy(),
14+
permissions: {
15+
has: Sinon.spy(),
16+
},
1417
};
15-
msg.guild.member.returns(memberMock);
18+
msg.guild.members.cache.get.returns(memberMock);
1619
msg.author.send.resolves();
17-
await handleCommand((msg as unknown) as Discord.Message);
20+
await handleCommand(msg as unknown as Discord.Message);
1821
expect(msg.reply).to.have.been.calledOnceWith('Wysłałam Ci DM ze wszystkimi komendami! 🎉');
1922
});
2023
});

src/commands/index.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Discord from 'discord.js';
2-
import type { PermissionString } from 'discord.js';
2+
import type { PermissionsString } from 'discord.js';
33

44
import { getConfig } from '../config';
55
import type { Command } from '../types';
@@ -71,7 +71,7 @@ const allCommands = [
7171
];
7272

7373
const cooldowns = new Discord.Collection<string, Discord.Collection<string, number>>();
74-
const PERMISSION_TO_OVERRIDE_COOLDOWN: PermissionString = 'ADMINISTRATOR';
74+
const PERMISSION_TO_OVERRIDE_COOLDOWN: PermissionsString = 'Administrator';
7575

7676
function verifyCooldown(msg: Discord.Message, command: Command) {
7777
if (typeof command.cooldown !== 'number') {
@@ -92,8 +92,8 @@ function verifyCooldown(msg: Discord.Message, command: Command) {
9292
const expirationTime = timestamps.get(msg.author.id)! + cooldownAmount;
9393

9494
if (now < expirationTime) {
95-
const member = msg.guild.member(msg.author);
96-
if (member?.hasPermission(PERMISSION_TO_OVERRIDE_COOLDOWN)) {
95+
const member = msg.guild.members.cache.get(msg.author.id);
96+
if (member?.permissions.has(PERMISSION_TO_OVERRIDE_COOLDOWN)) {
9797
return;
9898
}
9999

@@ -114,7 +114,7 @@ function printHelp(msg: Discord.Message, member: Discord.GuildMember) {
114114
return a.name.localeCompare(b.name);
115115
})
116116
.filter((command) => {
117-
if (command.permissions && !member.hasPermission(command.permissions)) {
117+
if (command.permissions && !member.permissions.has(command.permissions)) {
118118
return false;
119119
}
120120
return true;
@@ -128,9 +128,9 @@ function printHelp(msg: Discord.Message, member: Discord.GuildMember) {
128128
];
129129

130130
return msg.author
131-
.send(data, { split: true })
131+
.send(data.join('\n'))
132132
.then(() => {
133-
if (msg.channel.type === 'dm') {
133+
if (msg.channel.type === Discord.ChannelType.DM) {
134134
return undefined;
135135
}
136136
return msg.reply('Wysłałam Ci DM ze wszystkimi komendami! 🎉');
@@ -155,7 +155,7 @@ export function handleCommand(msg: Discord.Message) {
155155
const [, maybeCommand, rest] = COMMAND_PATTERN.exec(msg.content) || [null, null, null];
156156

157157
if (maybeCommand === 'help') {
158-
const member = msg.guild.member(msg.author);
158+
const member = msg.guild.members.cache.get(msg.author.id);
159159
if (member) {
160160
return printHelp(msg, member);
161161
}
@@ -170,16 +170,16 @@ export function handleCommand(msg: Discord.Message) {
170170
return processCommand(msg, command, rest);
171171
}
172172

173-
function processCommand(msg: Discord.Message, command: Command, rest: string | null) {
174-
const member = msg.guild?.member(msg.author);
173+
async function processCommand(msg: Discord.Message, command: Command, rest: string | null) {
174+
const member = msg.guild?.members.cache.get(msg.author.id);
175175

176-
if (!member || (command.permissions && !member.hasPermission(command.permissions))) {
176+
if (!member || (command.permissions && !member.permissions.has(command.permissions))) {
177177
return undefined; // silence is golden
178178
}
179179

180-
void msg.channel.startTyping();
180+
await msg.channel.sendTyping();
181181

182-
if (command.guildOnly && msg.channel.type !== 'text') {
182+
if (command.guildOnly && msg.channel.type !== Discord.ChannelType.GuildText) {
183183
throw new InvalidUsageError(`to polecenie można wywołać tylko na kanałach.`);
184184
}
185185

src/commands/karma.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import Discord from 'discord.js';
21
import Bluebird from 'bluebird';
2+
import Discord from 'discord.js';
33

4+
import type { KarmaAgg } from '../data/karma';
45
import {
56
getKarmaForMember,
67
getKarmaForAllMembers,
7-
KarmaAgg,
88
getKarmaForMembers,
99
getKarmaDescription,
1010
} from '../data/karma';
1111
import { getKarmaCollection, initDb } from '../db';
1212
import type { Command } from '../types';
1313

1414
export const KARMA_REGEX = new RegExp(
15-
`^(${Discord.MessageMentions.USERS_PATTERN.source}).*\\+\\+\\s*`,
15+
`^(${Discord.MessageMentions.UsersPattern.source}).*\\+\\+\\s*`,
1616
);
1717

1818
const addKarma: Command = {

src/commands/m1.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
import { Command } from '../types';
1+
import type { Command } from '../types';
22

33
const m1: Command = {
44
name: 'm1',
55
description: 'Apple silicon m1',
66
args: 'prohibited',
77
cooldown: 10,
88
execute(msg) {
9-
return msg.channel.send([
10-
`👨‍💻 ***Czy Apple Silicon m1 jest gotowe dla developerów?*** 👩‍💻 \n`,
11-
`https://isapplesiliconready.com/for/developer`,
12-
`https://www.apple.com/mac/m1/`,
13-
]);
9+
return msg.channel.send(
10+
[
11+
`👨‍💻 ***Czy Apple Silicon m1 jest gotowe dla developerów?*** 👩‍💻 \n`,
12+
`https://isapplesiliconready.com/for/developer`,
13+
`https://www.apple.com/mac/m1/`,
14+
].join('\n'),
15+
);
1416
},
1517
};
1618

0 commit comments

Comments
 (0)