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

Merge develop branch with main #19

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions .circleci/config.yml
@@ -0,0 +1,45 @@
version: '2.1'
orbs:
node: circleci/node@5.0.2
executors:
node-executor:
docker:
- image: cimg/node:18.3.0
resource_class: small

jobs:
build:
executor: node-executor
steps:
- checkout
- run: |
yarn
- run: |
yarn build
lint:
executor: node-executor
steps:
- checkout
- run: |
yarn
- run: |
yarn lint
prettier:
executor: node-executor
steps:
- checkout
- run: |
yarn
- run: |
yarn prettier

workflows:
build:
jobs:
- build
lint:
jobs:
- lint
prettier:
jobs:
- prettier
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -8,6 +8,11 @@ This is the offical CodeRED Discord Bot. The bot is built using Typescript and D

<hr/>

![CircleCI](https://img.shields.io/circleci/build/github/CodeRED-UH/CodeRED-DiscordBot?style=flat-square)
[![GitHub issues](https://img.shields.io/github/issues/CodeRED-UH/CodeRED-DiscordBot?style=flat-square)](https://github.com/CodeRED-UH/CodeRED-DiscordBot/issues)
![GitHub last commit](https://img.shields.io/github/last-commit/CodeRED-UH/CodeRED-DiscordBot?style=flat-square)
![GitHub package.json dependency version (prod)](https://img.shields.io/github/package-json/dependency-version/CodeRED-UH/CodeRED-DiscordBot/discord.js?style=flat-square)

# Development πŸ”¨

- #### Requirements
Expand Down
Binary file added src/assets/exit_map.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/venue_map.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions src/commands/help.ts
Expand Up @@ -12,7 +12,10 @@ export const help: Command = {
const description = `${client.user?.tag} is CodeRED's official Discord bot!`;
let iconURL: string | null | undefined;

if (client.user?.avatarURL({ format: "png" }) === null) {
if (
client.user?.avatarURL({ format: "png" }) === null ||
client.user?.avatarURL({ format: "png" }) === undefined
) {
iconURL = "https://avatars.githubusercontent.com/u/107168679?s=200&v=4";
} else {
iconURL = client.user?.avatarURL({ format: "png" });
Expand All @@ -28,7 +31,11 @@ export const help: Command = {
)
.addField(
"Stats πŸ“Š",
"To view the current statistics of the bot use `/stats`.\nOnly available to the bot's owner."
"To view the current statistics of the bot use `/stats`.`\nOnly available to the bot's owner.`"
)
.addField(
"Purge",
"To clear messages use `/purge.\nOnly available to officers.`"
)
.setTimestamp()
.setFooter({
Expand Down
72 changes: 72 additions & 0 deletions src/commands/map.ts
@@ -0,0 +1,72 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { MessageEmbed, MessageAttachment } from "discord.js";
import { Command } from "../interfaces/Command";

export const map: Command = {
data: new SlashCommandBuilder()
.setName("map")
.setDescription("Provides venue and exit plan maps")
.addStringOption((option) =>
option
.setName("map")
.setDescription("Enter either 'venue' or 'exit'")
.setRequired(true)
),
run: async (interaction, client) => {
await interaction.deferReply();

let iconURL: string | null | undefined;
if (client.user?.avatarURL({ format: "png" }) === null) {
iconURL = "https://avatars.githubusercontent.com/u/107168679?s=200&v=4";
} else {
iconURL = client.user?.avatarURL({ format: "png" });
}

let file: MessageAttachment;
let mapEmbed: MessageEmbed;

switch (interaction.options.getString("map", true)) {
case "venue": {
file = new MessageAttachment("src/assets/venue_map.jpg");
mapEmbed = new MessageEmbed()
.setColor("#ffeded")
.setTitle("Venue Map")
.setTimestamp()
.setImage("attachment://venue_map.jpg")
.setFooter({
text: `${client.user?.tag}`,
iconURL: iconURL as string,
});
await interaction.editReply({ embeds: [mapEmbed], files: [file] });
break;
}
case "exit": {
file = new MessageAttachment("src/assets/exit_map.jpg");
mapEmbed = new MessageEmbed()
.setColor("#ffeded")
.setTitle("Venue Map")
.setTimestamp()
.setImage("attachment://exit_map.jpg")
.setFooter({
text: `${client.user?.tag}`,
iconURL: iconURL as string,
});
await interaction.editReply({ embeds: [mapEmbed], files: [file] });
break;
}
default: {
mapEmbed = new MessageEmbed()
.setColor("#FF0000")
.setTitle("❌ Option not found")
.setDescription("That option doesn't seem to exist.")
.setTimestamp()
.setFooter({
text: `${client.user?.tag}`,
iconURL: iconURL as string,
});
await interaction.editReply({ embeds: [mapEmbed] });
break;
}
}
},
};
91 changes: 91 additions & 0 deletions src/commands/purge.ts
@@ -0,0 +1,91 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { MessageEmbed } from "discord.js";
import { Command } from "../interfaces/Command";
import { success, error } from "../utils/embeded";

const isInRange = (
n: number,
lowerBound: number,
upperBound: number
): boolean => {
return n >= lowerBound && n <= upperBound;
};

export const purge: Command = {
data: new SlashCommandBuilder()
.setName("purge")
.setDescription("Clear n amount of messages.")
.setDMPermission(false)
.addNumberOption((option) =>
option
.setName("n")
.setDescription("Enter a number from 1-100.")
.setRequired(true)
),
run: async (interaction, client) => {
await interaction.deferReply({ ephemeral: true });
const { user, channel } = interaction;
const n = interaction.options.getNumber("n", true);

if (channel?.type === "DM" || !interaction.guild) {
await interaction.editReply({
embeds: [
error(null, "You can only delete messages in guilds.", client),
],
});
return;
}

const guildMember = await interaction.guild.members.cache.find(
(u) => u.id === user.id
);

if (!guildMember) {
await interaction.editReply({
embeds: [
error(
null,
"Failed to retrieve your information in this guild.",
client
),
],
});
return;
}

let isOfficer = false;

await guildMember.roles.cache.forEach((roleID) => {
if (roleID.name === "Officer") {
isOfficer = true;
}
});

if (!isOfficer) {
await interaction.editReply({
embeds: [error("Permission Error", "You are not an officer.", client)],
});
return;
}

if (!isInRange(n, 1, 100)) {
await interaction.editReply({
embeds: [error("Out of range", "Must be in range 1-100.", client)],
});
return;
}

let returnMessage: MessageEmbed;
let description = `You have purged up to ${n} messages from this channel.`;

returnMessage = success(null, description, client);

await channel?.bulkDelete(n, true).catch((err: Error) => {
description = `An error has occurred.\n${err}`;
returnMessage = error(null, description, client);
});

await interaction.editReply({ embeds: [returnMessage] });
return;
},
};
11 changes: 3 additions & 8 deletions src/commands/report.ts
@@ -1,6 +1,6 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { Command } from "../interfaces/Command";
import { createEmbeded } from "../utils/embeded";
import { success } from "../utils/embeded";

export const report: Command = {
data: new SlashCommandBuilder()
Expand All @@ -14,17 +14,12 @@ export const report: Command = {
),
run: async (interaction, client) => {
await interaction.deferReply({ ephemeral: true });
const { user } = interaction;
// const { user } = interaction;
const report = interaction.options.getString("report", true);

const description = `Your report with the contents\n"${report}"\nhas been successfully submitted`;

const returnMessage = createEmbeded(
"**Report πŸ“ž**",
description,
user,
client
);
const returnMessage = success("**Report πŸ“ž**", description, client);

await interaction.editReply({ embeds: [returnMessage] });
return;
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
@@ -1,11 +1,12 @@
import { Client } from "discord.js";
import { validateEnv } from "./utils/validateEnv";
import { onReady } from "./events/ready";
import { onInteraction } from "./events/interaction";
import { IntentOptions } from "./config/intentOptions";
import "dotenv/config";

(async () => {
// if (!validateEnv()) return;
if (!validateEnv()) return;
const client = new Client({ intents: IntentOptions });

client.on("ready", async () => await onReady(client));
Expand Down
4 changes: 3 additions & 1 deletion src/utils/_Commandlists.ts
@@ -1,5 +1,7 @@
import { Command } from "../interfaces/Command";
import { help } from "../commands/help";
import { report } from "../commands/report";
import { purge } from "../commands/purge";
import { map } from "../commands/map";

export const CommandList: Command[] = [help, report];
export const CommandList: Command[] = [help, report, purge, map];