Skip to content

Commit

Permalink
Issue #283 (#508)
Browse files Browse the repository at this point in the history
* Refactored to be just command interface

* Added file to manage the command and subcommands

* Added file to manage list subcommand

* Added file to manage signup subcommand

* Added file to manage pause subcommand

* Added file to manage profile subcommand

* Added file to manage resume subcommand

* Added file to manage clear subcommand

* Added file to manage domain subcommand

* Refactored subcommand structures of interviewer command

* Refactored clear subcommand of interviewer

* Refactored domain subcommand of interviewer

* Refactored list subcommand of interviewer

* Refactored pause subcommand of interviewer

* Refactored profile subcommand of interviewer

* Refactored resume subcommand of interviewer

* Refactored signup subcommand of interviewer

* Made domain field of domain subcommand required

* Fixed bug with list subcommand when database is empty

* Fixed linting issues

* Modified subcommand comments
  • Loading branch information
KuroganeToyama authored Jan 29, 2024
1 parent 1813bd7 commit b3c9cd0
Show file tree
Hide file tree
Showing 8 changed files with 416 additions and 207 deletions.
40 changes: 40 additions & 0 deletions src/commandDetails/interviewer/clear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { container } from '@sapphire/framework';
import { clearProfile, getInterviewer } from '../../components/interviewer';
import {
CodeyCommandDetails,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerClearExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
_args,
): Promise<SapphireMessageResponse> => {
const id = getUserFromMessage(messageFromUser).id;

// Check if user signed up to be interviewer
if (!(await getInterviewer(id))) {
return `You don't seem to have signed up yet. Please sign up using \`${container.botPrefix}interviewer signup <calendarUrl>\`!`;
}

// Clear interviewer data
await clearProfile(id);
return 'Your interviewer profile has been cleared!';
};

export const interviewerClearCommandDetails: CodeyCommandDetails = {
name: 'clear',
aliases: ['clr'],
description: 'Clear all your interviewer data',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer clear\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Clearing your interviewer profile...',
executeCommand: interviewerClearExecuteCommand,
messageIfFailure: 'Could not clear your interviewer profile',
options: [],
subcommandDetails: {},
};
59 changes: 59 additions & 0 deletions src/commandDetails/interviewer/domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { container } from '@sapphire/framework';
import {
availableDomains,
getAvailableDomainsString,
getInterviewer,
toggleDomain,
} from '../../components/interviewer';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerDomainExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const domain: string | undefined = <string>args['domain_name'];
if (domain && !(domain.toLowerCase() in availableDomains)) {
return `You entered an invalid domain. Please enter one of ${getAvailableDomainsString()}.`;
}

const id = getUserFromMessage(messageFromUser).id;
// Check if user signed up to be interviewer
if (!(await getInterviewer(id))) {
return `You don't seem to have signed up yet. Please sign up using \`${container.botPrefix}interviewer signup <calendarUrl>\`!`;
}

// Add or remove domain to/from interviewer
const inDomain = await toggleDomain(id, domain);
return inDomain
? `You have been successfully removed from ${availableDomains[domain]}`
: `You have been successfully added to ${availableDomains[domain]}`;
};

export const interviewerDomainCommandDetails: CodeyCommandDetails = {
name: 'domain',
aliases: ['domain'],
description: 'Add/remove a domain of your choice',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer domain frontend\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Modifying domain data...',
executeCommand: interviewerDomainExecuteCommand,
messageIfFailure: 'Could not modify domain data',
options: [
{
name: 'domain_name',
description: 'A valid domain name',
type: CodeyCommandOptionType.STRING,
required: true,
},
],
subcommandDetails: {},
};
90 changes: 90 additions & 0 deletions src/commandDetails/interviewer/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { container } from '@sapphire/framework';
import { EmbedBuilder } from 'discord.js';
import _ from 'lodash';
import {
availableDomains,
getAvailableDomainsString,
getInterviewerDomainsString,
getInterviewers,
Interviewer,
} from '../../components/interviewer';
import { DEFAULT_EMBED_COLOUR } from '../../utils/embeds';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
} from '../../codeyCommand';

const RESULTS_PER_PAGE = 6;

const getInterviewerDisplayInfo = async (interviewer: Interviewer): Promise<string> => {
const { client } = container;
const user = await client.users.fetch(interviewer['user_id']);
const userDomainsAddIn = await getInterviewerDomainsString(interviewer['user_id']);
if (userDomainsAddIn === '') {
return `${user} | [Calendar](${interviewer['link']})\n\n`;
} else {
return `${user} | [Calendar](${interviewer['link']}) | ${userDomainsAddIn}\n\n`;
}
};

const interviewerListExecuteCommand: SapphireMessageExecuteType = async (
_client,
_messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const domain: string | undefined = <string>args['domain'];
if (domain && !(domain.toLowerCase() in availableDomains)) {
return `You entered an invalid domain. Please enter one of ${getAvailableDomainsString()}.`;
}

// Query interviewers
const interviewers = await getInterviewers(domain);
// Shuffles interviewers to load balance
const shuffledInterviewers = _.shuffle(interviewers);
// Only show up to page limit
const interviewersToShow = shuffledInterviewers.slice(0, RESULTS_PER_PAGE);
// Get information from each interviewer
const interviewersInfo = await Promise.all(
interviewersToShow.map((interviewer) => getInterviewerDisplayInfo(interviewer)),
);

// If there's no data, then interviewersInfo is an array of undefined, which messed things up
// Thus need to display something else instead of interviewersInfo.join()
const embedDescription =
interviewersInfo[0] === undefined ? 'No data to display' : interviewersInfo.join('');

// Construct embed for display
const title = domain
? `Available Interviewers for ${availableDomains[domain]}`
: 'Available Interviewers';
const outEmbed = new EmbedBuilder()
.setColor(DEFAULT_EMBED_COLOUR)
.setTitle(title)
.setDescription(embedDescription);
return { embeds: [outEmbed] };
};

export const interviewerListCommandDetails: CodeyCommandDetails = {
name: 'list',
aliases: ['ls'],
description: 'List all interviewers or those under a specific domain',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer list\`
\`${container.botPrefix}interviewer list backend\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Listing interviewers...',
executeCommand: interviewerListExecuteCommand,
messageIfFailure: 'Could not list interviewers',
options: [
{
name: 'domain',
description: 'The domain to be examined',
type: CodeyCommandOptionType.STRING,
required: false,
},
],
subcommandDetails: {},
};
40 changes: 40 additions & 0 deletions src/commandDetails/interviewer/pause.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { container } from '@sapphire/framework';
import { getInterviewer, pauseProfile } from '../../components/interviewer';
import {
CodeyCommandDetails,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerPauseExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
_args,
): Promise<SapphireMessageResponse> => {
const id = getUserFromMessage(messageFromUser).id;

// Check if user signed up to be interviewer
if (!(await getInterviewer(id))) {
return `You don't seem to have signed up yet, please sign up using \`${container.botPrefix}interviewer signup <calendarUrl>\`!`;
}

// Pause interviewer data
await pauseProfile(id);
return `Your interviewer profile has been paused! You will not appear in interviewer queries anymore, until you run \`${container.botPrefix}interviewer resume\`.`;
};

export const interviewerPauseCommandDetails: CodeyCommandDetails = {
name: 'pause',
aliases: ['ps'],
description: 'Put your interviewer profile on pause',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer pause\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Pausing profile...',
executeCommand: interviewerPauseExecuteCommand,
messageIfFailure: 'Could not pause profile',
options: [],
subcommandDetails: {},
};
54 changes: 54 additions & 0 deletions src/commandDetails/interviewer/profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { container } from '@sapphire/framework';
import { EmbedBuilder } from 'discord.js';
import _ from 'lodash';
import { getDomains, getDomainsString, getInterviewer } from '../../components/interviewer';
import { DEFAULT_EMBED_COLOUR } from '../../utils/embeds';
import {
CodeyCommandDetails,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerProfileExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
_args,
): Promise<SapphireMessageResponse> => {
const id = getUserFromMessage(messageFromUser).id;

// Check if user signed up to be interviewer
const interviewer = await getInterviewer(id);
if (!interviewer) {
return `You don't seem to have signed up yet. Please sign up using \`${container.botPrefix}interviewer signup <calendarUrl>\`!`;
}

// Get domains
const domains = await getDomains(id);

// Build output embed
const profileEmbed = new EmbedBuilder()
.setColor(DEFAULT_EMBED_COLOUR)
.setTitle('Interviewer Profile');
profileEmbed.addFields([
{ name: '**Link**', value: interviewer.link },
{ name: '**Domains**', value: _.isEmpty(domains) ? 'None' : getDomainsString(domains) },
]);

return { embeds: [profileEmbed] };
};

export const interviewerProfileCommandDetails: CodeyCommandDetails = {
name: 'profile',
aliases: ['pf'],
description: 'Display your interviewer profile data',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer profile\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Displaying profile...',
executeCommand: interviewerProfileExecuteCommand,
messageIfFailure: 'Could not display profile',
options: [],
subcommandDetails: {},
};
40 changes: 40 additions & 0 deletions src/commandDetails/interviewer/resume.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { container } from '@sapphire/framework';
import { getInterviewer, resumeProfile } from '../../components/interviewer';
import {
CodeyCommandDetails,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerResumeExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
_args,
): Promise<SapphireMessageResponse> => {
const id = getUserFromMessage(messageFromUser).id;

// Check if user signed up to be interviewer
if (!(await getInterviewer(id))) {
`You don't seem to have signed up yet. Please sign up using \`${container.botPrefix}interviewer signup <calendarUrl>\`!`;
}

// Resume interviewer data
await resumeProfile(id);
return 'Your interviewer profile has been resumed!';
};

export const interviewerResumeCommandDetails: CodeyCommandDetails = {
name: 'resume',
aliases: ['resume'],
description: 'Resume your interviewer profile',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer resume\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Resuming profile...',
executeCommand: interviewerResumeExecuteCommand,
messageIfFailure: 'Could not resume profile',
options: [],
subcommandDetails: {},
};
55 changes: 55 additions & 0 deletions src/commandDetails/interviewer/signup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { container } from '@sapphire/framework';
import { getEmojiByName } from '../../components/emojis';
import { parseLink, upsertInterviewer } from '../../components/interviewer';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
getUserFromMessage,
} from '../../codeyCommand';

const interviewerSignupExecuteCommand: SapphireMessageExecuteType = async (
_client,
messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const id = getUserFromMessage(messageFromUser).id;

// Get calendar URL from the 1st capture group
const calendarUrl = <string>args['calendar_url'];

// Parse link and checks for validity
const parsedUrl = parseLink(calendarUrl);
if (!parsedUrl) {
return `I don't seem to recognize your meeting link. Be sure to use calendly or x.ai.`;
}

// Add or update interviewer info
await upsertInterviewer(id, parsedUrl);
return `Your info has been updated. Thanks for helping out! ${getEmojiByName(
'codey_love',
)?.toString()}`;
};

export const interviewerSignupCommandDetails: CodeyCommandDetails = {
name: 'signup',
aliases: ['signup'],
description: 'Sign yourself up to be an interviewer!',
detailedDescription: `**Examples:**
\`${container.botPrefix}interviewer signup www.calendly.com\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Signing up for a profile...',
executeCommand: interviewerSignupExecuteCommand,
messageIfFailure: 'Could not sign up for a profile',
options: [
{
name: 'calendar_url',
description: 'A valid calendly.com or x.ai calendar link',
type: CodeyCommandOptionType.STRING,
required: true,
},
],
subcommandDetails: {},
};
Loading

0 comments on commit b3c9cd0

Please sign in to comment.