diff --git a/config/config.example.json b/config/config.example.json index ce91047..fe5c54b 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -39,7 +39,10 @@ "moderatorRoleId": "8236742893645345", "moderatorCommandChannelId": "3653476435525426", "courseSelectionChannelId": "34534643643455456", - "verificationChannelId": "52323425624352354" + "verificationChannelId": "52323425624352354", + "studentAdvisoryCommittee": { + "roleId": "238946293846263423" + } }, "89233498652365349": { "majors": ["phys", "chem"], diff --git a/src/models/config.ts b/src/models/config.ts index f9b8c61..8c0913c 100644 --- a/src/models/config.ts +++ b/src/models/config.ts @@ -55,4 +55,9 @@ export interface GuildConfig { moderatorCommandChannelId: string; courseSelectionChannelId: string; verificationChannelId: string; + studentAdvisoryCommittee?: GuildStudentAdvisoryCommitteeConfig; +} + +export interface GuildStudentAdvisoryCommitteeConfig { + roleId: string } diff --git a/src/services/config.ts b/src/services/config.ts index 2f98582..0f86ad3 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -164,7 +164,18 @@ export class ConfigService { if(!guild.verificationChannelId) { throw Error(`Guild ID ${guildId} configuration has missing or empty verification channel ID.`); } + this.validateGuildStudentAdvisoryCommitteeConfig(guildId); //TODO: web catalog validation. }); } + + private static validateGuildStudentAdvisoryCommitteeConfig(guildId: string): void { + const guild = this.config.guilds[guildId]; + if(guild.studentAdvisoryCommittee) { + if(!guild.studentAdvisoryCommittee.roleId) { + throw Error(`Guild ID ${guildId} configuration has missing or empty student advisory committee role ID. + If you did not mean to enable the student advisory committee functionality, please remove its configuration section.`); + } + } + } } diff --git a/src/services/implement/course/channel.ts b/src/services/implement/course/channel.ts index b7407c4..de93b09 100644 --- a/src/services/implement/course/channel.ts +++ b/src/services/implement/course/channel.ts @@ -12,12 +12,32 @@ export class CourseChannelImplementService { categoryId: string, mainRoleId: string, taRoleId: string): Promise { + let discordChannelType: any; + let topic = null; + switch (type) { case CourseImplementChannelType.CHAT: - return this.createChatChannel(guildContext, course, categoryId, mainRoleId, taRoleId); + discordChannelType = "text"; + topic = course.title ? `:information_source: ${course.title}` : ""; + break; case CourseImplementChannelType.VOICE: - return this.createVoiceChannel(guildContext, course, categoryId, mainRoleId, taRoleId); + discordChannelType = "voice"; + break; } + + const channel = await guildContext.guild.channels.create( + CourseUtils.getChannelNameByType(course, type), + { + type: discordChannelType, + topic: topic, + parent: categoryId, + position: 0, + permissionOverwrites: this.generateChannelPermissionsByType(guildContext, type, mainRoleId, taRoleId), + reason: "StudyBot automatic course channel creation.", + } + ); + + return channel; } public static async resetChannelPermissionsByType( @@ -36,9 +56,10 @@ export class CourseChannelImplementService { mainRoleId: string, taRoleId: string ): Discord.OverwriteResolvable[] { + let permissions: Discord.OverwriteResolvable[] = []; switch(type) { case CourseImplementChannelType.CHAT: - return [ + permissions = [ { type: "role", id: guildContext.guild.roles.everyone.id, @@ -60,8 +81,17 @@ export class CourseChannelImplementService { allow: ["VIEW_CHANNEL"] } ]; + + if(guildContext.guildConfig.studentAdvisoryCommittee) { + permissions.push({ + type: "role", + id: guildContext.guildConfig.studentAdvisoryCommittee.roleId, + allow: ["VIEW_CHANNEL"] + }); + } + break; case CourseImplementChannelType.VOICE: - return [ + permissions = [ { type: "role", id: guildContext.guild.roles.everyone.id, @@ -84,47 +114,17 @@ export class CourseChannelImplementService { allow: ["VIEW_CHANNEL"] } ]; - } - } - - public static async createChatChannel( - guildContext: GuildContext, - course: Course, - categoryId: string, - mainRoleId: string, - taRoleId: string): Promise { - const channel = await guildContext.guild.channels.create( - CourseUtils.getChatChannelName(course), - { - type: "text", - topic: `:information_source: ${course.title}`, - parent: categoryId, - position: 0, - permissionOverwrites: this.generateChannelPermissionsByType(guildContext, CourseImplementChannelType.CHAT, mainRoleId, taRoleId), - reason: "StudyBot automatic course channel creation.", - } - ); - - return channel; - } - - public static async createVoiceChannel( - guildContext: GuildContext, - course: Course, - categoryId: string, - mainRoleId: string, - taRoleId: string): Promise { - const channel = await guildContext.guild.channels.create( - CourseUtils.getVoiceChannelName(course), - { - type: "voice", - parent: categoryId, - position: 0, - permissionOverwrites: this.generateChannelPermissionsByType(guildContext, CourseImplementChannelType.VOICE, mainRoleId, taRoleId), - reason: "StudyBot automatic course channel creation.", - } - ); - return channel; + if(guildContext.guildConfig.studentAdvisoryCommittee) { + permissions.push({ + type: "role", + id: guildContext.guildConfig.studentAdvisoryCommittee.roleId, + allow: ["VIEW_CHANNEL", "SPEAK", "STREAM"] + }); + } + break; + } + + return permissions; } } \ No newline at end of file diff --git a/src/utils/course.ts b/src/utils/course.ts index 98c86f7..efec726 100644 --- a/src/utils/course.ts +++ b/src/utils/course.ts @@ -1,5 +1,6 @@ import * as crypto from "crypto"; import { PartialCourse } from "models/course"; +import { CourseImplementChannelType } from "models/implement/course"; import { Major } from "models/major"; import { ConfigService } from "services/config"; @@ -49,11 +50,12 @@ export class CourseUtils { return `${course.key}-ta`; } - public static getChatChannelName(course: PartialCourse): string { - return course.key; - } - - public static getVoiceChannelName(course: PartialCourse): string { - return `${course.key}-voice`; + public static getChannelNameByType(course: PartialCourse, type: CourseImplementChannelType): string { + switch(type) { + case CourseImplementChannelType.CHAT: + return course.key; + case CourseImplementChannelType.VOICE: + return `${course.key}-voice`; + } } } \ No newline at end of file