Skip to content

[DISC-121] Implement Logging for User Rejoining #199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 7 additions & 78 deletions commands/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,7 @@ const { SlashCommandBuilder } = require("@discordjs/builders");
const { Permissions } = require("discord.js");

const COMMAND_KICKUNVERIFIED = "kickunverified";
const COMMAND_MIGRATE = "migratecourses";
const COMMAND_REMOVECOURSEROLES = "nukeremovecourseroles";

// yeah i know this code is copy pasted from the other file
// but whatever, the migration command is temporary!
const is_valid_course = (course) => {
const reg_comp_course = /^comp\d{4}$/;
const reg_math_course = /^math\d{4}$/;
const reg_binf_course = /^binf\d{4}$/;
const reg_engg_course = /^engg\d{4}$/;
const reg_seng_course = /^seng\d{4}$/;
const reg_desn_course = /^desn\d{4}$/;

return (
reg_comp_course.test(course.toLowerCase()) ||
reg_math_course.test(course.toLowerCase()) ||
reg_binf_course.test(course.toLowerCase()) ||
reg_engg_course.test(course.toLowerCase()) ||
reg_seng_course.test(course.toLowerCase()) ||
reg_desn_course.test(course.toLowerCase())
);
};
const COMMAND_DROPUSERTABLE = "dropusertable";

module.exports = {
data: new SlashCommandBuilder()
Expand All @@ -36,19 +15,8 @@ module.exports = {
)
.addSubcommand((subcommand) =>
subcommand
.setName(COMMAND_MIGRATE)
.setDescription("Migrates a course role to permission overwrites.")
.addStringOption((option) =>
option
.setName("course")
.setDescription("Course role to remove")
.setRequired(true),
),
)
.addSubcommand((subcommand) =>
subcommand
.setName(COMMAND_REMOVECOURSEROLES)
.setDescription("WARNING: Removes course roles from the server."),
.setName(COMMAND_DROPUSERTABLE)
.setDescription("Deletes the user table and reliant tables."),
),
async execute(interaction) {
try {
Expand Down Expand Up @@ -93,50 +61,11 @@ module.exports = {
});
});
return await interaction.reply("Removed unverified members.");
} else if (interaction.options.getSubcommand() === COMMAND_MIGRATE) {
const course = interaction.options.getString("course");
if (!is_valid_course(course)) {
return await interaction.reply("Error: invalid course.");
}

const role = await interaction.guild.roles.cache.find(
(course_role) => course_role.name.toLowerCase() === course.toLowerCase(),
);

if (role === undefined) {
return await interaction.reply("Error: no role exists for course " + course);
}

const channel = await interaction.guild.channels.cache.find(
(role_channel) => role_channel.name.toLowerCase() === role.name.toLowerCase(),
);

if (channel === undefined) {
return await interaction.reply("Error: no channel exists for course " + course);
}

await interaction.deferReply();
for (const member of role.members.values()) {
await channel.permissionOverwrites.create(member, {
VIEW_CHANNEL: true,
});
}
return await interaction.editReply(
"Migrated course role to permission overwrites.",
);
} else if (interaction.options.getSubcommand() === COMMAND_REMOVECOURSEROLES) {
// get all roles, and find courses which match the regex
const course_roles = await interaction.guild.roles.cache.filter((role) =>
is_valid_course(role.name),
);

await interaction.deferReply();

for (const role of course_roles.values()) {
await role.delete();
}
} else if (interaction.options.getSubcommand() === COMMAND_DROPUSERTABLE) {
const userDB = global.userDB;
await userDB.drop_table();

return await interaction.editReply("Removed all course roles.");
return await interaction.editReply("Deleted user table.");
}

return await interaction.reply("Error: unknown subcommand.");
Expand Down
34 changes: 34 additions & 0 deletions events/guildMemberAdd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { Events } = require("discord.js");

const CSESOC_SERVER_ID = "693779865916276746";
const REPORT_CHANNEL_ID = "1270283342176059443";

module.exports = {
name: Events.GuildMemberAdd,
once: false,
execute(member) {
/** @type {DBuser} */
const userDB = global.userDB;

// Get report channel
if (member.user.bot || member.user.system || member.guild.id !== CSESOC_SERVER_ID) return;

// Get old user info before joining
userDB.get_user_info(member.id).then((user_data) => {
userDB.user_join(member.id).then((joinType) => {
if (joinType === "rejoin") {
// Fetch the channel to output details
const reportChannel = member.guild.channels.cache.get(REPORT_CHANNEL_ID);

// Fetch formatted date values from joining and leaving events
const joinDate = user_data.joinDate.toLocaleDateString("en-AU");
const leaveDate = user_data.leaveDate.toLocaleDateString("en-AU");

reportChannel.send(
`${member.user} (${member.user.tag}) has rejoined the server. [Last in server: ${leaveDate}, Last joined: ${joinDate}]`,
);
}
});
});
},
};
15 changes: 15 additions & 0 deletions events/guildMemberRemove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { Events } = require("discord.js");

module.exports = {
name: Events.GuildMemberRemove,
once: false,
execute(member) {
/** @type {DBuser} */
const userDB = global.userDB;

// Get report channel
if (member.user.bot || member.user.system) return;

userDB.user_leave(member.id);
},
};
57 changes: 55 additions & 2 deletions lib/database/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class DBuser {
console.log("Running creating user table");
await client.query("BEGIN");
const query = `CREATE TABLE users (
userid INTEGER PRIMARY KEY,
userid TEXT PRIMARY KEY,
joindate DATE NOT NULL,
leavedate DATE,
userleft BOOLEAN
Expand Down Expand Up @@ -196,7 +196,7 @@ class DBuser {
try {
await client.query("BEGIN");
const values = [time, true, userid];
const query = "UPDATE users SET leavedate = $1 , userleft = $2 where userid = $3";
const query = "UPDATE users SET leavedate = $1 , userleft = $2 where userid = $3";
await client.query(query, values);

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

let type = "new";

const client = await this.pool.connect();
try {
await client.query("BEGIN");
Expand All @@ -227,6 +229,9 @@ class DBuser {
query = "UPDATE users SET joindate=$1, userleft=$2 where userid=$3";
values = [time, false, userid];
await client.query(query, values);

// Report rejoining user to channel
type = "rejoin";
} else {
query =
"INSERT INTO users (USERID, JOINDATE, LEAVEDATE, USERLEFT) VALUES ($1,$2,$3,$4)";
Expand All @@ -241,6 +246,40 @@ class DBuser {
client.release();
// console.log("Client released successfully.")
}

return type;
}

async get_user_info(userid) {
const client = await this.pool.connect();
let info = null;

try {
await client.query("BEGIN");

const query = "select * from users where userid = $1";
const values = [userid];
const result = await client.query(query, values);

if (result.rows.length != 0) {
const row = result.rows[0];

info = {
userId: row["userid"],
joinDate: row["joindate"],
leaveDate: row["leavedate"],
userLeft: row["userleft"],
};
}
} catch (ex) {
console.log(`An unexpected error occurred: ${ex}`);
} finally {
await client.query("ROLLBACK");
client.release();
// console.log("Client released successfully.")
}

return info;
}

// Adding a user role
Expand Down Expand Up @@ -477,6 +516,20 @@ class DBuser {
client.release();
}
}

async deleteUsers() {
// Temporary - delete after use
const client = await this.pool.connect();
try {
// Query to delete users who have left the server
const query = `DROP TABLE users CASCADE;`;
await client.query(query);
} catch (error) {
console.error(error);
} finally {
client.release();
}
}
}

module.exports = {
Expand Down
Loading