Skip to content

Commit 8ed55ab

Browse files
authored
[DISC-121] Implement Logging for User Rejoining (#199)
* Implementation of user join and leave logging and admin command to facilitate replacing old db table * Complete implementation of rejoin notices
1 parent eecb1b5 commit 8ed55ab

File tree

4 files changed

+111
-80
lines changed

4 files changed

+111
-80
lines changed

commands/admin.js

Lines changed: 7 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,7 @@ const { SlashCommandBuilder } = require("@discordjs/builders");
22
const { Permissions } = require("discord.js");
33

44
const COMMAND_KICKUNVERIFIED = "kickunverified";
5-
const COMMAND_MIGRATE = "migratecourses";
6-
const COMMAND_REMOVECOURSEROLES = "nukeremovecourseroles";
7-
8-
// yeah i know this code is copy pasted from the other file
9-
// but whatever, the migration command is temporary!
10-
const is_valid_course = (course) => {
11-
const reg_comp_course = /^comp\d{4}$/;
12-
const reg_math_course = /^math\d{4}$/;
13-
const reg_binf_course = /^binf\d{4}$/;
14-
const reg_engg_course = /^engg\d{4}$/;
15-
const reg_seng_course = /^seng\d{4}$/;
16-
const reg_desn_course = /^desn\d{4}$/;
17-
18-
return (
19-
reg_comp_course.test(course.toLowerCase()) ||
20-
reg_math_course.test(course.toLowerCase()) ||
21-
reg_binf_course.test(course.toLowerCase()) ||
22-
reg_engg_course.test(course.toLowerCase()) ||
23-
reg_seng_course.test(course.toLowerCase()) ||
24-
reg_desn_course.test(course.toLowerCase())
25-
);
26-
};
5+
const COMMAND_DROPUSERTABLE = "dropusertable";
276

287
module.exports = {
298
data: new SlashCommandBuilder()
@@ -36,19 +15,8 @@ module.exports = {
3615
)
3716
.addSubcommand((subcommand) =>
3817
subcommand
39-
.setName(COMMAND_MIGRATE)
40-
.setDescription("Migrates a course role to permission overwrites.")
41-
.addStringOption((option) =>
42-
option
43-
.setName("course")
44-
.setDescription("Course role to remove")
45-
.setRequired(true),
46-
),
47-
)
48-
.addSubcommand((subcommand) =>
49-
subcommand
50-
.setName(COMMAND_REMOVECOURSEROLES)
51-
.setDescription("WARNING: Removes course roles from the server."),
18+
.setName(COMMAND_DROPUSERTABLE)
19+
.setDescription("Deletes the user table and reliant tables."),
5220
),
5321
async execute(interaction) {
5422
try {
@@ -93,50 +61,11 @@ module.exports = {
9361
});
9462
});
9563
return await interaction.reply("Removed unverified members.");
96-
} else if (interaction.options.getSubcommand() === COMMAND_MIGRATE) {
97-
const course = interaction.options.getString("course");
98-
if (!is_valid_course(course)) {
99-
return await interaction.reply("Error: invalid course.");
100-
}
101-
102-
const role = await interaction.guild.roles.cache.find(
103-
(course_role) => course_role.name.toLowerCase() === course.toLowerCase(),
104-
);
105-
106-
if (role === undefined) {
107-
return await interaction.reply("Error: no role exists for course " + course);
108-
}
109-
110-
const channel = await interaction.guild.channels.cache.find(
111-
(role_channel) => role_channel.name.toLowerCase() === role.name.toLowerCase(),
112-
);
113-
114-
if (channel === undefined) {
115-
return await interaction.reply("Error: no channel exists for course " + course);
116-
}
117-
118-
await interaction.deferReply();
119-
for (const member of role.members.values()) {
120-
await channel.permissionOverwrites.create(member, {
121-
VIEW_CHANNEL: true,
122-
});
123-
}
124-
return await interaction.editReply(
125-
"Migrated course role to permission overwrites.",
126-
);
127-
} else if (interaction.options.getSubcommand() === COMMAND_REMOVECOURSEROLES) {
128-
// get all roles, and find courses which match the regex
129-
const course_roles = await interaction.guild.roles.cache.filter((role) =>
130-
is_valid_course(role.name),
131-
);
132-
133-
await interaction.deferReply();
134-
135-
for (const role of course_roles.values()) {
136-
await role.delete();
137-
}
64+
} else if (interaction.options.getSubcommand() === COMMAND_DROPUSERTABLE) {
65+
const userDB = global.userDB;
66+
await userDB.drop_table();
13867

139-
return await interaction.editReply("Removed all course roles.");
68+
return await interaction.editReply("Deleted user table.");
14069
}
14170

14271
return await interaction.reply("Error: unknown subcommand.");

events/guildMemberAdd.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { Events } = require("discord.js");
2+
3+
const CSESOC_SERVER_ID = "693779865916276746";
4+
const REPORT_CHANNEL_ID = "1270283342176059443";
5+
6+
module.exports = {
7+
name: Events.GuildMemberAdd,
8+
once: false,
9+
execute(member) {
10+
/** @type {DBuser} */
11+
const userDB = global.userDB;
12+
13+
// Get report channel
14+
if (member.user.bot || member.user.system || member.guild.id !== CSESOC_SERVER_ID) return;
15+
16+
// Get old user info before joining
17+
userDB.get_user_info(member.id).then((user_data) => {
18+
userDB.user_join(member.id).then((joinType) => {
19+
if (joinType === "rejoin") {
20+
// Fetch the channel to output details
21+
const reportChannel = member.guild.channels.cache.get(REPORT_CHANNEL_ID);
22+
23+
// Fetch formatted date values from joining and leaving events
24+
const joinDate = user_data.joinDate.toLocaleDateString("en-AU");
25+
const leaveDate = user_data.leaveDate.toLocaleDateString("en-AU");
26+
27+
reportChannel.send(
28+
`${member.user} (${member.user.tag}) has rejoined the server. [Last in server: ${leaveDate}, Last joined: ${joinDate}]`,
29+
);
30+
}
31+
});
32+
});
33+
},
34+
};

events/guildMemberRemove.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const { Events } = require("discord.js");
2+
3+
module.exports = {
4+
name: Events.GuildMemberRemove,
5+
once: false,
6+
execute(member) {
7+
/** @type {DBuser} */
8+
const userDB = global.userDB;
9+
10+
// Get report channel
11+
if (member.user.bot || member.user.system) return;
12+
13+
userDB.user_leave(member.id);
14+
},
15+
};

lib/database/database.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class DBuser {
9393
console.log("Running creating user table");
9494
await client.query("BEGIN");
9595
const query = `CREATE TABLE users (
96-
userid INTEGER PRIMARY KEY,
96+
userid TEXT PRIMARY KEY,
9797
joindate DATE NOT NULL,
9898
leavedate DATE,
9999
userleft BOOLEAN
@@ -196,7 +196,7 @@ class DBuser {
196196
try {
197197
await client.query("BEGIN");
198198
const values = [time, true, userid];
199-
const query = "UPDATE users SET leavedate = $1 , userleft = $2 where userid = $3";
199+
const query = "UPDATE users SET leavedate = $1 , userleft = $2 where userid = $3";
200200
await client.query(query, values);
201201

202202
await client.query("COMMIT");
@@ -215,6 +215,8 @@ class DBuser {
215215
time.setMilliseconds(0);
216216
time = time.toISOString();
217217

218+
let type = "new";
219+
218220
const client = await this.pool.connect();
219221
try {
220222
await client.query("BEGIN");
@@ -227,6 +229,9 @@ class DBuser {
227229
query = "UPDATE users SET joindate=$1, userleft=$2 where userid=$3";
228230
values = [time, false, userid];
229231
await client.query(query, values);
232+
233+
// Report rejoining user to channel
234+
type = "rejoin";
230235
} else {
231236
query =
232237
"INSERT INTO users (USERID, JOINDATE, LEAVEDATE, USERLEFT) VALUES ($1,$2,$3,$4)";
@@ -241,6 +246,40 @@ class DBuser {
241246
client.release();
242247
// console.log("Client released successfully.")
243248
}
249+
250+
return type;
251+
}
252+
253+
async get_user_info(userid) {
254+
const client = await this.pool.connect();
255+
let info = null;
256+
257+
try {
258+
await client.query("BEGIN");
259+
260+
const query = "select * from users where userid = $1";
261+
const values = [userid];
262+
const result = await client.query(query, values);
263+
264+
if (result.rows.length != 0) {
265+
const row = result.rows[0];
266+
267+
info = {
268+
userId: row["userid"],
269+
joinDate: row["joindate"],
270+
leaveDate: row["leavedate"],
271+
userLeft: row["userleft"],
272+
};
273+
}
274+
} catch (ex) {
275+
console.log(`An unexpected error occurred: ${ex}`);
276+
} finally {
277+
await client.query("ROLLBACK");
278+
client.release();
279+
// console.log("Client released successfully.")
280+
}
281+
282+
return info;
244283
}
245284

246285
// Adding a user role
@@ -477,6 +516,20 @@ class DBuser {
477516
client.release();
478517
}
479518
}
519+
520+
async deleteUsers() {
521+
// Temporary - delete after use
522+
const client = await this.pool.connect();
523+
try {
524+
// Query to delete users who have left the server
525+
const query = `DROP TABLE users CASCADE;`;
526+
await client.query(query);
527+
} catch (error) {
528+
console.error(error);
529+
} finally {
530+
client.release();
531+
}
532+
}
480533
}
481534

482535
module.exports = {

0 commit comments

Comments
 (0)