diff --git a/commands/course.js b/commands/course.js index 15d87caa..b55544c1 100644 --- a/commands/course.js +++ b/commands/course.js @@ -128,52 +128,8 @@ module.exports = { }); } - // Otherwise, find a channel with the same name as the course - const channel = await interaction.guild.channels.cache.find( - (c) => c.name.toLowerCase() === course.toLowerCase(), - ); - - // Make sure that the channel exists, and is a text channel - if (channel === undefined) { - return await interaction.reply({ - content: `❌ | The course chat for \`${course}\` does not exist. If you'd like for it to be created, please raise a ticket in <#${MODERATION_REQUEST_CHANNEL}>.`, - ephemeral: true, - }); - } else if (channel.type !== "GUILD_TEXT") { - return await interaction.reply({ - content: `❌ | The course chat for \`${course}\` is not a text channel.`, - ephemeral: true, - }); - } - - const permissions = new Permissions( - channel.permissionsFor(interaction.user.id).bitfield, - ); - - // Check if the member already has an entry in the channel's permission overwrites, and update - // the entry if they do just to make sure that they have the correct permissions - if ( - permissions.has([ - Permissions.FLAGS.VIEW_CHANNEL, - Permissions.FLAGS.SEND_MESSAGES, - ]) - ) { - await channel.permissionOverwrites.edit(interaction.member, { - VIEW_CHANNEL: true, - }); - return await interaction.reply({ - content: `❌ | You are already in the course chat for \`${course_with_alias}\`.`, - ephemeral: true, - }); - } - - // Add the member to the channel's permission overwrites - await channel.permissionOverwrites.create(interaction.member, { - VIEW_CHANNEL: true, - }); - return await interaction.reply({ - content: `✅ | Added you to the chat for ${course_with_alias}.`, + content: `✅ | End of command - ${course_with_alias}.`, ephemeral: true, }); } else if (interaction.options.getSubcommand() === COMMAND_LEAVE) { @@ -182,7 +138,7 @@ module.exports = { if (!is_valid_course(course)) { return await interaction.reply({ - content: `❌ | You are not allowed to leave this channel using this command.`, + content: `❌ | Not a valid course.`, ephemeral: true, }); } @@ -196,7 +152,7 @@ module.exports = { if (role !== undefined) { if (!interaction.member.roles.cache.has(role.id)) { return await interaction.reply({ - content: `❌ | You are not in the course chat for \`${course}\`.`, + content: `❌ | You do not have the role for \`${course}\`.`, ephemeral: true, }); } @@ -204,55 +160,11 @@ module.exports = { // If they do, let's remove the role from them await interaction.member.roles.remove(role); return await interaction.reply({ - content: `✅ | Removed you from the chat for \`${course}\`.`, + content: `✅ | Removed you from the role and chat for \`${course}\`.`, ephemeral: true, }); } - - // Find a channel with the same name as the course - const channel = await interaction.guild.channels.cache.find( - (c) => c.name.toLowerCase() === course.toLowerCase(), - ); - - // Otherwise, make sure that the channel exists, and is a text channel - if (channel === undefined) { - return await interaction.reply({ - content: `❌ | The course chat for \`${course}\` does not exist.`, - ephemeral: true, - }); - } else if (channel.type !== "GUILD_TEXT") { - return await interaction.reply({ - content: `❌ | The course chat for \`${course}\` is not a text channel.`, - ephemeral: true, - }); - } - - const permissions = new Permissions( - channel.permissionsFor(interaction.user.id).bitfield, - ); - - // Check if the member already has an entry in the channel's permission overwrites - if ( - !permissions.has([ - Permissions.FLAGS.VIEW_CHANNEL, - Permissions.FLAGS.SEND_MESSAGES, - ]) - ) { - return await interaction.reply({ - content: `❌ | You are not in the course chat for \`${course}\`.`, - ephemeral: true, - }); - } - - // Remove the member from the channel's permission overwrites - await channel.permissionOverwrites.delete(interaction.member); - - return await interaction.reply({ - content: `✅ | Removed you from the course chat for \`${course}\`.`, - ephemeral: true, - }); } - return await interaction.reply("Error: invalid subcommand."); } catch (error) { await interaction.reply("Error: " + error); diff --git a/commands/project-descriptions.js b/commands/project-descriptions.js index 0b186b0d..39f820eb 100644 --- a/commands/project-descriptions.js +++ b/commands/project-descriptions.js @@ -12,14 +12,17 @@ module.exports = { .addChoices([ ["Chaos", "chaos"], ["Circles", "circles"], - ["CS Electives", "cselectives"], + ["Uni-lectives", "unilectives"], ["Discord Bot", "discordbot"], ["Freerooms", "freerooms"], ["Jobsboard", "jobsboard"], ["Notangles", "notangles"], ["Structs.sh", "structs.sh"], + ["Trainee Program", "training-program"], ["UI/UX", "ui/ux"], + ["CMS", "cms"], ["Website", "website"], + ["???", "projects-fair-easter-egg-ctf"], ]), ), @@ -28,57 +31,100 @@ module.exports = { // console.log(`.${parsedOption}.`); switch (parsedOption) { case "chaos": - await interaction.reply( - "Chaos is a CSESoc internal recruitment tool written in Rust.", - ); + await interaction.reply({ + content: + "Chaos is an internal recruitment tool written in Rust. Are you allergic to google sheets and excel? Do you have nightmares from browsing through millions of lines of csv just to pick one applicant to take in? \nIntroducing Chaos, the ultimate lifesaver for clubs and societies! \nSay goodbye to the chaos and hello to simplicity. Chaos streamlines everything, making applications a breeze. \nWith a Rust 🦀 backend, type-safe and secure, no more segfaults and losing data! \nOur minimalistic while aesthetic frontend interface frees your eyes and brains from the repetitive and dull rows and columns of data sheets 📃\n\n", + ephemeral: true, + }); break; case "circles": - await interaction.reply( - "Circles is a degree planner that helps you choose courses, plan out your terms and check progression.", - ); + await interaction.reply({ + content: + "Tired of using a poorly laid out spreadsheet to cobble together a course progression plan to follow for the next 3-8 years of your life? Have no fear, Circles is here! \nCircles is a UNSW degree planner where you can explore and validate your degree structure. \nYou can find and use a live build of Circles at ", + ephemeral: true, + }); break; - case "cselectives": - await interaction.reply( - "Unsure about what a course is like? Worry no more; CSElectives lets you read and write reviews of UNSW CSE courses.", - ); + case "unilectives": + await interaction.reply({ + content: + "Tired of searching through websites and forum posts to find the perfect course? Only to discover that it's offered once a year? Or perhaps the workload turned out to be completely different from your expectations? \nLook no further, Uni-lectives has got your back. With 1000 unique reviews and counting across a variety of faculties, Uni-lectives is your one stop shop for UNSW courses and electives, where you can access valuable reviews and also contribute your own, empowering others to make informed choices about the courses they enrol in!\n\n", + ephemeral: true, + }); break; case "discordbot": - await interaction.reply( - "CSESoc Discord Bot is your friendly helper in all things fun and CSE.", - ); + await interaction.reply({ + content: + "Discord Bot is your friendly CSE discord companion on the CSESoc discord server, offering various features such as checking what week it is, explaining what all CSESoc/DevSoc Projects do, the 24 minigame and more to come! \nHere's a sneak peek at coming features: \n\nWeekly Lunch buddy - a speed friending feature for organising and meeting up on-campus each week with like-minded friendly people! \nSydney Trains Delay API - conveniently check if the light rail is down from the comfort of your study room before you get hit with a nasty surprise at Anzac Parade or High Street!", + ephemeral: true, + }); break; case "freerooms": - await interaction.reply( - "Looking for a room to study in? Freerooms lets you see which on-campus rooms are vacant and which ones are booked.", - ); + await interaction.reply({ + content: + "Freerooms is a tool designed to help UNSW students find empty or unbooked rooms on campus.\n\n🥾Have you ever wandered around campus, searching for an empty study room?🚪 Have you ever wanted to study somewhere other than the weird smelling ASB🏢, the loud corridors of Ainsworth 🏦 or the poorly decorated main library? 📚 \nIf you are a director or exec, have you ever wanted to find a room for your in-person meetings or society event? \nWhether you're in need of a quiet study nook or a large space for your society's next big event, Freerooms has got you covered!\n\n", + ephemeral: true, + }); break; case "jobsboard": - await interaction.reply( - "Jobsboard is an app that connects CSE students with companies looking for recruits.", - ); + await interaction.reply({ + content: + "Are you tired of hearing your friends talk about their exciting summer internship experiences while feeling left out? Fear not, because Jobsboard has got your back so you can wave goodbye to spending your summer working on projects to put on your resume! \nSupported by CSESoc’s strong partnerships with top tech giants in Australia like Atlassian, IMC, Canva and more, you will have immediate access to opportunities from these companies as soon they become available on Jobsboard!\n\n", + ephemeral: true, + }); break; case "notangles": - await interaction.reply( - "Notangles is a timetable planning app for UNSW students to build their perfect timetable, even before class registration opens.", - ); + await interaction.reply({ + content: + "Class registrations out and you have no clue how your next term is going to pan out? No idea how to come up with a timetable that balances all your classes and social events that you cannot miss? Do not worry! Notangles got your back. \nNotangles is your interactive timetable application, that can help you and your friends plan out a weekly schedule by showing you available classes for your courses and allow you to also slot in recurring events that can not be missed. It can also generate a timetable for you by taking in your preferences. Let there be no more timetable-tangles with Notangles!\n\n", + ephemeral: true, + }); break; case "structs.sh": - await interaction.reply("Structs.sh is an interactive algorithm visualiser."); + await interaction.reply({ + content: + "Structs.sh is an educational tool for computer science students that visualizes the most fundamental data structures (arrays, linked lists and binary search trees) and algorithms (sorting, searching and traversal). \nThe 2023 team is committed to transforming your educational experience by developing an application never seen before: a visual debugger that lets users type in arbitrary C code for our website to visualize the data structure(s) present in memory.\n\n", + ephemeral: true, + }); + break; + case "training-program": + await interaction.reply({ + content: + "The Training Program is a 1 term crash-course built to train up students new to or interested in web-dev! Every term, we teach the basics of React and JS, then put trainees into groups led by our talented training leads to build a personal project of their own! These personal projects can be anything that you think of, ranging from productivity web apps 📆 to dating apps built just for computer science students 😳. The training program is a place for learning new skills and getting you started on building that new tech idea you've always been thinking about!\n\nCome join today!", + ephemeral: true, + }); break; case "ui/ux": - await interaction.reply( - "The CSESoc Development UI/UX team works with all things related to user interface and experience design!", - ); + await interaction.reply({ + content: + "The CSESoc Development UI/UX team works with all things related to user interface and experience design!", + ephemeral: true, + }); + break; + case "projects-fair-easter-egg-ctf": + await interaction.reply({ + content: "Good job! Ollie's easter egg is levelup{discordbot_and_Ollie}", + ephemeral: true, + }); + break; + case "cms": + await interaction.reply({ + content: + "Each year CSESoc creates and publishes a number of blogs, articles, and guides dedicated to exploring interesting topics and helping students with their studies. The CMS aims to make creating these documents easier and more efficient by unifying the system used across portfolios. \nThis year the team has focused on developing the fundamental building blocks blog writers may need such as having sections of code within documents. The CMS team continues to evolve the application with the objective of having concurrent editing capabilities.", + ephemeral: true, + }); break; case "website": - await interaction.reply( - "The website team are in charge of writing the software for the CSESoc website.", - ); + await interaction.reply({ + content: + "Representing the CSE Society, the website showcases the main features of the community and collates all relevant resources in an easily located manner. Decorated with links to portfolios, guides, sponsors, and relevant social media platforms, the website allows all students to quickly navigate to the service they require.\n\n", + ephemeral: true, + }); break; default: - await interaction.reply( - "Error: the switch case has fallen through to the default case.", - ); + await interaction.reply({ + content: "Error: the switch case has fallen through to the default case.", + ephemeral: true, + }); break; } }, diff --git a/commands/rolesPermOverride.js b/commands/rolesPermOverride.js new file mode 100644 index 00000000..21e05e75 --- /dev/null +++ b/commands/rolesPermOverride.js @@ -0,0 +1,93 @@ +const { SlashCommandBuilder } = require("@discordjs/builders"); +const { Permissions } = require("discord.js"); + +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()) + ); +}; + +function editChannels(interaction, channels, role) { + channels.forEach((channel) => { + if ( + channel.type === "GUILD_TEXT" && + channel.name.toLowerCase() === role.name.toLowerCase() + ) { + // Remove all permissions from a role + role.setPermissions(0n) + .then((updated) => + console.log(`Updated permissions to ${updated.permissions.bitfield}`), + ) + .catch(console.error); + // Set the permissions of the role + // Add the member to the channel's permission overwrites + channel.permissionOverwrites.create(role, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + }); + console.log(channel.name, role.name); + } + }); +} + +function editRoles(interaction, roles) { + roles.forEach((role) => { + if (is_valid_course(role.name)) { + interaction.guild.channels + .fetch() + .then( + (channels) => ( + editChannels(interaction, channels, role), + console.log(`There are ${channels.size} channels.`) + ), + ) + .catch(console.error); + } + }); + interaction.reply({ + content: `✅ | found course chats and matching roles, cleared and set permission overwrites for roles.`, + ephemeral: true, + }); +} + +module.exports = { + data: new SlashCommandBuilder() + .setName("rolespermoverride") + .setDescription( + "Looks for matches between roles and course chats and attaches permissions.", + ), + async execute(interaction) { + try { + if (!interaction.member.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) { + return await interaction.reply({ + content: "You do not have permission to execute this command.", + ephemeral: true, + }); + } + // for all roles with name == chat name involving 4 letter prefix comp, seng, engg or binf, + + // give the role the permission override to participate in the matching channel. + interaction.guild.roles + .fetch() + .then( + (roles) => ( + editRoles(interaction, roles), console.log(`There are ${roles.size} roles.`) + ), + ) + .catch(console.error); + } catch (error) { + await interaction.reply("Error: " + error); + } + }, +}; diff --git a/config/carrotboard.yaml b/config/carrotboard.yaml index 32c98a8b..7a4a11b6 100644 --- a/config/carrotboard.yaml +++ b/config/carrotboard.yaml @@ -3,5 +3,5 @@ leaderboard_channel_id: 979516523335016509 carrotboard_alert_channel_id: 894267846106963998 guild_id: 884747109935497236 carrot_emoji: 🥳 -minimum_carrot_count: 1 -minimum_pin_count: 1 +minimum_carrot_count: 999999 +minimum_pin_count: 999999999999