├── config.example.json
├── events
├── ready.js
├── messageCreate.js
└── interactionCreate.js
├── SlashCommands
├── Info
│ ├── ping.js
│ ├── help.js
│ └── userinfo.js
├── Mod
│ ├── lock.js
│ ├── unlock.js
│ ├── unwarn.js
│ ├── slowmode.js
│ ├── unban.js
│ ├── ban.js
│ ├── kick.js
│ ├── clear.js
│ ├── warn.js
│ ├── removerole.js
│ ├── nickname.js
│ ├── addrole.js
│ ├── warnings.js
│ └── timeout.js
└── Config
│ └── setmodlogs.js
├── models
├── modlogs.js
└── warnModel.js
├── index.js
├── package.json
├── handler
├── index.js
└── functions.js
├── README.md
└── LICENSE
/config.example.json:
--------------------------------------------------------------------------------
1 | {
2 | "token": "",
3 | "mongooseConnectionString": "",
4 | "fail": "",
5 | "success": "",
6 | "ban": ""
7 | }
--------------------------------------------------------------------------------
/events/ready.js:
--------------------------------------------------------------------------------
1 | const client = require("../index");
2 |
3 | client.on("ready", () => {
4 | client.user.setActivity(`${client.guilds.cache.size} guilds`, {
5 | type: "COMPETING",
6 | });
7 | console.log(`✔️ ${client.user.tag}`);
8 | });
9 |
--------------------------------------------------------------------------------
/SlashCommands/Info/ping.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: "ping",
3 | description: "websocket ping",
4 | category: "info",
5 |
6 | run: async (client, interaction) => {
7 | interaction.followUp({ content: `${client.ws.ping} ms` });
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/models/modlogs.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const modLogModel = mongoose.model(
4 | "modlogs",
5 | new mongoose.Schema({
6 | Guild: { type: String },
7 | Channel: { type: String },
8 | Enabled: { type: Boolean, default: false },
9 | })
10 | );
11 |
12 | module.exports = modLogModel;
13 |
--------------------------------------------------------------------------------
/models/warnModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | module.exports = mongoose.model(
4 | "warnings",
5 | new mongoose.Schema({
6 | userId: { type: String },
7 | guildId: { type: String },
8 | moderatorId: { type: String },
9 | reason: { type: String },
10 | timestamp: { type: Number },
11 | })
12 | );
13 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const { Client, Collection } = require("discord.js");
2 |
3 | const client = new Client({
4 | intents: 32767,
5 | });
6 | module.exports = client;
7 |
8 | client.slashCommands = new Collection();
9 | client.config = require("./config.json");
10 | client.setMaxListeners(50);
11 | require("events").defaultMaxListeners = 50;
12 |
13 | require("./handler")(client);
14 |
15 | client.login(client.config.token);
16 |
--------------------------------------------------------------------------------
/events/messageCreate.js:
--------------------------------------------------------------------------------
1 | const client = require("../index");
2 |
3 | client.on("messageCreate", async (message) => {
4 | if (
5 | message.content === `<@${client.user.id}>` ||
6 | message.content === `<@!${client.user.id}>`
7 | )
8 | return message.channel.send({
9 | content: `Hi ${message.author} I'm **${client.user.username}**\nA powerful slash Moderation Discord bot`,
10 | });
11 |
12 | if (message.author.bot || !message.guild) return;
13 | });
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leaf",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "test": "nodemon index.js"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "Apache-2.0",
13 | "dependencies": {
14 | "discord.js": "^13.6.0",
15 | "glob": "^7.2.0",
16 | "leaf-utils": "^1.1.3",
17 | "mongoose": "^6.1.4",
18 | "ms": "^2.1.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/handler/index.js:
--------------------------------------------------------------------------------
1 | const { glob } = require("glob");
2 | const { promisify } = require("util");
3 | const { Client } = require("discord.js");
4 | const mongoose = require("mongoose");
5 |
6 | const globPromise = promisify(glob);
7 |
8 | module.exports = async (client) => {
9 |
10 | const eventFiles = await globPromise(`${process.cwd()}/events/*.js`);
11 | eventFiles.map((value) => require(value));
12 |
13 |
14 | const slashCommands = await globPromise(
15 | `${process.cwd()}/SlashCommands/*/*.js`
16 | );
17 |
18 | const arrayOfSlashCommands = [];
19 | slashCommands.map((value) => {
20 | const file = require(value);
21 | if (!file?.name) return;
22 | client.slashCommands.set(file.name, file);
23 |
24 | if (["MESSAGE", "USER"].includes(file.type)) delete file.description;
25 | arrayOfSlashCommands.push(file);
26 | });
27 | client.on("ready", async () => {
28 | await client.application.commands.set(arrayOfSlashCommands);
29 | });
30 |
31 | const { mongooseConnectionString } = require('../config.json')
32 | if (!mongooseConnectionString) return;
33 |
34 | mongoose.connect(mongooseConnectionString).then(() => console.log('✔️ MongoDB'));
35 | };
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Moderation Discord Bot
3 |
4 |
5 |
6 | [](https://discord.gg/yfD2Vmnr6F)
7 |
8 |
9 | ## About
10 | A powerful Slash `Moderation` Discord Bot
11 |
12 | ## Installation
13 | To get started clone this repository and run `npm install`.
14 |
15 | ## Setting Up
16 | Rename `config.example.json` to `config.json` and fill the parameters
17 | ```
18 | {
19 | "token": "your_bot_token",
20 | "mongooseConnectionString": "mongoURI",
21 | // emojis
22 | "fail": "",
23 | "success": "",
24 | "ban": ""
25 | }
26 | ```
27 |
28 | Invite your Discord Bot with `bot` and `applications.commands` scope
29 |
30 | ## Note
31 | It can take up to 1 hour until the slash commands are displayed
32 |
33 | ## Projects
34 | - [Youtube](https://www.youtube.com/channel/UC9yRVadElzxSO3ZUywK6Yig) - My `Youtube Channel`
35 | - [Discord Server](https://discord.gg/yfD2Vmnr6F) - My `Discord Server`
36 | - [GitHub](https://github.com/notLeaf/leaf-utils) - Leaf-utils `Github`
37 | - [NPM](https://www.npmjs.com/package/leaf-utils) - Leaf-utils `NPM`
38 |
39 | ## Preview
40 | if you’re looking for a preview of the bot, check out my [youtube video](https://youtu.be/6t1Dp2iC_oc)
41 |
--------------------------------------------------------------------------------
/events/interactionCreate.js:
--------------------------------------------------------------------------------
1 | const { fail } = require("../config.json");
2 | const client = require("../index");
3 |
4 | client.on("interactionCreate", async (interaction) => {
5 | if (interaction.isCommand()) {
6 | await interaction.deferReply({ ephemeral: false }).catch(() => {});
7 |
8 | const cmd = client.slashCommands.get(interaction.commandName);
9 | if (!cmd)
10 | return interaction.followUp({ content: "An error has occured " });
11 |
12 | const args = [];
13 |
14 | for (let option of interaction.options.data) {
15 | if (option.type === "SUB_COMMAND") {
16 | if (option.name) args.push(option.name);
17 | option.options?.forEach((x) => {
18 | if (x.value) args.push(x.value);
19 | });
20 | } else if (option.value) args.push(option.value);
21 | }
22 | interaction.member = interaction.guild.members.cache.get(
23 | interaction.user.id
24 | );
25 |
26 | if (
27 | !interaction.guild.roles.everyone.permissions.has(
28 | "USE_EXTERNAL_EMOJIS"
29 | )
30 | ) {
31 | return interaction.followUp({
32 | content:
33 | "The `@everyone` role is missing the Permission to `USE_EXTERNAL_EMOJIS`, enable it",
34 | });
35 | }
36 |
37 | cmd.run(client, interaction, args);
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/lock.js:
--------------------------------------------------------------------------------
1 | const { modLog } = require("../../handler/functions");
2 | const { fail, success } = require("../../config.json");
3 |
4 | module.exports = {
5 | name: "lock",
6 | description: "locks a channel",
7 | category: "mod",
8 | options: [
9 | {
10 | name: "channel",
11 | description: "channel to lock",
12 | type: "CHANNEL",
13 | channelTypes: ["GUILD_TEXT"],
14 | required: true,
15 | },
16 | {
17 | name: "reason",
18 | description: "reason for this lock",
19 | type: "STRING",
20 | required: false,
21 | },
22 | ],
23 |
24 | run: async (client, interaction) => {
25 | const channel = interaction.options.getChannel("channel");
26 | const reason =
27 | interaction.options.getString("reason") || "`No Reason Provided`";
28 |
29 | if (
30 | !channel
31 | .permissionsFor(interaction.guild.roles.everyone)
32 | .has("SEND_MESSAGES")
33 | )
34 | return interaction.followUp({
35 | content: `${fail} ${channel} is already locked`,
36 | });
37 |
38 | channel.permissionOverwrites.edit(interaction.guild.id, {
39 | SEND_MESSAGES: false,
40 | });
41 |
42 | interaction.editReply({
43 | content: `${success} ${channel} locked successfully!`,
44 | });
45 |
46 | modLog(interaction, reason, {
47 | Action: "`Lock`",
48 | Channel: `${channel}`,
49 | });
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/unlock.js:
--------------------------------------------------------------------------------
1 | const { modLog } = require("../../handler/functions");
2 | const { fail, success } = require("../../config.json");
3 |
4 | module.exports = {
5 | name: "unlock",
6 | description: "unlocks a channel",
7 | category: "mod",
8 | options: [
9 | {
10 | name: "channel",
11 | description: "channel to lock",
12 | type: "CHANNEL",
13 | channelTypes: ["GUILD_TEXT"],
14 | required: true,
15 | },
16 | {
17 | name: "reason",
18 | description: "reason for this unlock",
19 | type: "STRING",
20 | required: false,
21 | },
22 | ],
23 |
24 | run: async (client, interaction) => {
25 | const channel = interaction.options.getChannel("channel");
26 | const reason =
27 | interaction.options.getString("reason") || "`No Reason Provided`";
28 |
29 | if (
30 | channel
31 | .permissionsFor(interaction.guild.roles.everyone)
32 | .has("SEND_MESSAGES")
33 | )
34 | return interaction.followUp({
35 | content: `${fail} ${channel} is not locked`,
36 | });
37 |
38 | channel.permissionOverwrites.edit(interaction.guild.id, {
39 | SEND_MESSAGES: true,
40 | });
41 |
42 | interaction.editReply({
43 | content: `${success} ${channel} unlocked successfully!`,
44 | });
45 |
46 | modLog(interaction, reason, {
47 | Action: "`Unlock`",
48 | Channel: `${channel}`,
49 | });
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/SlashCommands/Config/setmodlogs.js:
--------------------------------------------------------------------------------
1 | const { fail, success } = require("../../config.json");
2 | const modLogModel = require("../../models/modlogs");
3 |
4 | module.exports = {
5 | name: "modlogs",
6 | description: "sets the modlog channel",
7 | category: "config",
8 | options: [
9 | {
10 | name: "enable",
11 | description: "enable the modlogs system",
12 | type: "SUB_COMMAND",
13 | options: [
14 | {
15 | name: "channel",
16 | description: "modlogs channel",
17 | type: "CHANNEL",
18 | channelTypes: ["GUILD_TEXT"],
19 | required: true,
20 | },
21 | ],
22 | },
23 | {
24 | name: "disable",
25 | description: "disable the modlogs system",
26 | type: "SUB_COMMAND",
27 | },
28 | ],
29 |
30 | run: async (client, interaction) => {
31 | const data =
32 | (await modLogModel.findOne({
33 | Guild: interaction.guildId,
34 | })) ||
35 | (await modLogModel.create({
36 | Guild: interaction.guildId,
37 | }));
38 | channel = interaction.options.getChannel("channel");
39 | command = interaction.options.getSubcommand();
40 |
41 | if (command === "enable") {
42 | if (data.Channel === channel.id)
43 | return interaction.followUp({
44 | content: `${fail} This is already the modlogs channel`,
45 | });
46 |
47 | data.Channel = channel.id;
48 | data.Enabled = true;
49 | data.save();
50 |
51 | interaction.followUp({
52 | content: `${success} Logs have been set to ${channel}`,
53 | });
54 | } else if (command === "disable") {
55 | if (data.Enabled !== true)
56 | return interaction.followUp({
57 | content: `${fail} Modlogs system is already disabled`,
58 | });
59 |
60 | data.Channel = null;
61 | data.Enabled = false;
62 | data.save();
63 |
64 | interaction.followUp({
65 | content: `${success} Modlogs system has been disabled`,
66 | });
67 | }
68 | },
69 | };
70 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/unwarn.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 | const warnModel = require("../../models/warnModel");
9 |
10 | module.exports = {
11 | name: "unwarn",
12 | description: "unwarns a member in your server",
13 | category: "mod",
14 | options: [
15 | {
16 | name: "warnid",
17 | description: "warnId you want to delete",
18 | type: "STRING",
19 | required: true,
20 | },
21 | {
22 | name: "reason",
23 | description: "reason for this warn",
24 | type: "STRING",
25 | required: false,
26 | },
27 | ],
28 |
29 | run: async (client, interaction) => {
30 | try {
31 | const warnId = interaction.options.getString("warnid");
32 | data = await warnModel.findById(warnId);
33 | user = interaction.guild.members.cache.get(data.userId);
34 | reason =
35 | interaction.options.getString("reason") ||
36 | "`No Reason Provided`";
37 |
38 | const embed = new MessageEmbed()
39 | .setAuthor({
40 | name: `${interaction.user.tag}`,
41 | iconURL: interaction.user.displayAvatarURL({
42 | dynamic: true,
43 | }),
44 | })
45 | .setDescription(
46 | `**${interaction.user.tag}** are you sure you want to unwarn ${user}`
47 | )
48 | .setFooter({
49 | text: client.user.tag,
50 | iconURL: client.user.displayAvatarURL(),
51 | })
52 | .setColor(randomHex())
53 | .setTimestamp();
54 |
55 | confirmButtons(interaction, {
56 | embed: embed,
57 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
58 | yes: {
59 | style: "PRIMARY",
60 | label: "Unwarn",
61 | emoji: "✔️",
62 | },
63 | no: {
64 | style: "SECONDARY",
65 | label: "Cancel",
66 | emoji: "🛑",
67 | },
68 | }).then(async (confirm) => {
69 | if (confirm === "yes") {
70 | await data.delete();
71 | interaction.editReply({
72 | content: `${success} Unwarned **${user}** successfully!`,
73 | });
74 | modLog(interaction, reason, {
75 | Action: "`Unwarn`",
76 | Member: `${user}`,
77 | });
78 | }
79 | if (confirm === "no") {
80 | interaction.editReply({
81 | content: `${fail} cancelled!`,
82 | });
83 | }
84 | if (confirm === "time") {
85 | interaction.editReply({
86 | content: `${fail} Time is up`,
87 | });
88 | }
89 | });
90 | } catch (e) {
91 | return interaction.followUp({
92 | content: `${fail} This is not a valid warnID`,
93 | });
94 | }
95 | },
96 | };
97 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/slowmode.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const { modLog, randomHex } = require("../../handler/functions");
3 | const { fail } = require("../../config.json");
4 | const ms = require("ms");
5 |
6 | module.exports = {
7 | name: "slowmode",
8 | description: "slowmode command",
9 | category: "mod",
10 | options: [
11 | {
12 | name: "rate",
13 | description: "rate limit between 1 and 21600",
14 | type: "INTEGER",
15 | required: true,
16 | choices: [
17 | { name: "off", value: 0 },
18 | { name: "5 seconds", value: 5 },
19 | { name: "10 seconds", value: 10 },
20 | { name: "15 seconds", value: 15 },
21 | { name: "30 seconds", value: 30 },
22 | { name: "1 minute", value: 60 },
23 | { name: "2 minutes", value: 120 },
24 | { name: "5 minutes", value: 300 },
25 | { name: "10 minutes", value: 600 },
26 | { name: "15 minutes", value: 900 },
27 | { name: "30 minutes", value: 1800 },
28 | { name: "1 hour", value: 3600 },
29 | { name: "2 hours", value: 7200 },
30 | { name: "6 hours", value: 21600 },
31 | ],
32 | },
33 | {
34 | name: "channel",
35 | description:
36 | "enables slowmode in a channel with the specified rate",
37 | type: "CHANNEL",
38 | channelTypes: ["GUILD_TEXT"],
39 | required: false,
40 | },
41 | {
42 | name: "reason",
43 | description: "reason for this slowmode",
44 | type: "STRING",
45 | required: false,
46 | },
47 | ],
48 |
49 | run: async (client, interaction) => {
50 | const rate = interaction.options.getInteger("rate");
51 | channel =
52 | interaction.options.getChannel("channel") || interaction.channel;
53 | reason =
54 | interaction.options.getString("reason") || "`No Reason Provided`";
55 |
56 | if (rate === 0 && !channel.rateLimitPerUser)
57 | return interaction.followUp({
58 | content: `${fail} Slowmode is already off`,
59 | });
60 |
61 | await channel.setRateLimitPerUser(rate, reason);
62 |
63 | const embed = new MessageEmbed()
64 | .setTitle("Slowmode")
65 | .setFooter({
66 | text: client.user.tag,
67 | iconURL: client.user.displayAvatarURL(),
68 | })
69 | .setTimestamp()
70 | .setColor(randomHex());
71 |
72 | interaction.followUp({
73 | embeds: [
74 | embed
75 | .addField("Moderator", `\`${interaction.user.tag}\``, true)
76 | .addField("Channel", `${channel}`, true)
77 | .addField(
78 | "Rate",
79 | rate > 0
80 | ? `\`${ms(rate * 1e3, { long: true })}\``
81 | : "`off`",
82 | true
83 | )
84 | .addField("Reason", `${reason}`),
85 | ],
86 | });
87 |
88 | modLog(interaction, reason, {
89 | Action: "`Slowmode`",
90 | Channel: `${channel}`,
91 | Rate: rate > 0 ? `\`${ms(rate * 1e3, { long: true })}\`` : "`off`",
92 | });
93 | },
94 | };
95 |
--------------------------------------------------------------------------------
/SlashCommands/Info/help.js:
--------------------------------------------------------------------------------
1 | const { SelectMenus } = require("leaf-utils");
2 |
3 | module.exports = {
4 | name: "help",
5 | description: "Displays a list of all current commands",
6 | category: "info",
7 |
8 | run: async (client, interaction) => {
9 | const pages = [
10 | {
11 | title: client.user.username + "'s commands",
12 | description: "Click this menu for more info",
13 | footer: {
14 | text: client.user.tag,
15 | icon_url: client.user.displayAvatarURL(),
16 | },
17 | color: interaction.guild.me.displayHexColor,
18 | timestamp: new Date(),
19 | },
20 | {
21 | title: "Config command",
22 | description: client.slashCommands
23 | .filter((cmd) => cmd.category === "config")
24 | .map((cmd) => `\`${cmd.name}\``)
25 | .join(", "),
26 | footer: {
27 | text: client.user.tag,
28 | icon_url: client.user.displayAvatarURL(),
29 | },
30 | color: "#F3AA05",
31 | timestamp: new Date(),
32 | },
33 | {
34 | title: "Info commands",
35 | description: client.slashCommands
36 | .filter((cmd) => cmd.category === "info")
37 | .map((cmd) => `\`${cmd.name}\``)
38 | .join(", "),
39 | footer: {
40 | text: client.user.tag,
41 | icon_url: client.user.displayAvatarURL(),
42 | },
43 | color: "#F3AA05",
44 | timestamp: new Date(),
45 | },
46 | {
47 | title: "Mod commands",
48 | description: client.slashCommands
49 | .filter((cmd) => cmd.category === "mod")
50 | .map((cmd) => `\`${cmd.name}\``)
51 | .join(", "),
52 | footer: {
53 | text: client.user.tag,
54 | icon_url: client.user.displayAvatarURL(),
55 | },
56 | color: "#F3AA05",
57 | timestamp: new Date(),
58 | },
59 | ],
60 | options = [
61 | {
62 | label: "Home",
63 | emoji: "🏠",
64 | },
65 | {
66 | label: "Configuration",
67 | emoji: "⚙️",
68 | },
69 | {
70 | label: "Info",
71 | emoji: "ℹ️",
72 | },
73 | {
74 | label: "Moderation",
75 | emoji: "🔨",
76 | },
77 | ];
78 |
79 | await SelectMenus({
80 | message: interaction,
81 | slash_command: true,
82 | time: 300000,
83 | pages: pages,
84 | options: options,
85 | authorOnly: {
86 | enabled: true,
87 | ephemeral: true,
88 | authorMessage: "Only <@{{author}}> can use this menu",
89 | },
90 | placeholder: "Help Menu",
91 | });
92 | },
93 | };
94 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/unban.js:
--------------------------------------------------------------------------------
1 | const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "unban",
11 | description: "unbans a member from your server",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "userid",
16 | description: "userid you want to unban",
17 | type: "STRING",
18 | required: true,
19 | },
20 | {
21 | name: "reason",
22 | description: "reason for this unban",
23 | type: "STRING",
24 | required: false,
25 | },
26 | ],
27 |
28 | run: async (client, interaction) => {
29 | try {
30 | const id = interaction.options.getString("userid");
31 | reason =
32 | interaction.options.getString("reason") ||
33 | "`No Reason Provided`";
34 | user = await client.users.fetch(id);
35 | bans = await interaction.guild.bans.fetch();
36 | bannedusers = bans.find((b) => b.user.id == id);
37 |
38 | if (!bannedusers)
39 | return interaction.followUp({
40 | content: `${fail} \`${user.tag}\` is not banned`,
41 | });
42 |
43 | const embed = new MessageEmbed()
44 | .setAuthor({
45 | name: `${interaction.user.tag}`,
46 | iconURL: interaction.user.displayAvatarURL({
47 | dynamic: true,
48 | }),
49 | })
50 | .setDescription(
51 | `**${interaction.user.tag}** are you sure you want to unban **${user.tag}**`
52 | )
53 | .setFooter({
54 | text: client.user.tag,
55 | iconURL: client.user.displayAvatarURL(),
56 | })
57 | .setColor(randomHex())
58 | .setTimestamp();
59 |
60 | confirmButtons(interaction, {
61 | embed: embed,
62 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
63 | yes: {
64 | style: "SUCCESS",
65 | label: "Unban",
66 | emoji: "✔️",
67 | },
68 | no: {
69 | style: "SECONDARY",
70 | label: "Cancel",
71 | emoji: "🛑",
72 | },
73 | }).then(async (confirm) => {
74 | if (confirm === "yes") {
75 | await interaction.guild.members.unban(user, reason);
76 | interaction.editReply({
77 | content: `${success} Unbanned **${user.tag}** successfully!`,
78 | });
79 | modLog(interaction, reason, {
80 | Action: "`Unban`",
81 | Member: `\`${user.tag}\``,
82 | });
83 | }
84 | if (confirm === "no") {
85 | interaction.editReply({
86 | content: `${fail} cancelled!`,
87 | });
88 | }
89 | if (confirm === "time") {
90 | interaction.editReply({
91 | content: `${fail} Time is up`,
92 | });
93 | }
94 | });
95 | } catch (e) {
96 | return interaction.followUp({
97 | content: `${fail} This is not a valid user`,
98 | });
99 | }
100 | },
101 | };
102 |
--------------------------------------------------------------------------------
/SlashCommands/Info/userinfo.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const statuses = {
3 | online: `\`Online\``,
4 | idle: `\`AFK\``,
5 | undefined: `\`Offline\``, // offline members don't have a presence
6 | dnd: `\`Do Not Disturb\``,
7 | };
8 | const flags = {
9 | DISCORD_EMPLOYEE: `\`Discord Employee\``,
10 | DISCORD_PARTNER: `\`Partnered Server Owner\``,
11 | BUGHUNTER_LEVEL_1: `\`Bug Hunter (Level 1)\``,
12 | BUGHUNTER_LEVEL_2: `\`Bug Hunter (Level 2)\``,
13 | HYPESQUAD_EVENTS: `\`HypeSquad Events\``,
14 | HOUSE_BRAVERY: `\`House of Bravery\``,
15 | HOUSE_BRILLIANCE: `\`House of Brilliance\``,
16 | HOUSE_BALANCE: `\`House of Balance\``,
17 | EARLY_SUPPORTER: `\`Early Supporter\``,
18 | TEAM_USER: "Team User",
19 | SYSTEM: "System",
20 | VERIFIED_BOT: `\`Verified Bot\``,
21 | VERIFIED_DEVELOPER: `\`Early Verified Bot Developer\``,
22 | };
23 |
24 | module.exports = {
25 | name: "userinfo",
26 | description: "Displays the userinfo of the specified target.",
27 | category: "info",
28 | options: [
29 | {
30 | name: "target",
31 | description: "Select the target.",
32 | type: "USER",
33 | required: false,
34 | },
35 | ],
36 |
37 | run: async (client, interaction) => {
38 | const member =
39 | interaction.options.getMember("target") || interaction.member;
40 | const userFlags = (await member.user.fetchFlags()).toArray();
41 |
42 | const embed = new MessageEmbed()
43 | .setAuthor({
44 | name: `${member.user.tag}`,
45 | iconURL: member.user.displayAvatarURL({
46 | dynamic: true,
47 | }),
48 | })
49 | .addField(
50 | "Joined server",
51 | ``,
52 | true
53 | )
54 | .addField(
55 | "Joined Discord",
56 | ``,
57 | true
58 | )
59 | .addField("Highest Role", `${member.roles.highest}`, true)
60 | .addField("Status", `${statuses[member.presence?.status]}`, true)
61 | .addField("Bot", `\`${member.user.bot}\``, true)
62 | .setThumbnail(member.user.displayAvatarURL({ dynamic: true }))
63 | .setFooter({
64 | text: "ID: " + member.id,
65 | })
66 | .setColor("RED")
67 | .setTimestamp();
68 |
69 | if (member.presence?.activities) {
70 | const activitytype = {
71 | PLAYING: "Playing",
72 | STREAMING: "Streaming",
73 | LISTENING: "Listening",
74 | WATCHING: "Watching",
75 | CUSTOM: "Custom Status",
76 | COMPETING: "Competing",
77 | };
78 |
79 | let activitystring = ``;
80 | member.presence.activities.forEach((activity) => {
81 | activitystring += `\n**${activitytype[activity.type]}**${
82 | activity.name == `Custom Status`
83 | ? `\n${activity.state}`
84 | : `\n${activity.name} ${
85 | activity.details
86 | ? `- \`${activity.details}\``
87 | : ``
88 | }`
89 | }`;
90 | });
91 | if (activitystring.length > 0) embed.setDescription(activitystring);
92 | }
93 |
94 | if (userFlags.length > 0)
95 | embed.addField(
96 | "Badges",
97 | userFlags.map((flag) => flags[flag]).join("\n")
98 | );
99 |
100 | interaction.followUp({
101 | embeds: [embed],
102 | });
103 | },
104 | };
105 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/ban.js:
--------------------------------------------------------------------------------
1 | const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, ban } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "ban",
11 | description: "ban a member",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "target",
16 | description: "target to ban",
17 | type: "USER",
18 | required: true,
19 | },
20 | {
21 | name: "reason",
22 | description: "reason for this ban",
23 | type: "STRING",
24 | required: false,
25 | },
26 | ],
27 |
28 | run: async (client, interaction) => {
29 | const target = interaction.options.getMember("target");
30 | const reason =
31 | interaction.options.getString("reason") || "`No Reason Provided`";
32 |
33 | if (target.id === interaction.member.id)
34 | return interaction.followUp({
35 | content: `${fail} You cant ban yourself`,
36 | });
37 |
38 | if (target.id === interaction.guild.me.id)
39 | return interaction.followUp({
40 | content: `${fail} You cant ban me`,
41 | });
42 |
43 | if (target.id === interaction.guild.ownerId)
44 | return interaction.followUp({
45 | content: `${fail} You cannot ban the server owner`,
46 | });
47 |
48 | if (
49 | target.roles.highest.position >=
50 | interaction.member.roles.highest.position
51 | )
52 | return interaction.followUp({
53 | content: `${fail} This user is higher/equal than you`,
54 | });
55 |
56 | if (
57 | target.roles.highest.position >=
58 | interaction.guild.me.roles.highest.position
59 | )
60 | return interaction.followUp({
61 | content: `${fail} This user is higher/equal than me`,
62 | });
63 |
64 | const embed = new MessageEmbed()
65 | .setAuthor({
66 | name: `${interaction.user.tag}`,
67 | iconURL: interaction.user.displayAvatarURL({
68 | dynamic: true,
69 | }),
70 | })
71 | .setDescription(
72 | `**${interaction.user.tag}** are you sure you want to ban **${target.user.tag}**`
73 | )
74 | .setFooter({
75 | text: client.user.tag,
76 | iconURL: client.user.displayAvatarURL(),
77 | })
78 | .setColor(randomHex())
79 | .setTimestamp();
80 |
81 | confirmButtons(interaction, {
82 | embed: embed,
83 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
84 | yes: {
85 | style: "PRIMARY",
86 | label: "Ban",
87 | emoji: `${ban}`,
88 | },
89 | no: {
90 | style: "SECONDARY",
91 | label: "No",
92 | emoji: "🛑",
93 | },
94 | }).then(async (confirm) => {
95 | if (confirm === "yes") {
96 | await target.ban({
97 | reason,
98 | });
99 | interaction.editReply({
100 | content: `${ban} Banned **${target.user.tag}** successfully!`,
101 | });
102 | modLog(interaction, reason, {
103 | Action: "`Ban`",
104 | Member: `\`${target.user.tag}\``,
105 | });
106 | }
107 | if (confirm === "no") {
108 | interaction.editReply({
109 | content: `${fail} **${target.user.tag}** hasn't been banned!`,
110 | });
111 | }
112 | if (confirm === "time") {
113 | interaction.editReply({
114 | content: `${fail} Time is up`,
115 | });
116 | }
117 | });
118 | },
119 | };
120 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/kick.js:
--------------------------------------------------------------------------------
1 | const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "kick",
11 | description: "kick a member",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "target",
16 | description: "target to kick",
17 | type: "USER",
18 | required: true,
19 | },
20 | {
21 | name: "reason",
22 | description: "reason for this kick",
23 | type: "STRING",
24 | required: false,
25 | },
26 | ],
27 |
28 | run: async (client, interaction) => {
29 | const target = interaction.options.getMember("target");
30 | const reason =
31 | interaction.options.getString("reason") || "`No Reason Provided`";
32 |
33 | if (target.id === interaction.member.id)
34 | return interaction.followUp({
35 | content: `${fail} You cant kick yourself`,
36 | });
37 |
38 | if (target.id === interaction.guild.me.id)
39 | return interaction.followUp({
40 | content: `${fail} You cant kick me`,
41 | });
42 |
43 | if (target.id === interaction.guild.ownerId)
44 | return interaction.followUp({
45 | content: `${fail} You cannot kick the server owner`,
46 | });
47 |
48 | if (
49 | target.roles.highest.position >=
50 | interaction.member.roles.highest.position
51 | )
52 | return interaction.followUp({
53 | content: `${fail} This user is higher/equal than you`,
54 | });
55 |
56 | if (
57 | target.roles.highest.position >=
58 | interaction.guild.me.roles.highest.position
59 | )
60 | return interaction.followUp({
61 | content: `${fail} This user is higher/equal than me`,
62 | });
63 |
64 | const embed = new MessageEmbed()
65 | .setAuthor({
66 | name: `${interaction.user.tag}`,
67 | iconURL: interaction.user.displayAvatarURL({
68 | dynamic: true,
69 | }),
70 | })
71 | .setDescription(
72 | `**${interaction.user.tag}** are you sure you want to kick **${target.user.tag}**`
73 | )
74 | .setFooter({
75 | text: client.user.tag,
76 | iconURL: client.user.displayAvatarURL(),
77 | })
78 | .setColor(randomHex())
79 | .setTimestamp();
80 |
81 | confirmButtons(interaction, {
82 | embed: embed,
83 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
84 | yes: {
85 | style: "SUCCESS",
86 | label: "Kick",
87 | emoji: "✔️",
88 | },
89 | no: {
90 | style: "SECONDARY",
91 | label: "No",
92 | emoji: "🛑",
93 | },
94 | }).then(async (confirm) => {
95 | if (confirm === "yes") {
96 | await target.kick(reason);
97 | interaction.editReply({
98 | content: `${success} Kicked **${target.user.tag}** successfully!`,
99 | });
100 | modLog(interaction, reason, {
101 | Action: "`Kick`",
102 | Member: `\`${target.user.tag}\``,
103 | });
104 | }
105 | if (confirm === "no") {
106 | interaction.editReply({
107 | content: `${fail} **${target.user.tag}** hasn't been kicked!`,
108 | });
109 | }
110 | if (confirm === "time") {
111 | interaction.editReply({
112 | content: `${fail} Time is up`,
113 | });
114 | }
115 | });
116 | },
117 | };
118 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/clear.js:
--------------------------------------------------------------------------------
1 | const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
2 | const { modLog, randomHex } = require("../../handler/functions");
3 | const { fail } = require("../../config.json");
4 |
5 | module.exports = {
6 | name: "clear",
7 | description: "deletes messages",
8 | category: "mod",
9 | options: [
10 | {
11 | name: "amount",
12 | description: "Select the amount messages to delete",
13 | type: "INTEGER",
14 | required: true,
15 | },
16 | {
17 | name: "channel",
18 | description: "channel to delete messages",
19 | type: "CHANNEL",
20 | required: false,
21 | },
22 | {
23 | name: "target",
24 | description: "Select a target to clear their messages",
25 | type: "USER",
26 | required: false,
27 | },
28 | {
29 | name: "reason",
30 | description: "reason for this purge",
31 | type: "STRING",
32 | required: false,
33 | },
34 | ],
35 |
36 | run: async (client, interaction) => {
37 | const channel =
38 | interaction.options.getChannel("channel") || interaction.channel;
39 | member = interaction.options.getMember("target");
40 | amount = interaction.options.getInteger("amount");
41 | reason =
42 | interaction.options.getString("reason") || "`No Reason Provided`";
43 |
44 | if (amount < 0 || amount > 100)
45 | return interaction.followUp({
46 | content: `${fail} You can only delete 100 messages at once`,
47 | });
48 |
49 | if (!channel.isText())
50 | return interaction.followUp({
51 | content: `${fail} Please select a text channel`,
52 | });
53 |
54 | let messages;
55 | if (member) {
56 | messages = (
57 | await channel.messages.fetch({
58 | limit: amount,
59 | })
60 | ).filter((m) => m.member.id === member.id);
61 | } else messages = amount;
62 |
63 | if (messages.size === 0) {
64 | return interaction.followup({
65 | content: `${fail} Unable to find any messages from ${member}`,
66 | });
67 | } else {
68 | await channel.bulkDelete(messages, true).then((messages) => {
69 | const embed = new MessageEmbed()
70 | .setDescription(
71 | `
72 | Successfully deleted **${messages.size}** message(s).
73 | `
74 | )
75 | .addField("Channel", `${channel}`, true)
76 | .addField("Message Count", `\`${messages.size}\``, true)
77 | .addField("Reason", `${reason}`, true)
78 | .setTimestamp()
79 | .setColor(randomHex());
80 |
81 | if (member) {
82 | embed
83 | .spliceFields(1, 1, {
84 | name: "Found Messages",
85 | value: `\`${messages.size}\``,
86 | inline: true,
87 | })
88 | .spliceFields(1, 0, {
89 | name: "Member",
90 | value: `${member}`,
91 | inline: true,
92 | });
93 | }
94 | interaction
95 | .editReply({
96 | embeds: [embed],
97 | })
98 | .catch(() => {});
99 | });
100 | }
101 |
102 | const fields = {
103 | Action: "`Clear`",
104 | Channel: `${channel}`,
105 | };
106 |
107 | if (member) {
108 | fields["Member"] = `${member}`;
109 | fields["Found Messages"] = `\`${messages.size}\``;
110 | } else fields["Message Count"] = `\`${amount}\``;
111 |
112 | modLog(interaction, reason, fields);
113 | },
114 | };
115 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/warn.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 | const warnModel = require("../../models/warnModel");
9 |
10 | module.exports = {
11 | name: "warn",
12 | description: "warns a member in your server",
13 | category: "mod",
14 | options: [
15 | {
16 | name: "target",
17 | description: "target to warn",
18 | type: "USER",
19 | required: true,
20 | },
21 | {
22 | name: "reason",
23 | description: "reason for this warn",
24 | type: "STRING",
25 | required: false,
26 | },
27 | ],
28 |
29 | run: async (client, interaction) => {
30 | const target = interaction.options.getMember("target");
31 | const reason =
32 | interaction.options.getString("reason") || "`No Reason Provided`";
33 |
34 | if (target.id === interaction.member.id)
35 | return interaction.followUp({
36 | content: `${fail} You cant warn yourself`,
37 | });
38 |
39 | if (target.id === interaction.guild.me.id)
40 | return interaction.followUp({
41 | content: `${fail} You cant warn me`,
42 | });
43 |
44 | if (target.id === interaction.guild.ownerId)
45 | return interaction.followUp({
46 | content: `${fail} You cannot warn the server owner`,
47 | });
48 |
49 | if (
50 | target.roles.highest.position >=
51 | interaction.member.roles.highest.position
52 | )
53 | return interaction.followUp({
54 | content: `${fail} This user is higher/equal than you`,
55 | });
56 |
57 | if (
58 | target.roles.highest.position >=
59 | interaction.guild.me.roles.highest.position
60 | )
61 | return interaction.followUp({
62 | content: `${fail} This user is higher/equal than me`,
63 | });
64 |
65 | const embed = new MessageEmbed()
66 | .setAuthor({
67 | name: `${interaction.user.tag}`,
68 | iconURL: interaction.user.displayAvatarURL({
69 | dynamic: true,
70 | }),
71 | })
72 | .setDescription(
73 | `**${interaction.user.tag}** are you sure you want to warn **${target.user.tag}**`
74 | )
75 | .setFooter({
76 | text: client.user.tag,
77 | iconURL: client.user.displayAvatarURL(),
78 | })
79 | .setColor(randomHex())
80 | .setTimestamp();
81 |
82 | confirmButtons(interaction, {
83 | embed: embed,
84 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
85 | yes: {
86 | style: "PRIMARY",
87 | label: "Warn",
88 | emoji: "✔️",
89 | },
90 | no: {
91 | style: "SECONDARY",
92 | label: "No",
93 | emoji: "🛑",
94 | },
95 | }).then(async (confirm) => {
96 | if (confirm === "yes") {
97 | await new warnModel({
98 | userId: target.id,
99 | guildId: interaction.guildId,
100 | moderatorId: interaction.user.id,
101 | reason,
102 | timestamp: Date.now(),
103 | }).save();
104 | interaction.editReply({
105 | content: `${success} Warned **${target.user.tag}** successfully!`,
106 | });
107 | modLog(interaction, reason, {
108 | Action: "`Warn`",
109 | Member: `${target}`,
110 | });
111 | }
112 | if (confirm === "no") {
113 | interaction.editReply({
114 | content: `${fail} **${target.user.tag}** hasn't been warned!`,
115 | });
116 | }
117 | if (confirm === "time") {
118 | interaction.editReply({
119 | content: `${fail} Time is up`,
120 | });
121 | }
122 | });
123 | },
124 | };
125 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/removerole.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "removerole",
11 | description: "removes the specified role from the provided user",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "target",
16 | description: "target to remove role to",
17 | type: "USER",
18 | required: true,
19 | },
20 | {
21 | name: "role",
22 | description: "role to remove",
23 | type: "ROLE",
24 | required: true,
25 | },
26 | {
27 | name: "reason",
28 | description: "reason",
29 | type: "STRING",
30 | required: false,
31 | },
32 | ],
33 |
34 | run: async (client, interaction) => {
35 | const target = interaction.options.getMember("target");
36 | role = interaction.options.getRole("role");
37 | reason =
38 | interaction.options.getString("reason") || "`No Reason Provided`";
39 |
40 | if (
41 | target.roles.highest.position >=
42 | interaction.member.roles.highest.position
43 | )
44 | return interaction.followUp({
45 | content: `${fail} This user is higher/equal than you`,
46 | });
47 |
48 | if (
49 | target.roles.highest.position >=
50 | interaction.guild.me.roles.highest.position
51 | )
52 | return interaction.followUp({
53 | content: `${fail} This user is higher/equal than me`,
54 | });
55 |
56 | if (role.position >= interaction.member.roles.highest.position)
57 | return interaction.followUp({
58 | content: `${fail} That role is higher/equal than you`,
59 | });
60 |
61 | if (role.position >= interaction.guild.me.roles.highest.position)
62 | return interaction.followUp({
63 | content: `${fail} That role is higher/equal than me`,
64 | });
65 |
66 | if (!target.roles.cache.has(role.id))
67 | return interaction.followUp({
68 | content: `${fail} User does not have the provided role`,
69 | });
70 |
71 | const embed = new MessageEmbed()
72 | .setAuthor({
73 | name: `${interaction.user.tag}`,
74 | iconURL: interaction.user.displayAvatarURL({
75 | dynamic: true,
76 | }),
77 | })
78 | .setDescription(
79 | `**${interaction.user.tag}** are you sure you want to remove from **${target.user.tag}** the ${role} role`
80 | )
81 | .setFooter({
82 | text: client.user.tag,
83 | iconURL: client.user.displayAvatarURL(),
84 | })
85 | .setColor(randomHex())
86 | .setTimestamp();
87 |
88 | confirmButtons(interaction, {
89 | embed: embed,
90 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
91 | yes: {
92 | style: "SUCCESS",
93 | label: "Remove",
94 | emoji: "✔️",
95 | },
96 | no: {
97 | style: "SECONDARY",
98 | label: "Cancel",
99 | emoji: "🛑",
100 | },
101 | }).then(async (confirm) => {
102 | if (confirm === "yes") {
103 | await target.roles.remove(role);
104 | interaction.editReply({
105 | content: `${success} **${role.name}** was successfully removed from **${target.user.tag}**`,
106 | });
107 | modLog(interaction, reason, {
108 | Action: "`Remove Role`",
109 | Member: `${target}`,
110 | Role: `${role}`,
111 | });
112 | }
113 | if (confirm === "no") {
114 | interaction.editReply({
115 | content: `${fail} **${target.user.tag}** cancelled!`,
116 | });
117 | }
118 | if (confirm === "time") {
119 | interaction.editReply({
120 | content: `${fail} Time is up`,
121 | });
122 | }
123 | });
124 | },
125 | };
126 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/nickname.js:
--------------------------------------------------------------------------------
1 | const { Client, CommandInteraction, MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "nickname",
11 | description: "changes the provided user's nickname to the one specified",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "target",
16 | description: "target you want to change the nickname",
17 | type: "USER",
18 | required: true,
19 | },
20 | {
21 | name: "nick",
22 | description: "new nickname",
23 | type: "STRING",
24 | required: true,
25 | },
26 | {
27 | name: "reason",
28 | description: "reason for this action",
29 | type: "STRING",
30 | required: false,
31 | },
32 | ],
33 |
34 | run: async (client, interaction) => {
35 | const target = interaction.options.getMember("target");
36 | newnick = interaction.options.getString("nick");
37 | reason =
38 | interaction.options.getString("reason") || "`No Reason Provided`";
39 |
40 | if (target.id === interaction.guild.me.id)
41 | return interaction.followUp({
42 | content: `${fail} You cant change my name`,
43 | });
44 |
45 | if (target.id === interaction.guild.ownerId)
46 | return interaction.followUp({
47 | content: `${fail} You cannot modify the server owner`,
48 | });
49 |
50 | if (
51 | target.roles.highest.position >=
52 | interaction.member.roles.highest.position
53 | )
54 | return interaction.followUp({
55 | content: `${fail} This user is higher/equal than you`,
56 | });
57 |
58 | if (
59 | target.roles.highest.position >=
60 | interaction.guild.me.roles.highest.position
61 | )
62 | return interaction.followUp({
63 | content: `${fail} This user is higher/equal than me`,
64 | });
65 |
66 | if (newnick.length > 32)
67 | return interaction.followUp({
68 | content: `${fail} Please ensure the nickname is no larger than 32 characters`,
69 | });
70 |
71 | const embed = new MessageEmbed()
72 | .setAuthor({
73 | name: `${interaction.user.tag}`,
74 | iconURL: interaction.user.displayAvatarURL({
75 | dynamic: true,
76 | }),
77 | })
78 | .setDescription(
79 | `**${interaction.user.tag}** are you sure you want to change **${target.user.username}**'s nickname`
80 | )
81 | .setFooter({
82 | text: client.user.tag,
83 | iconURL: client.user.displayAvatarURL(),
84 | })
85 | .setColor(randomHex())
86 | .setTimestamp();
87 |
88 | confirmButtons(interaction, {
89 | embed: embed,
90 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
91 | yes: {
92 | style: "PRIMARY",
93 | label: "Yes",
94 | emoji: "✔️",
95 | },
96 | no: {
97 | style: "SECONDARY",
98 | label: "No",
99 | emoji: "🛑",
100 | },
101 | }).then(async (confirm) => {
102 | if (confirm === "yes") {
103 | await target.setNickname(newnick);
104 | interaction.editReply({
105 | content: `${success} **${target.user.username}**'s nickname was successfully updated. **(${newnick})**`,
106 | });
107 | modLog(interaction, reason, {
108 | Action: "`Nickname`",
109 | Member: `${target}`,
110 | Nickname: `\`${newnick}\``,
111 | });
112 | }
113 | if (confirm === "no") {
114 | interaction.editReply({
115 | content: `${fail} cancelled!`,
116 | });
117 | }
118 | if (confirm === "time") {
119 | interaction.editReply({
120 | content: `${fail} Time is up`,
121 | });
122 | }
123 | });
124 | },
125 | };
126 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/addrole.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 |
9 | module.exports = {
10 | name: "addrole",
11 | description: "adds the specified role to the provided user",
12 | category: "mod",
13 | options: [
14 | {
15 | name: "target",
16 | description: "target to add role to",
17 | type: "USER",
18 | required: true,
19 | },
20 | {
21 | name: "role",
22 | description: "role to add",
23 | type: "ROLE",
24 | required: true,
25 | },
26 | {
27 | name: "reason",
28 | description: "reason",
29 | type: "STRING",
30 | required: false,
31 | },
32 | ],
33 |
34 | run: async (client, interaction) => {
35 | const target = interaction.options.getMember("target");
36 | role = interaction.options.getRole("role");
37 | reason =
38 | interaction.options.getString("reason") || "`No Reason Provided`";
39 |
40 | if (target.id === interaction.member.id)
41 | return interaction.followUp({
42 | content: `${fail} You cannot add a role to yourself`,
43 | });
44 |
45 | if (
46 | target.roles.highest.position >=
47 | interaction.member.roles.highest.position
48 | )
49 | return interaction.followUp({
50 | content: `${fail} This user is higher/equal than you`,
51 | });
52 |
53 | if (
54 | target.roles.highest.position >=
55 | interaction.guild.me.roles.highest.position
56 | )
57 | return interaction.followUp({
58 | content: `${fail} This user is higher/equal than me`,
59 | });
60 |
61 | if (role.position >= interaction.member.roles.highest.position)
62 | return interaction.followUp({
63 | content: `${fail} That role is higher/equal than you`,
64 | });
65 |
66 | if (role.position >= interaction.guild.me.roles.highest.position)
67 | return interaction.followUp({
68 | content: `${fail} That role is higher/equal than me`,
69 | });
70 |
71 | if (target.roles.cache.has(role.id))
72 | return interaction.followUp({
73 | content: `${fail} User already has the provided role`,
74 | });
75 |
76 | const embed = new MessageEmbed()
77 | .setAuthor({
78 | name: `${interaction.user.tag}`,
79 | iconURL: interaction.user.displayAvatarURL({
80 | dynamic: true,
81 | }),
82 | })
83 | .setDescription(
84 | `**${interaction.user.tag}** are you sure you want to add to **${target.user.tag}** the ${role} role`
85 | )
86 | .setFooter({
87 | text: client.user.tag,
88 | iconURL: client.user.displayAvatarURL(),
89 | })
90 | .setColor(randomHex())
91 | .setTimestamp();
92 |
93 | confirmButtons(interaction, {
94 | embed: embed,
95 | othersMessage: `Only <@${interaction.member.id}> can use these buttons`,
96 | yes: {
97 | style: "SUCCESS",
98 | label: "Add",
99 | emoji: "✔️",
100 | },
101 | no: {
102 | style: "SECONDARY",
103 | label: "No",
104 | emoji: "🛑",
105 | },
106 | }).then(async (confirm) => {
107 | if (confirm === "yes") {
108 | await target.roles.add(role);
109 | interaction.editReply({
110 | content: `${success} **${role.name}** was successfully added to **${target.user.tag}**`,
111 | });
112 | modLog(interaction, reason, {
113 | Action: "`Add Role`",
114 | Member: `${target}`,
115 | Role: `${role}`,
116 | });
117 | }
118 | if (confirm === "no") {
119 | interaction.editReply({
120 | content: `${fail} **${target.user.tag}** didn't get the **${role.name}** role!`,
121 | });
122 | }
123 | if (confirm === "time") {
124 | interaction.editReply({
125 | content: `${fail} Time is up`,
126 | });
127 | }
128 | });
129 | },
130 | };
131 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/warnings.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const { ButtonPages } = require("leaf-utils"); // my package
3 | const { fail } = require("../../config.json");
4 | const warnModel = require("../../models/warnModel");
5 |
6 | module.exports = {
7 | name: "warnings",
8 | description: "display all warnings that a user has",
9 | category: "mod",
10 | options: [
11 | {
12 | name: "target",
13 | description: "user you want to view warnings on",
14 | type: "USER",
15 | required: true,
16 | },
17 | ],
18 |
19 | run: async (client, interaction) => {
20 | const target = interaction.options.getMember("target");
21 | const userWarnings = await warnModel.find({
22 | userId: target.id,
23 | guildId: interaction.guildId,
24 | });
25 |
26 | if (!userWarnings || userWarnings.length <= 0)
27 | return interaction.followUp({
28 | content: `${fail} ${target} has no warnings`,
29 | });
30 |
31 | let items = [];
32 | array = [];
33 | pages = [];
34 |
35 | if (userWarnings.length > 5) {
36 | userWarnings.forEach((w, i) => {
37 | w.index = i + 1;
38 | if (items.length < 5) items.push(w);
39 | else {
40 | array.push(items);
41 | items = [w];
42 | }
43 | });
44 | array.push(items);
45 |
46 | array.forEach((x) => {
47 | let warns = x
48 | .map(
49 | (w) =>
50 | `Moderator: ${
51 | interaction.guild.members.cache.get(
52 | w.moderatorId
53 | ) || `${fail}`
54 | }\nReason: \`${w.reason}\`\nDate: \nWarnID: \`${w._id}\``
57 | )
58 | .join("\n\n");
59 |
60 | let emb = new MessageEmbed()
61 | .setAuthor({
62 | name: `${target.user.tag}` + "'s warnings",
63 | iconURL: target.user.displayAvatarURL({
64 | dynamic: true,
65 | }),
66 | })
67 | .setDescription(`${warns}`)
68 | .setFooter({
69 | text: client.user.tag,
70 | iconURL: client.user.displayAvatarURL(),
71 | })
72 | .setColor("#F36605")
73 | .setTimestamp();
74 | pages.push(emb);
75 | });
76 |
77 | await ButtonPages({
78 | message: interaction,
79 | slash_command: true,
80 | pages: pages,
81 | time: 300000,
82 | back: {
83 | label: " ",
84 | style: "PRIMARY",
85 | emoji: "⬅️",
86 | },
87 | home: {
88 | label: " ",
89 | style: "DANGER",
90 | emoji: "🏠",
91 | },
92 | next: {
93 | label: " ",
94 | style: "PRIMARY",
95 | emoji: "➡️",
96 | },
97 | authorOnly: "Only <@{{author}}> can use these buttons!",
98 | });
99 | } else {
100 | let warns = userWarnings
101 | .map(
102 | (w) =>
103 | `Moderator: ${
104 | interaction.guild.members.cache.get(
105 | w.moderatorId
106 | ) || `${fail}`
107 | }\nReason: \`${w.reason}\`\nDate: \nWarnID: \`${w._id}\``
110 | )
111 | .join("\n\n");
112 |
113 | let emb = new MessageEmbed()
114 | .setAuthor({
115 | name: `${target.user.tag}` + "'s warnings",
116 | iconURL: target.user.displayAvatarURL({
117 | dynamic: true,
118 | }),
119 | })
120 | .setDescription(`${warns}`)
121 | .setFooter({
122 | text: client.user.tag,
123 | iconURL: client.user.displayAvatarURL(),
124 | })
125 | .setColor("#F36605")
126 | .setTimestamp();
127 |
128 | interaction.followUp({
129 | embeds: [emb],
130 | });
131 | }
132 | },
133 | };
134 |
--------------------------------------------------------------------------------
/SlashCommands/Mod/timeout.js:
--------------------------------------------------------------------------------
1 | const { MessageEmbed } = require("discord.js");
2 | const {
3 | confirmButtons,
4 | modLog,
5 | randomHex,
6 | } = require("../../handler/functions");
7 | const { fail, success } = require("../../config.json");
8 | const ms = require("ms");
9 |
10 | module.exports = {
11 | name: "timeout",
12 | description: "time someone out",
13 | category: "mod",
14 | options: [
15 | {
16 | name: "target",
17 | description: "target to timeout",
18 | type: "USER",
19 | required: true,
20 | },
21 | {
22 | name: "time",
23 | description: "amount of time to timeout",
24 | type: "INTEGER",
25 | required: true,
26 | minValue: 1,
27 | maxValue: 60,
28 | },
29 | {
30 | name: "unit",
31 | description: "time unit",
32 | type: "STRING",
33 | required: true,
34 | choices: [
35 | { name: "seconds", value: "s" },
36 | { name: "minutes", value: "m" },
37 | { name: "hours", value: "h" },
38 | { name: "days", value: "d" },
39 | ],
40 | },
41 | {
42 | name: "reason",
43 | description: "reason for this timeout",
44 | type: "STRING",
45 | required: false,
46 | },
47 | ],
48 |
49 | run: async (client, interaction) => {
50 | let target = interaction.options.getMember("target");
51 | reason =
52 | interaction.options.getString("reason") || "`No Reason Provided`";
53 | time = ms(
54 | interaction.options.getInteger("time") +
55 | interaction.options.getString("unit")
56 | );
57 |
58 | time > 2332800000 ? (time = 2332800000) : (time = time);
59 |
60 | if (target.id === interaction.member.id)
61 | return interaction.editReply({
62 | content: `${fail} You cant timeout yourself`,
63 | });
64 |
65 | if (target.id === interaction.guild.me.id)
66 | return interaction.editReply({
67 | content: `${fail} You cant timeout me`,
68 | });
69 |
70 | if (target.id === interaction.guild.ownerId)
71 | return interaction.followUp({
72 | content: `${fail} You cannot mute the server owner`,
73 | });
74 |
75 | if (
76 | target.roles.highest.position >=
77 | interaction.member.roles.highest.position
78 | )
79 | return interaction.editReply({
80 | content: `${fail} This user is higher/equal than you`,
81 | });
82 |
83 | if (
84 | target.roles.highest.position >=
85 | interaction.guild.me.roles.highest.position
86 | )
87 | return interaction.editReply({
88 | content: `${fail} This user is higher/equal than me`,
89 | });
90 |
91 | if (!target.moderatable)
92 | return interaction.editReply({
93 | content: `${fail} This user can't be timed out`,
94 | });
95 |
96 | const embed = new MessageEmbed()
97 | .setAuthor({
98 | name: `${interaction.user.tag}`,
99 | iconURL: interaction.user.displayAvatarURL({
100 | dynamic: true,
101 | }),
102 | })
103 | .setDescription(
104 | `**${interaction.user.tag}** are you sure you want to timeout **${target.user.tag}**`
105 | )
106 | .setFooter({
107 | text: client.user.tag,
108 | iconURL: client.user.displayAvatarURL(),
109 | })
110 | .setColor(randomHex())
111 | .setTimestamp();
112 |
113 | confirmButtons(interaction, {
114 | embed: embed,
115 | authorOnly: `Only <@${interaction.member.id}> can use these buttons`,
116 | yes: {
117 | style: "SUCCESS",
118 | label: "Timeout",
119 | emoji: "✔️",
120 | },
121 | no: {
122 | style: "SECONDARY",
123 | label: "No",
124 | emoji: "🛑",
125 | },
126 | }).then(async (confirm) => {
127 | if (confirm === "yes") {
128 | await target.timeout(time, reason);
129 | interaction.editReply({
130 | content: `${success} **${
131 | target.user.tag
132 | }** has been timed out for **${ms(time, { long: true })}**`,
133 | });
134 | modLog(interaction, reason, {
135 | Action: "`Timeout`",
136 | Member: `${target}`,
137 | Time: `\`${ms(time, { long: true })}\``,
138 | });
139 | }
140 | if (confirm === "no") {
141 | interaction.editReply({
142 | content: `${fail} **${target.user.tag}** hasn't been timed out!`,
143 | });
144 | }
145 | if (confirm === "time") {
146 | interaction.editReply({
147 | content: `${fail} Time is up`,
148 | });
149 | }
150 | });
151 | },
152 | };
153 |
--------------------------------------------------------------------------------
/handler/functions.js:
--------------------------------------------------------------------------------
1 | const { MessageButton, MessageActionRow, MessageEmbed } = require("discord.js");
2 | const { fail } = require("../config.json");
3 | const modLogModel = require("../models/modlogs");
4 |
5 | module.exports = {
6 | confirmButtons(message, options = {}) {
7 | let yn = (st) => [
8 | new MessageActionRow().addComponents(
9 | new MessageButton()
10 | .setStyle(options.yes.style || "SUCCESS")
11 | .setLabel(options.yes.label || "Yes")
12 | .setEmoji(options.yes.emoji || null)
13 | .setCustomId("confyes")
14 | .setDisabled(st),
15 | new MessageButton()
16 | .setStyle(options.no.style || "DANGER")
17 | .setLabel(options.no.label || "No")
18 | .setEmoji(options.no.emoji || null)
19 | .setCustomId("confno")
20 | .setDisabled(st)
21 | ),
22 | ];
23 |
24 | if (!message.author) {
25 | return new Promise(async (res) => {
26 | await message
27 | .reply({
28 | embeds: [options.embed],
29 | components: yn(false),
30 | })
31 | .catch(async () => {
32 | await message.followUp({
33 | embeds: [options.embed],
34 | components: yn(false),
35 | });
36 | });
37 |
38 | let msg = await message.fetchReply();
39 |
40 | const collector = await msg.createMessageComponentCollector({
41 | type: "BUTTON",
42 | time: 60000,
43 | });
44 |
45 | collector.on("collect", async (i) => {
46 | if (i.user.id !== message.user.id)
47 | return i.reply({
48 | content:
49 | options.authorOnly ||
50 | "You cant use these buttons",
51 | ephemeral: true,
52 | });
53 |
54 | await i.deferUpdate();
55 | if (i.customId === "confyes") {
56 | collector.stop("confy");
57 | message.editReply({
58 | components: yn(true),
59 | });
60 |
61 | res("yes");
62 | }
63 | if (i.customId === "confno") {
64 | collector.stop("confn");
65 | message.editReply({
66 | components: yn(true),
67 | });
68 |
69 | res("no");
70 | }
71 | });
72 |
73 | collector.on("end", async (i, r) => {
74 | if (r === "time") {
75 | message
76 | .editReply({
77 | components: yn(true),
78 | })
79 | .catch(() => {});
80 |
81 | res("time");
82 | }
83 | });
84 | });
85 | } else {
86 | return new Promise(async (res) => {
87 | let msg = await message.channel.send({
88 | embeds: [options.embed],
89 | components: yn(false),
90 | });
91 |
92 | let collector = msg.createMessageComponentCollector({
93 | max: 1,
94 | componentType: "BUTTON",
95 | time: options.time * 1000 || 30000,
96 | });
97 |
98 | collector.on("collect", async (i) => {
99 | if (i.user.id !== message.user.id)
100 | return i.reply({
101 | content:
102 | options.authorOnly ||
103 | "You cant use these buttons",
104 | ephemeral: true,
105 | });
106 |
107 | await i.deferUpdate();
108 | if (i.customId === "confyes") {
109 | collector.stop("confy");
110 | i.message.edit({
111 | components: yn(true),
112 | });
113 |
114 | res("yes");
115 | }
116 | if (i.customId === "confno") {
117 | collector.stop("confn");
118 | i.message.edit({
119 | components: yn(true),
120 | });
121 |
122 | res("no");
123 | }
124 | });
125 |
126 | collector.on("end", async (i, r) => {
127 | if (r === "time") {
128 | msg.edit({
129 | components: yn(true),
130 | }).catch(() => {});
131 |
132 | res("time");
133 | }
134 | });
135 | });
136 | }
137 | },
138 | modLog(interaction, reason, fields = {}) {
139 | modLogModel.findOne(
140 | {
141 | Guild: interaction.guildId,
142 | },
143 | async (err, data) => {
144 | if (err) throw err;
145 | if (!data || (data && !data.Channel)) return;
146 |
147 | const modLog = interaction.guild.channels.cache.get(
148 | data.Channel
149 | );
150 | if (
151 | modLog &&
152 | modLog.viewable &&
153 | modLog
154 | .permissionsFor(interaction.guild.me)
155 | .has(["SEND_MESSAGES", "EMBED_LINKS"])
156 | ) {
157 | const embed = new MessageEmbed()
158 | .addField(
159 | "Moderator",
160 | `${interaction.user || `${fail}`}`,
161 | true
162 | )
163 | .setFooter({
164 | text: `${interaction.user.tag}`,
165 | iconURL: interaction.user.displayAvatarURL({
166 | dynamic: true,
167 | }),
168 | })
169 | .setTimestamp()
170 | .setColor("DARK_RED");
171 | for (const field in fields) {
172 | embed.addField(field, fields[field], true);
173 | }
174 | embed.addField("Reason", reason);
175 | modLog.send({
176 | embeds: [embed],
177 | });
178 | }
179 | }
180 | );
181 | },
182 | randomHex() {
183 | return "#" + Math.floor(Math.random() * 16777215).toString(16);
184 | },
185 | };
186 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2021-2022 notLeaf
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------