Skip to content
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

New UWFlow Command Setup #515

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
29 changes: 29 additions & 0 deletions docs/COMMAND-WIKI.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,35 @@
- ``description``: The description of the customization to be set for the user.
- **Subcommands:** None

# UWFLOW
## uwflow
- **Aliases:** None
- **Description:** Handle UWFlow commands.
- **Examples:**
- **Options:** None
- **Subcommands:** `info`, `req`, `search`

## uwflow info
- **Aliases:** `information`, `i`
- **Description:** Get course information
- **Examples:**<br>`.uwflow info cs135`<br>`.uwflow information cs246`<br>`.uwflow i cs240`
- **Options:**
- **Subcommands:** None

## uwflow req
- **Aliases:** `requisite`
- **Description:** Get course requisites
- **Examples:**<br>`.uwflow req cs135`<br>`.uwflow requisite cs246`
- **Options:**
- **Subcommands:** None

## uwflow search
- **Aliases:** None
- **Description:** Search for courses in specified range
- **Examples:**<br>`.uwflow search CS 100 200`<br>`.uwflow search cs 100 200`
- **Options:**
- **Subcommands:** None

# SUGGESTION
## suggestion
- **Aliases:** ``suggest``
Expand Down
87 changes: 87 additions & 0 deletions src/commandDetails/uwflow/info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { container } from '@sapphire/framework';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
} from '../../codeyCommand';
import { courseInfo, getCourseInfo } from '../../components/uwflow';
import { EmbedBuilder } from 'discord.js';

const uwflowInfoExecuteCommand: SapphireMessageExecuteType = async (
_client,
_messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const courseCodeArg = <string | undefined>args['course_code'];

// If no argument is passed, return default information
if (courseCodeArg === undefined) {
const defaultEmbed = new EmbedBuilder()
.setColor('Blue')
.setTitle('General Information')
.setDescription('UWFlow is a website where students can view course reviews and ratings.');
return { embeds: [defaultEmbed] };
}

// Standardize the course code (i.e. cs 135, CS135, CS 135 becomes cs135 for the GraphQL query)
const courseCode = <string>courseCodeArg.split(' ').join('').toLowerCase();

const result: courseInfo | number = await getCourseInfo(courseCode);

// If mistyped course code or course doesn't exist
if (result === -1) {
const errorDesc = 'Oops, that course does not exist!';
const courseEmbed = new EmbedBuilder()
.setColor('Red')
.setTitle(`Information for ${courseCode.toUpperCase()}`)
.setDescription(errorDesc);
return { embeds: [courseEmbed] };
}

const info = <courseInfo>result;

const code = info.code.toUpperCase();
const name = info.name;
const description = info.description;
const liked = (info.liked * 100).toFixed(2);
const easy = (info.easy * 100).toFixed(2);
const useful = (info.useful * 100).toFixed(2);

const courseEmbed = new EmbedBuilder()
.setColor('Green')
.setTitle(`Information for ${code}`)
.addFields(
{ name: 'Course code', value: code, inline: false },
{ name: 'Course name', value: name, inline: false },
{ name: 'Course description', value: description, inline: false },
{ name: 'Like ratings', value: `${liked}%`, inline: true },
{ name: 'Easy ratings', value: `${easy}%`, inline: true },
{ name: 'Useful ratings', value: `${useful}%`, inline: true },
);

return { embeds: [courseEmbed] };
};

export const uwflowInfoCommandDetails: CodeyCommandDetails = {
name: 'info',
aliases: ['information', 'i'],
description: 'Get course information',
detailedDescription: `**Examples:**
\`${container.botPrefix}uwflow info cs135\`
\`${container.botPrefix}uwflow information cs246\`
\`${container.botPrefix}uwflow i cs240\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Getting information about UWFlow:',
executeCommand: uwflowInfoExecuteCommand,
options: [
{
name: 'course_code',
description: 'The course code. Examples: cs135, cs 135, CS135, CS 135',
type: CodeyCommandOptionType.STRING,
required: false,
},
],
subcommandDetails: {},
};
73 changes: 73 additions & 0 deletions src/commandDetails/uwflow/req.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { container } from '@sapphire/framework';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
} from '../../codeyCommand';
import { courseReqs, getCourseReqs } from '../../components/uwflow';
import { EmbedBuilder } from 'discord.js';

const uwflowReqExecuteCommand: SapphireMessageExecuteType = async (
_client,
_messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const courseCodeArg = <string>args['course_code'];

// Standardize the course code (i.e. cs 135, CS135, CS 135 becomes cs135 for the GraphQL query)
const courseCode = <string>courseCodeArg.split(' ').join('').toLowerCase();

const result: courseReqs | number = await getCourseReqs(courseCode);

// If mistyped course code or course doesn't exist
if (result === -1) {
const errorDesc = 'Oops, that course does not exist!';
const courseEmbed = new EmbedBuilder()
.setColor('Red')
.setTitle(`Information for ${courseCode.toUpperCase()}`)
.setDescription(errorDesc);
return { embeds: [courseEmbed] };
}

const requisites = <courseReqs>result;

const code = requisites.code.toUpperCase();
const antireqs = requisites.antireqs;
const prereqs = requisites.prereqs;
const coreqs = requisites.coreqs;

const courseEmbed = new EmbedBuilder()
.setColor('Green')
.setTitle(`Requisites for ${code}`)
.addFields(
{ name: 'Course code', value: code, inline: false },
{ name: 'Antirequisites', value: antireqs, inline: false },
{ name: 'Prerequisites', value: prereqs, inline: false },
{ name: 'Corequisites', value: coreqs, inline: false },
);

return { embeds: [courseEmbed] };
};

export const uwflowReqCommandDetails: CodeyCommandDetails = {
name: 'req',
aliases: ['requisite'],
description: 'Get course requisites',
detailedDescription: `**Examples:**
\`${container.botPrefix}uwflow req cs135\`
\`${container.botPrefix}uwflow requisite cs246\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Getting information from UWFlow:',
executeCommand: uwflowReqExecuteCommand,
options: [
{
name: 'course_code',
description: 'The course code. Examples: cs135, cs 135, CS135, CS 135',
type: CodeyCommandOptionType.STRING,
required: true,
},
],
subcommandDetails: {},
};
93 changes: 93 additions & 0 deletions src/commandDetails/uwflow/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { container } from '@sapphire/framework';
import {
CodeyCommandDetails,
CodeyCommandOptionType,
SapphireMessageExecuteType,
SapphireMessageResponse,
} from '../../codeyCommand';
import { searchResults, getSearchResults } from '../../components/uwflow';
import { EmbedBuilder } from 'discord.js';

const uwflowSearchExecuteCommand: SapphireMessageExecuteType = async (
_client,
_messageFromUser,
args,
): Promise<SapphireMessageResponse> => {
const courseArg = <string>args['course'];
const min = <number>args['min'];
const max = <number>args['max'];

// Standardize the course initials (i.e. CS becomes cs for the GraphQL query)
const course = courseArg.toLowerCase();

const results: searchResults[] | number = await getSearchResults(course, min, max);

// If mistyped course initials or course doesn't exist
if (results === -1) {
const errorDesc = 'UWFlow returned no data';
const courseEmbed = new EmbedBuilder()
.setColor('Red')
.setTitle(`Information for query of ${course.toUpperCase()} courses in range ${min} - ${max}`)
.setDescription(errorDesc);
return { embeds: [courseEmbed] };
}

const resultArray = <searchResults[]>results;
// If no courses fit the range
if (resultArray.length < 1) {
const desc = 'No courses suit the query';
const embed = new EmbedBuilder()
.setColor('Orange')
.setTitle(`Information for query of ${course} courses in range ${min} - ${max}`)
.setDescription(desc);
return { embeds: [embed] };
}

const courseArray: string[] = [];
for (const result of resultArray) {
courseArray.push(result.code);
}

const desc = courseArray.join(', ');

const resultEmbed = new EmbedBuilder()
.setColor('Green')
.setTitle(`Information for query of ${course} courses in range ${min} - ${max}`)
.setDescription(desc);

return { embeds: [resultEmbed] };
};

export const uwflowSearchCommandDetails: CodeyCommandDetails = {
name: 'search',
aliases: [],
description: 'Search for courses in specified range',
detailedDescription: `**Examples:**
\`${container.botPrefix}uwflow search CS 100 200\`
\`${container.botPrefix}uwflow search cs 100 200\``,

isCommandResponseEphemeral: false,
messageWhenExecutingCommand: 'Getting information from UWFlow:',
executeCommand: uwflowSearchExecuteCommand,
options: [
{
name: 'course',
description: 'The initials of the course. Examples: CS, cs, MATH, math',
type: CodeyCommandOptionType.STRING,
required: true,
},
{
name: 'min',
description: 'The minimum code of the course',
type: CodeyCommandOptionType.INTEGER,
required: true,
},
{
name: 'max',
description: 'The maximum code of the course',
type: CodeyCommandOptionType.INTEGER,
required: true,
},
],
subcommandDetails: {},
};
32 changes: 32 additions & 0 deletions src/commands/uwflow/uwflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Command } from '@sapphire/framework';
import { uwflowInfoCommandDetails } from '../../commandDetails/uwflow/info';
import { uwflowReqCommandDetails } from '../../commandDetails/uwflow/req';
import { uwflowSearchCommandDetails } from '../../commandDetails/uwflow/search';
import { CodeyCommand, CodeyCommandDetails } from '../../codeyCommand';

const uwflowCommandDetails: CodeyCommandDetails = {
name: 'uwflow',
aliases: [],
description: 'Handle UWFlow commands.',
detailedDescription: `**Examples:**`,
options: [],
subcommandDetails: {
info: uwflowInfoCommandDetails,
req: uwflowReqCommandDetails,
search: uwflowSearchCommandDetails,
},
defaultSubcommandDetails: uwflowInfoCommandDetails,
};

export class UWFlowCommand extends CodeyCommand {
details = uwflowCommandDetails;

public constructor(context: Command.Context, options: Command.Options) {
super(context, {
...options,
aliases: uwflowCommandDetails.aliases,
description: uwflowCommandDetails.description,
detailedDescription: uwflowCommandDetails.detailedDescription,
});
}
}
Loading
Loading