Skip to content

Commit

Permalink
Merge pull request #275 from nwplus/hc2023-updates
Browse files Browse the repository at this point in the history
Hc2023 updates
  • Loading branch information
DonaldKLee authored Oct 29, 2024
2 parents a2d1ae8 + bcb310b commit e748e8f
Show file tree
Hide file tree
Showing 55 changed files with 3,743 additions and 2,815 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.env
node_modules/
logs/
.idea/
.idea/
registrations.csv
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript"],

"cSpell.words": [
Expand Down
170 changes: 99 additions & 71 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
require('dotenv-flow').config();
const mongoUtil = require('./db/mongo/mongoUtil');
const firebaseUtil = require('./db/firebase/firebaseUtil');
// const Commando = require('discord.js-commando');
const Discord = require('discord.js');
const firebaseServices = require('./db/firebase/firebase-services');
const winston = require('winston');
const fs = require('fs');
const discordServices = require('./discord-services');
const BotGuild = require('./db/mongo/BotGuild');
const BotGuildModel = require('./classes/Bot/bot-guild');
const Verification = require('./classes/Bot/Features/Verification/verification');
const { StringPrompt } = require('advanced-discord.js-prompts');
const Sentry = require('@sentry/node');
const Tracing = require('@sentry/tracing');
const { LogLevel, SapphireClient } = require('@sapphire/framework')
const { LogLevel, SapphireClient } = require('@sapphire/framework');
const Pronouns = require('./commands/a_utility/pronouns');
const RoleSelector = require('./commands/a_utility/role-selector');
const StartReport = require('./commands/hacker_utility/start-report');

/**
* The Main App module houses the bot events, process events, and initializes
Expand All @@ -26,32 +27,27 @@ const { LogLevel, SapphireClient } = require('@sapphire/framework')
* Read command line args to know if prod, dev, or test and what server
* First arg is one of prod, dev or test
* the second is the test server, but the first one must be test
* @param {string[]} args
* @returns {Map} config settings
*/
function getConfig(args) {
if (args.length >= 1) {
if (args[0] === 'dev') {
// Default dev
return JSON.parse(process.env.DEV);
} else if (args[0] === 'prod') {
// Production
if (args[1] === 'yes') {
return JSON.parse(process.env.PROD);
}
} else if (args[0] === 'test') {
// Test
const testConfig = JSON.parse(process.env.TEST);
let server = args[1] ?? 0;
if (server === '1') {
return testConfig['ONE'];
} else if (server === '2') {
return testConfig['TWO'];
} else if (server === '3') {
return testConfig['THREE'];
} else if (server === '4') {
return testConfig['FOUR'];
}
function getConfig() {
if (process.env.NODE_ENV === 'DEV') {
// Default dev
return JSON.parse(process.env.DEV);
} else if (process.env.NODE_ENV === 'PROD') {
// Production
return JSON.parse(process.env.PROD);
} else if (process.env.NODE_ENV === 'TEST') {
// Test
const testConfig = JSON.parse(process.env.TEST);
let server = process.env.SERVER;
if (server === '1') {
return testConfig['ONE'];
} else if (server === '2') {
return testConfig['TWO'];
} else if (server === '3') {
return testConfig['THREE'];
} else if (server === '4') {
return testConfig['FOUR'];
}
}

Expand All @@ -60,7 +56,7 @@ function getConfig(args) {
process.exit(0);
}

const config = getConfig(process.argv.slice(2));
const config = getConfig();

const isLogToConsole = config['consoleLog'];

Expand All @@ -77,22 +73,22 @@ if (config['sentryLog']) {

const bot = new SapphireClient({
defaultPrefix: '!',
caseInsensitiveCommands: true,
logger: {
level: LogLevel.Debug
},
shards: 'auto',
intents: [
'GUILDS',
'GUILD_MEMBERS',
'GUILD_BANS',
'GUILD_EMOJIS_AND_STICKERS',
'GUILD_VOICE_STATES',
'GUILD_MESSAGES',
'GUILD_MESSAGE_REACTIONS',
'DIRECT_MESSAGES',
'DIRECT_MESSAGE_REACTIONS'
],
caseInsensitiveCommands: true,
logger: {
level: LogLevel.Debug
},
shards: 'auto',
intents: [
'GUILDS',
'GUILD_MEMBERS',
'GUILD_BANS',
'GUILD_EMOJIS_AND_STICKERS',
'GUILD_VOICE_STATES',
'GUILD_MESSAGES',
'GUILD_MESSAGE_REACTIONS',
'DIRECT_MESSAGES',
'DIRECT_MESSAGE_REACTIONS'
],
});

const customLoggerLevels = {
Expand Down Expand Up @@ -155,42 +151,80 @@ bot.once('ready', async () => {

// initialize firebase
const adminSDK = JSON.parse(process.env.NWPLUSADMINSDK);
firebaseServices.initializeFirebaseAdmin('nwPlusBotAdmin', adminSDK, 'https://nwplus-bot.firebaseio.com');
mainLogger.warning('Connected to firebase admin sdk successfully!', { event: 'Ready Event' });

// set mongoose connection
await mongoUtil.mongooseConnect();
mainLogger.warning('Connected to mongoose successfully!', { event: 'Ready Event' });
firebaseUtil.initializeFirebaseAdmin('Factotum', adminSDK, process.env.FIREBASE_URL);
mainLogger.warning('Connected to nwFirebase successfully!', { event: 'Ready Event' });
firebaseUtil.connect('Factotum');

// make sure all guilds have a botGuild, this is in case the bot goes offline and its added
// to a guild. If botGuild is found, make sure only the correct commands are enabled.
bot.guilds.cache.forEach(async (guild, key, guilds) => {
const guildsArr = Array.from(bot.guilds.cache);
for (const [_, guild] of guildsArr) {
// create the logger for the guild
createALogger(guild.id, guild.name, false, isLogToConsole);

let botGuild = await BotGuild.findById(guild.id);
let botGuild = await firebaseUtil.getInitBotInfo(guild.id);
if (!botGuild) {
newGuild(guild);
await newGuild(guild);
mainLogger.verbose(`Created a new botGuild for the guild ${guild.id} - ${guild.name} on bot ready.`, { event: 'Ready Event' });
} else {
// set all non guarded commands to not enabled for the guild
// bot.registry.groups.forEach((group, key, map) => {
// if (!group.guarded) guild.setGroupEnabled(group, false);
// });

await botGuild.setCommandStatus(bot);
// await botGuild.setCommandStatus(bot);

guild.commandPrefix = botGuild.prefix;

mainLogger.verbose(`Found a botGuild for ${guild.id} - ${guild.name} on bot ready.`, { event: 'Ready Event' });

if (botGuild.isSetUpComplete) {
mainLogger.verbose('Trying to restore existing pronoun command message');
/** @type {Pronouns} */
const pronounsCommand = bot.stores.get('commands').get('pronouns');
const pronounsError = await pronounsCommand.tryRestoreReactionListeners(guild);
if (pronounsError) {
mainLogger.warning(pronounsError);
} else {
mainLogger.verbose('Restored pronoun command message');
}

/** @type {StartMentorCave} */
const mentorCaveCommand = bot.stores.get('commands').get('start-mentor-cave');
const mentorCaveError = await mentorCaveCommand.tryRestoreReactionListeners(guild);
if (mentorCaveError) {
mainLogger.warning(mentorCaveError);
} else {
mainLogger.verbose('Restored mentor cave command message');
}

/** @type {RoleSelector} */
const roleSelectorCommand = bot.stores.get('commands').get('role-selector');
const roleSelectorError = await roleSelectorCommand.tryRestoreReactionListeners(guild);
if (mentorCaveError) {
mainLogger.warning(roleSelectorError);
} else {
mainLogger.verbose('Restored role selector command message');
}

/** @type {StartReport} */
const startReportCommand = bot.stores.get('commands').get('start-report');
const startReportError = await startReportCommand.tryRestoreReactionListeners(guild);
if (startReportError) {
mainLogger.warning(roleSelectorError);
} else {
mainLogger.verbose('Restored role selector command message');
}
}

guild.commandPrefix = botGuild.prefix;
}
});
}
});

/**
* Runs when the bot is added to a guild.
*/
bot.on('guildCreate', /** @param {sapphireClient.Guild} guild */(guild) => {
bot.on('guildCreate', /** @param {Discord.Guild} guild */(guild) => {
mainLogger.warning(`The bot was added to a new guild: ${guild.id} - ${guild.name}.`, { event: 'Guild Create Event' });

newGuild(guild);
Expand All @@ -202,29 +236,23 @@ bot.on('guildCreate', /** @param {sapphireClient.Guild} guild */(guild) => {

/**
* Will set up a new guild.
* @param {sapphireClient.Guild} guild
* @param {Discord.Guild} guild
* @private
*/
function newGuild(guild) {
async function newGuild(guild) {
// set all non guarded commands to not enabled for the new guild
// bot.registry.groups.forEach((group, key, map) => {
// if (!group.guarded) guild.setGroupEnabled(group, false);
// });
// create a botGuild object for this new guild.
BotGuild.create({
_id: guild.id,
});
await firebaseUtil.createInitBotInfoDoc(guild.id);
}

/**
* Runs when the bot is removed from a server.
*/
bot.on('guildDelete', async (guild) => {
mainLogger.warning(`The bot was removed from the guild: ${guild.id} - ${guild.name}`);

let botGuild = await BotGuild.findById(guild.id);
botGuild.remove();
mainLogger.verbose(`BotGuild with id: ${guild.id} has been removed!`);
});

/**
Expand Down Expand Up @@ -264,7 +292,7 @@ bot.on('commandError', (command, error, message) => {
* Runs when a new member joins a guild the bot is running in.
*/
bot.on('guildMemberAdd', async member => {
let botGuild = await BotGuild.findById(member.guild.id);
let botGuild = await firebaseUtil.getInitBotInfo(member.guild.id);
member.roles.add(botGuild.verification.guestRoleID);

// if the guild where the user joined is complete then greet and verify.
Expand Down Expand Up @@ -433,18 +461,18 @@ async function greetNewMember(member, botGuild) {

try {
await Verification.verify(member, email, member.guild, botGuild);
if (!askedAboutCodex && await firebaseServices.checkCodexActive(member.guild.id)
if (!askedAboutCodex && await firebaseUtil.checkCodexActive(member.guild.id)
&& discordServices.checkForRole(member, botGuild.verification.verificationRoles.get('hacker'))) {
try {
discordServices.askBoolQuestion(member,botGuild, 'One more thing!',
'Would you like to receive free [Codex beta](https://openai.com/blog/openai-codex/) access, courtesy of our sponsor OpenAI (first come first served, while supplies last)?\n\n' +
'Would you like to receive free [Codex beta](https://openai.com/blog/openai-codex/) access, courtesy of our sponsor OpenAI (first come first served, while supplies last)?\n\n' +

'Open AI is giving out prizes to the best 2 projects using Codex or GPT-3:\n' +
'- 1st place: $120 worth of credits(2 million words in GPT-3 DaVinci)\n' +
'- 2nd place: $60 worth of credits (1 million words in GPT-3 DaVinci)\n\n' +

'If you would like a Codex code, please react with a 👍',
'Thanks for indicating your interest, you have been added to the list! If you are selected to receive an API key, you will get an email.', email);
'Thanks for indicating your interest, you have been added to the list! If you are selected to receive an API key, you will get an email.', email);
askedAboutCodex = true;
} catch (error) {
discordServices.sendEmbedToMember(member, {
Expand Down
35 changes: 17 additions & 18 deletions classes/Bot/Features/Stamps/stamps-manager.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const { Collection, MessageEmbed, GuildMember } = require('discord.js');
const winston = require('winston');
const { addRoleToMember, sendEmbedToMember, replaceRoleToMember, sendMessageToMember } = require('../../../../discord-services');
const BotGuildModel = require('../../bot-guild');
const Activity = require('../../activities/activity');

/**
Expand All @@ -13,18 +12,18 @@ class StampsManager {
* Will let hackers get a stamp for attending the activity.
* @param {Activity} activity - activity to use
* @param {Number} [time] - time to wait till collector closes, in seconds
* @param {BotGuildModel} botGuild
* @param {FirebaseFirestore.DocumentData | null | undefined} initBotInfo
* @async
*/
static async distributeStamp(activity, botGuild, time = 60) {
static async distributeStamp(activity, initBotInfo, time = 60) {

winston.loggers.get(activity.guild.id).event(`Activity named ${activity.name} is distributing stamps.`, {event: 'Activity Manager'});

// The users already seen by this stamp distribution.
let seenUsers = new Collection();

const promptEmbed = new MessageEmbed()
.setColor(botGuild.colors.embedColor)
.setColor(initBotInfo.colors.embedColor)
.setTitle('React within ' + time + ' seconds of the posting of this message to get a stamp for ' + activity.name + '!');

let promptMsg = await activity.generalText.send(promptEmbed);
Expand All @@ -38,7 +37,7 @@ class StampsManager {
const member = activity.generalText.guild.member(user);

if (!seenUsers.has(user.id)) {
this.parseRole(member, activity.name, botGuild);
this.parseRole(member, activity.name, initBotInfo);
seenUsers.set(user.id, user.username);
}
});
Expand All @@ -57,41 +56,41 @@ class StampsManager {
* Upgrade the stamp role of a member.
* @param {GuildMember} member - the member to add the new role to
* @param {String} activityName - the name of the activity
* @param {BotGuildModel} botGuild
* @param {FirebaseFirestore.DocumentData | null | undefined} initBotInfo
* @throws Error if the botGuild has stamps disabled
*/
static parseRole(member, activityName, botGuild) {
if (!botGuild.stamps.isEnabled) {
winston.loggers.get(botGuild._id).error(`Stamp system is turned off for guild ${botGuild._id} but I was asked to parse a role for member ${member.id} for activity ${activityName}.`, { event: 'Activity Manager' });
throw Error(`Stamp system is turned of for guild ${botGuild._id} but I was asked to parse a role for member ${member.id} for activity ${activityName}.`);
static parseRole(member, activityName, initBotInfo) {
if (!initBotInfo.stamps.isEnabled) {
winston.loggers.get(initBotInfo.id).error(`Stamp system is turned off for guild ${initBotInfo.id} but I was asked to parse a role for member ${member.id} for activity ${activityName}.`, { event: 'Activity Manager' });
throw Error(`Stamp system is turned of for guild ${initBotInfo.id} but I was asked to parse a role for member ${member.id} for activity ${activityName}.`);
}

let role = member.roles.cache.find(role => botGuild.stamps.stampRoleIDs.has(role.id));
let role = member.roles.cache.find(role => initBotInfo.stamps.stampRoleIDs.has(role.id));

if (role === undefined) {
addRoleToMember(member, botGuild.stamps.stamp0thRoleId);
addRoleToMember(member, initBotInfo.stamps.stamp0thRoleId);
sendEmbedToMember(member, 'I did not find an existing stamp role for you so I gave you one for attending '
+ activityName + '. Please contact an admin if there was a problem.', true);
winston.loggers.get(botGuild._id).userStats(`Activity named ${activityName} tried to give a stamp to the user with id ${member.id} but he has no stamp, I gave them the first stamp!`, {event: 'Activity Manager'});
winston.loggers.get(initBotInfo.id).userStats(`Activity named ${activityName} tried to give a stamp to the user with id ${member.id} but he has no stamp, I gave them the first stamp!`, {event: 'Activity Manager'});
return;
}

let stampNumber = botGuild.stamps.stampRoleIDs.get(role.id);
if (stampNumber === botGuild.stamps.stampRoleIDs.size - 1) {
let stampNumber = initBotInfo.stamps.stampRoleIDs.get(role.id);
if (stampNumber === initBotInfo.stamps.stampRoleIDs.size - 1) {
sendMessageToMember(member, 'You already have the maximum allowed number of stamps!', true);
winston.loggers.get(botGuild._id).userStats(`Activity named ${activityName} tried to give a stamp to the user with id ${member.id} but he is already in the max stamp ${stampNumber}`, {event: 'Activity Manager'});
winston.loggers.get(initBotInfo.id).userStats(`Activity named ${activityName} tried to give a stamp to the user with id ${member.id} but he is already in the max stamp ${stampNumber}`, {event: 'Activity Manager'});
return;
}
let newRoleID;

botGuild.stamps.stampRoleIDs.forEach((num, key, map) => {
initBotInfo.stamps.stampRoleIDs.forEach((num, key, map) => {
if (num === stampNumber + 1) newRoleID = key;
});

if (newRoleID != undefined) {
replaceRoleToMember(member, role.id, newRoleID);
sendMessageToMember(member, 'You have received a higher stamp for attending ' + activityName + '!', true);
winston.loggers.get(botGuild._id).userStats(`Activity named ${activityName} gave a stamp to the user with id ${member.id} going from stamp number ${stampNumber} to ${stampNumber + 1}`, {event: 'Activity Manager'});
winston.loggers.get(initBotInfo.id).userStats(`Activity named ${activityName} gave a stamp to the user with id ${member.id} going from stamp number ${stampNumber} to ${stampNumber + 1}`, {event: 'Activity Manager'});
}
}
}
Expand Down
Loading

0 comments on commit e748e8f

Please sign in to comment.