Skip to content

Commit 33cb9ac

Browse files
committed
feat: Add active role
1 parent 78d125b commit 33cb9ac

File tree

4 files changed

+157
-79
lines changed

4 files changed

+157
-79
lines changed

src/app.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import { createHttpServer } from './http-server';
1010
import { InvalidUsageError } from './types';
1111
import { getWeekNumber } from './utils';
1212
import { getStatsCollection, initDb } from './db';
13-
import { updateKarmaRoles } from './cron/roles';
1413
import { messageToReflinks } from './commands/reflink';
14+
import { updateKarmaRoles } from './cron/karma';
15+
import { updateStatsRoles } from './cron/stats';
1516

1617
const MESSAGE_COLLECTOR_CACHE_S = 60 * 60;
1718
const messageCollectorCache = new Cache({ stdTTL: MESSAGE_COLLECTOR_CACHE_S });
@@ -193,6 +194,17 @@ client.on('messageDelete', async (msg) => {
193194

194195
async function init() {
195196
await client.login(getConfig('DISCORD_BOT_TOKEN'));
197+
198+
// Auto assign roles
199+
{
200+
const TYPE_OF_WEB_GUILD_ID = '440163731704643589';
201+
const guild = await client.guilds.fetch(TYPE_OF_WEB_GUILD_ID);
202+
updateRoles(guild);
203+
setInterval(() => {
204+
updateRoles(guild);
205+
}, 1000 * 60 * 60 * 24 * 1);
206+
}
207+
196208
if (process.env.NODE_ENV === 'production') {
197209
const rssClient = new MonitoRSS.ClientManager(settings);
198210
await new Promise((resolve) => rssClient.start(() => resolve(undefined)));
@@ -204,17 +216,15 @@ init().catch((err) => errors.push(err));
204216

205217
const httpServer = createHttpServer(client, errors, warnings, debugs);
206218

207-
const updateRoles = () => {
208-
updateKarmaRoles()
219+
const updateRoles = (guild: Discord.Guild) => {
220+
updateKarmaRoles(guild)
221+
.then(() => console.log(`Successfully updated roles`))
222+
.catch((err) => errors.push(err));
223+
updateStatsRoles(guild)
209224
.then(() => console.log(`Successfully updated roles`))
210225
.catch((err) => errors.push(err));
211226
};
212227

213228
httpServer.listen(getConfig('PORT'), () => {
214229
console.log(`Server running!`);
215-
216-
updateRoles();
217-
setInterval(() => {
218-
updateRoles();
219-
}, 1000 * 60 * 60 * 24 * 1);
220230
});

src/cron/karma.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import Discord from 'discord.js';
2+
import { initDb, getKarmaCollection } from '../db';
3+
import { offsetDateByWeeks } from '../utils';
4+
import { fetchOrCreateRole, updateRoles } from './roles';
5+
6+
const TOP_KARMA_ROLE_NAME = 'POMOCNI';
7+
8+
interface MemberTotalKarma {
9+
readonly _id: string;
10+
readonly total: number;
11+
}
12+
13+
const createKarmaRole = (guild: Discord.Guild) => {
14+
return guild.roles.create({
15+
data: {
16+
name: TOP_KARMA_ROLE_NAME,
17+
color: 'DARK_VIVID_PINK',
18+
mentionable: false,
19+
hoist: true,
20+
},
21+
reason: 'Najbardziej pomocny/a',
22+
});
23+
};
24+
25+
const getBestKarmaMemberIds = async (
26+
fromDate = offsetDateByWeeks(new Date(), 2),
27+
toDate = new Date(),
28+
) => {
29+
const db = await initDb();
30+
const karmaCollection = getKarmaCollection(db);
31+
32+
const agg = await karmaCollection
33+
.aggregate<MemberTotalKarma>([
34+
{ $match: { createdAt: { $gte: fromDate, $lte: toDate } } },
35+
{ $group: { _id: '$to', total: { $sum: '$value' } } },
36+
{ $sort: { total: -1 } },
37+
{ $limit: 10 },
38+
])
39+
.toArray();
40+
41+
return agg;
42+
};
43+
44+
const getTopKarmaMembers = async (guild: Discord.Guild) => {
45+
const ids = await getBestKarmaMemberIds();
46+
47+
return Promise.all(ids.map(({ _id }) => guild.members.fetch(_id)));
48+
};
49+
50+
export const updateKarmaRoles = async (guild: Discord.Guild) => {
51+
const [karmaRole, bestKarmaMembers] = await Promise.all([
52+
fetchOrCreateRole(guild, TOP_KARMA_ROLE_NAME, createKarmaRole),
53+
getTopKarmaMembers(guild),
54+
]);
55+
56+
await updateRoles(karmaRole, bestKarmaMembers);
57+
};

src/cron/roles.ts

Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,18 @@
11
import Discord from 'discord.js';
22

3-
import { getConfig } from '../config';
4-
import { initDb, getKarmaCollection } from '../db';
5-
import { offsetDateByWeeks } from '../utils';
6-
7-
interface MemberTotalKarma {
8-
readonly _id: string;
9-
readonly total: number;
10-
}
11-
12-
const TYPE_OF_WEB_GUILD_ID = '440163731704643589';
13-
const ROLE_NAME = 'AKTYWNI';
14-
15-
const createKarmaRole = (guild: Discord.Guild) => {
16-
return guild.roles.create({
17-
data: {
18-
name: ROLE_NAME,
19-
color: 'DARK_VIVID_PINK',
20-
mentionable: false,
21-
hoist: true,
22-
},
23-
reason: 'Most active',
24-
});
25-
};
26-
27-
const fetchKarmaRole = async (guild: Discord.Guild) => {
3+
const fetchRole = async (guild: Discord.Guild, roleName: string) => {
284
const roles = await guild.roles.fetch(undefined, false);
29-
return roles.cache.find((role) => role.name === ROLE_NAME);
5+
return roles.cache.find((role) => role.name === roleName);
306
};
317

32-
const fetchOrCreateKarmaRole = async (guild: Discord.Guild) => {
33-
const role = await fetchKarmaRole(guild);
8+
export const fetchOrCreateRole = async (
9+
guild: Discord.Guild,
10+
roleName: string,
11+
createRole: (guild: Discord.Guild) => Promise<Discord.Role>,
12+
) => {
13+
const role = await fetchRole(guild, roleName);
3414
if (!role) {
35-
return createKarmaRole(guild);
15+
return createRole(guild);
3616
}
3717
return role;
3818
};
@@ -47,31 +27,6 @@ const removeRole = (member: Discord.GuildMember, role: Discord.Role) => {
4727
return member.roles.remove(role.id);
4828
};
4929

50-
const getBestKarmaMemberIds = async (
51-
fromDate = offsetDateByWeeks(new Date(), 2),
52-
toDate = new Date(),
53-
) => {
54-
const db = await initDb();
55-
const karmaCollection = getKarmaCollection(db);
56-
57-
const agg = await karmaCollection
58-
.aggregate<MemberTotalKarma>([
59-
{ $match: { createdAt: { $gte: fromDate, $lte: toDate } } },
60-
{ $group: { _id: '$to', total: { $sum: '$value' } } },
61-
{ $sort: { total: -1 } },
62-
{ $limit: 10 },
63-
])
64-
.toArray();
65-
66-
return agg;
67-
};
68-
69-
const getBestMembers = async (guild: Discord.Guild) => {
70-
const ids = await getBestKarmaMemberIds();
71-
72-
return Promise.all(ids.map(({ _id }) => guild.members.fetch(_id)));
73-
};
74-
7530
const assignMembersRoles = async (members: Discord.GuildMember[], role: Discord.Role) => {
7631
return Promise.all(members.map((member) => giveRole(member, role)));
7732
};
@@ -83,25 +38,16 @@ const removeMembersRoles = (
8338
return Promise.all(members.map((member) => removeRole(member, role)));
8439
};
8540

86-
export const updateKarmaRoles = async () => {
87-
const client = new Discord.Client();
88-
await client.login(getConfig('DISCORD_BOT_TOKEN'));
89-
90-
const guild = await client.guilds.fetch(TYPE_OF_WEB_GUILD_ID);
91-
const [karmaRole, bestKarmaMembers] = await Promise.all([
92-
fetchOrCreateKarmaRole(guild),
93-
getBestMembers(guild),
94-
]);
95-
96-
const currentKarmaMembers = karmaRole.members;
41+
export const updateRoles = async (role: Discord.Role, futureRoleMembers: Discord.GuildMember[]) => {
42+
const currentRoleMembers = role.members;
9743

98-
const membersToRemove = currentKarmaMembers.filter(
99-
(m) => !bestKarmaMembers.find((bm) => bm.id === m.id),
44+
const membersToRemove = currentRoleMembers.filter(
45+
(m) => !futureRoleMembers.find((bm) => bm.id === m.id),
10046
);
101-
const membersToAdd = bestKarmaMembers.filter(
102-
(bm) => !currentKarmaMembers.find((m) => m.id === bm.id),
47+
const membersToAdd = futureRoleMembers.filter(
48+
(bm) => !currentRoleMembers.find((m) => m.id === bm.id),
10349
);
10450

105-
await removeMembersRoles(membersToRemove, karmaRole);
106-
await assignMembersRoles(membersToAdd, karmaRole);
51+
await removeMembersRoles(membersToRemove, role);
52+
await assignMembersRoles(membersToAdd, role);
10753
};

src/cron/stats.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Discord from 'discord.js';
2+
import { initDb, getStatsCollection } from '../db';
3+
import { offsetDateByWeeks } from '../utils';
4+
import { fetchOrCreateRole, updateRoles } from './roles';
5+
6+
const TOP_STATS_ROLE_NAME = 'AKTYWNI';
7+
8+
const createStatsRole = (guild: Discord.Guild) => {
9+
return guild.roles.create({
10+
data: {
11+
name: TOP_STATS_ROLE_NAME,
12+
color: 'BLUE',
13+
mentionable: false,
14+
hoist: true,
15+
},
16+
reason: 'Najbardziej aktywna/y',
17+
});
18+
};
19+
20+
interface MemberTotalStats {
21+
readonly _id: string;
22+
readonly messagesCount: number;
23+
readonly memberName: string;
24+
}
25+
26+
const getBestStatsMemberIds = async (
27+
fromDate = offsetDateByWeeks(new Date(), 2),
28+
toDate = new Date(),
29+
) => {
30+
const db = await initDb();
31+
const statsCollection = getStatsCollection(db);
32+
33+
const agg = await statsCollection
34+
.aggregate<MemberTotalStats>([
35+
{ $match: { updatedAt: { $gte: fromDate, $lte: toDate } } },
36+
{
37+
$group: {
38+
_id: '$memberId',
39+
messagesCount: { $sum: '$messagesCount' },
40+
memberName: { $push: '$memberName' },
41+
},
42+
},
43+
{ $sort: { messagesCount: -1 } },
44+
{ $limit: 10 },
45+
{ $addFields: { memberName: { $arrayElemAt: [{ $reverseArray: '$memberName' }, 0] } } },
46+
])
47+
.toArray();
48+
49+
return agg;
50+
};
51+
52+
const getTopStatsMembers = async (guild: Discord.Guild) => {
53+
const ids = await getBestStatsMemberIds();
54+
55+
return Promise.all(ids.map(({ _id }) => guild.members.fetch(_id)));
56+
};
57+
58+
export const updateStatsRoles = async (guild: Discord.Guild) => {
59+
const [statsRole, bestStatsMembers] = await Promise.all([
60+
fetchOrCreateRole(guild, TOP_STATS_ROLE_NAME, createStatsRole),
61+
getTopStatsMembers(guild),
62+
]);
63+
64+
await updateRoles(statsRole, bestStatsMembers);
65+
};

0 commit comments

Comments
 (0)