Compare commits

..

11 Commits

Author SHA1 Message Date
rhearmas 2c862b1c15 We finally have it finished, for now 2020-08-20 18:02:20 -04:00
rhearmas 2434b76b31 Add rfa.js 2020-08-15 07:45:54 -04:00
rhearmas b764bc7667 Add rfa, update some more stuff 2020-08-15 07:45:36 -04:00
rhearmas 8d92e7d176 Ignore files starting with underscores 2020-08-11 22:06:15 -04:00
rhearmas 240b60076a Progress! 2020-02-13 15:38:39 -05:00
rhearmas e1ecadfc8e Preparing to make the huge overhaul 2020-02-09 21:27:26 -05:00
rhearmas d8df28edbc Fix some stuff 2020-02-09 21:09:12 -05:00
rhearmas 12fc7ad8b4 Add mine and usable systems 2020-02-09 21:08:19 -05:00
Carol Knieriem c9f87cecbd
adjust colon 2020-02-07 12:49:04 -05:00
User 6068ee89e3 Added ability to view only commands you have access to 2020-02-07 09:46:42 -05:00
rhearmas d8fbddb351 adding specific command info, attempting to create all commands 2020-02-06 16:07:08 -05:00
15 changed files with 541 additions and 199 deletions

58
.eslintrc.json Normal file
View File

@ -0,0 +1,58 @@
{
"parserOptions": {
"ecmaVersion": 2017
},
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"rules": {
"no-console": "off",
"indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"warn",
"double"
],
"semi": [
"warn",
"always"
],
"keyword-spacing": [
"error", {
"before": true,
"after": true
}
],
"space-before-blocks": [
"error", {
"functions":"always",
"keywords": "always",
"classes": "always"
}
],
"space-before-function-paren": [
"error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}
],
"prefer-const": [
"error", {
"destructuring": "any",
"ignoreReadBeforeAssign": false
}
]
}
}

2
.gitignore vendored
View File

@ -7,6 +7,7 @@ yarn-error.log*
config.json
config.js
data/
test.js
# Runtime data
pids
@ -59,3 +60,4 @@ typings/
# dotenv environment variables file
.env

View File

@ -1,23 +1,57 @@
# Welcome
<h1 align="center">Cardboard Box</h1>
## Information
**Cardboard Box** is a [Discord](https://discordapp.com) bot for my [**Discord server**](https://discord.gg/4zJ8xqV) powered by [Discord.js](https://discord.js.org). It comes packaged with many utilities and fun stuff, and even some special moderation functions.
**This bot is not suitable for usage outside of my Discord server!** This repository is primarily for issue tracking and global management between my own devices. If you really, _really_ want to run it yourself, read the sections below.
**This bot is not suitable for usage outside of my Discord server!** This repository is primarily for issue tracking and global management between my own devices. If you really, *really* want to run it yourself, read the sections below.
### Adding the bot to your guild
## Adding the bot to your guild
Don't want to run the bot yourself? Simply use [this link](https://discordapp.com/oauth2/authorize/?permissions=8&scope=bot&client_id=618576806177538079) to invite it to your own guild.
Don't want to run the bot yourself? Simply use [this link](https://discordapp.com/oauth2/authorize/?permissions=8&scope=bot&client_id=618576806177538079) to invite it to your own guild. If you prefer to run it under your own bot name, read the section below.
## Credits
<h1 align="center">Running it yourself</h1>
* [SharpBot, a selfbot for Discord](https://github.com/RayzrDev/SharpBot) was actually my source for most of these cool commands! Huge kudos to [RayzrDev](https://github.com/RayzrDev) for making a cool selfbot.
* This was initially an edit to [GuideBot, the boilerplate example bot in Discord.js](https://github.com/AnIdiotsGuide/guidebot). It has some minor edits to the base code, but most of the basic stuff came from this very example bot.
If you're really wanting to use this bot yourself, let's go over what you need and how to install it.
## Join me
## Requirements
- `git` command line. Install by clicking your operating system's name in this list:
- [Windows](https://git-scm.com/download/win)
- [Linux](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- [Macintosh](https://git-scm.com/download/mac)
- `node` version [8.0.0 or higher](https://nodejs.org).
- Your **Discord bot token.** Read the first section of [this page](https://anidiots.guide/getting-started/the-long-version.html) on how to snag it.
- `Python`. Install it from [here](https://www.python.org/downloads).
## Installation
1. Head on over to your terminal (preferrably **Command Prompt**) and clone the repository.
- If you want to clone to a specific folder, you have two options:
- **`cd` into your desired folder.** For example, if you wanted to clone the repository into Documents, open the terminal normally and run `cd C:/Users/<user>/Documents`.
- Open the terminal in a specific folder by doing **Shift-Rightclick => Open <Powershell/command terminal> here**.
- After doing either of those steps, clone the repository by running `git clone https://github.com/rhearmas/cardboardbot.git` through your terminal.
2. When `git` has finished, `cd` into the newly-created folder for the repository.
3. Run `npm install`. This installs all the prerequisites for the bot through **Node package manager**, which is bundled with `node`.
- If you get any errors about python or msibuild.exe or binding, read the requirements section again and make sure you've installed **everything**.
4. Run `node setup.js` to get a configuration file added.
## Running the bot
Open your terminal and run `node index.js` inside the folder. Don't forget to `cd` into it if the folder isn't in places like your Desktop.
## Getting it to your server
Generate an OAuth link for your bot. Use [this delicious link](https://finitereality.github.io/permissions-calculator/?v=0) to get your link. It even has a calculator for permissions!
<h1 align="center">Credits</h1>
- [SharpBot, a selfbot for Discord](https://github.com/RayzrDev/SharpBot) was actually my source for most of these cool commands! Huge kudos to [RayzrDev](https://github.com/RayzrDev) for making a cool selfbot.
- This was initially an edit to [GuideBot, the boilerplate example bot in Discord.js](https://github.com/AnIdiotsGuide/guidebot). It has some minor edits to the base code, but most of the basic stuff came from this very example bot.
<h1 align="center">Join me</h1>
If you need a fun server to join, regardless of whether or not you're new to Discord, join now! If you've never used Discord before, don't fret! It only takes a few minutes to sign up and get started.
## [https://discord.gg/4zJ8xqV](https://discord.gg/4zJ8xqV)
# https://discord.gg/4zJ8xqV

View File

@ -20,8 +20,12 @@ exports.run = async (client, message, args) => {
let fetched;
fetched = await chnl.fetchMessages();
await output.edit(`Clearing messages in ${chnl}.`);
chnl.bulkDelete(fetched);
await output.edit(`Messages cleared in ${chnl}.`);
if(fetched) {
chnl.bulkDelete(fetched);
await output.edit(`Messages cleared in ${chnl}.`);
} else {
await output.edit(`No messages found in ${chnl}.`);
}
}
clearLanding();
@ -29,33 +33,27 @@ exports.run = async (client, message, args) => {
.setTitle("Introduction")
.setColor(0x2f3136)
.setDescription(`Welcome to **${guild.name}**! This is a Discord server that I personally run for all my shenanigans. This is the channel where I explain rules and stuff and other stuff.`)
.addField("IMPORTANT DISCLAIMER:", "This list does not constitute the full list of rules. With that in mind, try to use common sense and good judgement for any action you're about to take at all times.")
.addField("Before we go further...","I don't care if you use profanity here, since Discord only allows users who are at least 13 years of age. If you have a problem with this, then this isn't the discord server for you.")
.addField("Before we jump in...", "This list does not constitute the full list of rules. With that in mind, try to use common sense and good judgement for any action you're about to take at all times.\nDiscord's [Community Guidelines](https://discord.com/channels/387727726297088002/743142164564803705) also have some important rules not mentioned here.")
.setThumbnail(guild.iconURL);
const textrules = new Discord.RichEmbed()
.setTitle("Text Channel Rules")
.setColor(0x2f3136)
.addField("Use common sense.","This means that you shouldn't be a jerk to others.")
.addField("No raiding.","Nobody here endorses raiding. Raiding this server or trying to rally other users to help you raid this server or another server is not allowed.")
.addField("Do not attempt to destroy the server.","This includes vandalizing non-spam channels with spam or playing excessively loud music.")
.addField("Abide by Discord's global ruleset.","This means that you should take the time to read the [Discord Terms of Service](https://discordapp.com/terms) and [Community Guidelines](https://discordapp.com/guidelines).")
.addField("Do not attempt to destroy the server.","For example, don't vandalize media channels with spam or try to check your level in the general chat.")
.addField("No discrimination.","This includes disrespecting people because of personal factors such as gender, sexual orientation, mental disabilities, race, age, location of residence, or anything else of the like.")
.addField("Threats towards others are not allowed.","Do not attempt to cause others to feel endangered in this server. We want to provide a safe space for everyone here, so don't ruin it.")
.addField("Abide by Discord's global platform rules.","This means that you should take the time to read the [Discord Terms of Service](https://discordapp.com/terms) and [Community Guidelines](https://discordapp.com/guidelines).")
.addField("Don't complain about your punishments.","They were given for a valid reason. ModMail exists just in case a staff member falsely punishes you.")
.addField("Loopholes aren't a thing, so don't go looking for them.","Don't be a wise-ass and just follow the rules. Don't test your boundaries, being here is a priviledge, not a right.")
.addField("Advertising outside of the advertisement channel is not permitted.","This includes third-party services (that are not related to this Discord) or anything you or others have created, regardless of permission granted. Advertising other Discord servers -- or advertising **anything** in your playing status or through unsolicited DMs -- is strictly forbidden.")
.addField("Loopholes aren't a thing, so don't go looking for them.","Don't be a wise-a## and just follow the rules. Don't test your boundaries; being here is a priviledge, not a right.")
.addField("Advertising outside of the advertisement channel is not permitted.","Things such third-party services that are not related to this Discord or anything you or others have created arne't allowed. Advertising other Discord servers -- or advertising **anything** in your playing status or through unsolicited DMs -- is strictly forbidden.")
.addField("Don't cause beef with other members.","Don't send hate to other people if you see them as a bad person. Tolerate everyone here, even if you despise them, and don't engage in arguments.")
.addField("Do not humiliate other people.","Mentioning previous drama or other situations any person was involved in is included.")
.addField("No excuses for punishment.","The rule nullification system exists for a valid reason. Staff don't care until someone complains. Don't use this system as a way to attempt to circumvent a punishment.")
.addField("Absolutely no NSFW content.","Shocking or graphic content, animal cruelty, and gore are not allowed whatsoever outside of the designated NSFW channels. Breaking this rule will result in a permanent ban on sight.");
const voicerules = new Discord.RichEmbed()
.setTitle("Voice Channel Rules")
.setColor(0x2f3136)
.addField("Most text rules apply in the voice chat.","Don't go crazy because of the channels being different.")
.addField("No loud audio.","Playing loud and/or annoying audio through your microphone or music bots is not allowed.")
.addField("Be responsible.","Everyone in the server holds the right to report users in the voice channels to have them muted as needed.")
.addField("Use common sense.","You can't escape this rule. Please don't ignore it.")
.addField("Limit the usage of voice changers.","Don't fake what you sound like. We prevent discrimination, you're fine.");
.addField("Limit the usage of voice changers.","Don't fake what you sound like. We prevent discrimination, you're fine.")
.addField("Don't blast music to others.","While we can limit which music bots can enter voice channels, we can't automatically stop other members from joining any of these channels with music blasting into their microphone.");
const punishmentsystem = new Discord.RichEmbed()
.setTitle("Punishment System")
.setColor(0x2f3136)
@ -102,7 +100,7 @@ exports.run = async (client, message, args) => {
await output.edit(`Landing has finished building in ${chnl}. This message will be removed in 5 seconds.`).then(output => {
output.delete(5000)
})
.catch(() => console.error("Error while deleting message."));
.catch(() => { });
}
sendLandingEmbeds();
};

View File

@ -0,0 +1,98 @@
const Discord = require("discord.js");
exports.run = async (client, message, args) => {
message.delete();
const output = await message.channel.send("Generating the Guidelines. Reading arguments...");
guild = message.guild;
let chnl = guild.channels.find(c => c.name === 'community-guidelines') || guild.channels.find(c => c.name === 'guidelines');
if(args[0]) {
chnl = args[0].substring("<#".length);
chnl = chnl.substring(chnl.length-1,0);
chnl = guild.channels.find(c => c.id === chnl);
output.edit(`Guidelines channel set to <#${chnl}>.`);
} else {
output.edit(`Arguments provided are invalid or channel was not found; set landing channel to ${chnl}.`);
}
async function clearGuidelinesChannel() {
let fetched;
fetched = await chnl.fetchMessages();
await output.edit(`Clearing messages in ${chnl}...`);
if(fetched) {
chnl.bulkDelete(fetched);
await output.edit(`Messages cleared in ${chnl}.`);
} else {
await output.edit(`No messages found in ${chnl}.`);
}
}
clearGuidelinesChannel();
const intro = new Discord.RichEmbed()
.setTitle("Discord Community Guidelines")
.setColor(0x2f3136)
.setDescription(`We created Discord to help people come together around games. It's been amazing to watch it grow into what it is today - a place where millions of diverse communities exist and people connect with old friends and new. We can't wait to see what's next.\n\nOur community guidelines are meant to explain what is and isnt allowed on Discord, and ensure that everyone has a good experience. If you come across a message that appears to break these rules, please report it to us. We may take a number of steps, including issuing a warning, removing the content, or removing the accounts and/or servers responsible.\n\nThe overwhelming majority of people use Discord responsibly, so these guidelines may seem obvious. Still, we want to be clear about the expectations for our users. Every user of Discord should feel like their voice can be heard, but not at the expense of someone else.`)
const interact = new Discord.RichEmbed()
.setTitle("Here are some rules for interacting with others:")
.setColor(0x2f3136)
.addField("Do not organize, participate in, or encourage harassment of others.","Disagreements happen and are normal, but continuous, repetitive, or severe negative comments may cross the line into harassment and are not okay.")
.addField("Do not organize, promote, or coordinate servers around hate speech.","Its unacceptable to attack a person or a community based on attributes such as their race, ethnicity, national origin, sex, gender, sexual orientation, religious affiliation, or disabilities.")
.addField("Do not make threats of violence or threaten to harm others.","This includes indirect threats, as well as sharing or threatening to share someones private personal information (also known as doxxing).")
.addField("Do not evade user blocks or server bans.","Do not send unwanted, repeated friend requests or messages, especially after theyve made it clear they dont want to talk to you anymore. Do not try to hide your identity in an attempt to contact someone who has blocked you, or otherwise circumvent the tools we have which enable users to protect themselves.")
.addField("Do not send others viruses or malware.","[Also, do not] attempt to phish others, or hack or DDoS them.")
const content = new Discord.RichEmbed()
.setTitle("Here are some rules for content on Discord:")
.setColor(0x2f3136)
.addField("You may not sexualize minors in any way.","This includes sharing content or links which depict minors in a pornographic, sexually suggestive, or violent manner, and includes illustrated or digitally altered pornography that depicts minors (such as lolicon, shotacon, or cub). We report illegal content to the [National Center for Missing and Exploited Children](https://www.missingkids.org/gethelpnow/cybertipline).")
.addField("You may not share sexually explicit content of other people without their consent.","In addition, you cannot share or promote sharing of non-consensual intimate imagery (also known as revenge porn) in an attempt to shame or degrade someone.")
.addField("You may not share content that glorifies or promotes suicide or self-harm.","This includes any encouragement to others to cut themselves, or embrace eating disorders such as anorexia or bulimia.")
.addField("You may not share images of sadistic gore or animal cruelty.","_ _")
.addField("You may not use Discord for the organization, promotion, or support of violent extremism.","_ _")
.addField("You may not operate a server that sells or facilitates the sales of prohibited or potentially dangerous goods.","This includes firearms, ammunition, drugs, and controlled substances.")
.addField("You may not promote, distribute, or provide access to content involving the hacking, cracking, or distribution of pirated software or stolen accounts.","This includes sharing or selling cheats or hacks that may negatively affect others in multiplayer games.")
.addField("In general, you should not promote, encourage or engage in any illegal behavior.","This is very likely to get you kicked off Discord, and may get you reported to law enforcement.");
const respect = new Discord.RichEmbed()
.setTitle("Finally, we ask that you respect Discord itself:")
.setColor(0x2f3136)
.addField("You may not sell your account or your server.","_ _")
.addField("You may not use self-bots or user-bots to access Discord.","_ _")
.addField("You may not share content that violates anyone's intellectual property or other rights.","_ _")
.addField("You may not spam Discord, especially our Customer Support and Trust & Safety teams.","Making false and malicious reports, sending multiple reports about the same issue, or asking a group of users to all report the same content may lead to action being taken on your account.");
const end = new Discord.RichEmbed()
.setTitle("Reporting users who break these Guidelines")
.setColor(0x2f3136)
.setDescription("If you see any activity that violates these guidelines, you can report it to us by filling out [this form](https://dis.gd/request).")
async function sendGuidelineEmbeds() {
await output.edit("Sending intro... *(Embed 1/5)*");
await chnl.send({embed: intro});
await output.edit("Sending interaction rules... *(Embed 2/5)*");
await chnl.send({embed: interact});
await output.edit("Sending content rules... *(Embed 3/5)*");
await chnl.send({embed: content});
await output.edit("Sending Discord's respect rules... *(Embed 4/5)*");
await chnl.send({embed: respect});
await output.edit("Sending ending... *(Embed 5/5)*");
await chnl.send({embed: end});
await output.edit(`Guidelines have been sent in ${chnl}. This message will be removed in 5 seconds.`).then(output => {
output.delete(5000)
})
.catch(() => { });
}
sendGuidelineEmbeds();
};
exports.conf = {
enabled: true,
guildOnly: false,
aliases: [],
permLevel: "Bot Owner"
};
exports.help = {
name: "guidelines",
category: "Channel Building",
description: "Builds the guidelines channel by purging the whole channel and sending embeds. Builds in first channel named **community-guidelines** _or_ **guidelines** if no arguments are provided.",
usage: "guidelines channel"
};

View File

@ -0,0 +1,85 @@
const Discord = require("discord.js");
exports.run = async (client, message, args) => {
message.delete();
const output = await message.channel.send("Generating the requests for adminship channel. Reading arguments...");
guild = message.guild;
let chnl = guild.channels.find(c => c.name === 'rfa-info');
if(args[0]) {
chnl = args[0].substring("<#".length);
chnl = chnl.substring(chnl.length-1,0);
chnl = guild.channels.find(c => c.id === chnl);
output.edit(`RfA info channel set to <#${chnl}>.`);
} else {
output.edit(`Arguments provided are invalid or channel was not found; set RfA channel to ${chnl}.`);
}
async function clearRfA() {
let fetched;
fetched = await chnl.fetchMessages();
await output.edit(`Clearing messages in ${chnl}.`);
if(fetched) {
chnl.bulkDelete(fetched);
await output.edit(`Messages cleared in ${chnl}.`);
} else {
await output.edit(`No messages found in ${chnl}.`);
}
}
clearRfA();
const intro = new Discord.RichEmbed()
.setTitle("Introduction")
.setColor(0x2f3136)
.setDescription(`Whether you're nominating yourself or somebody else, or simply reading what people say here, we welcome you warmly to the Requests for Adminship category. This category allows eligible users to nominate themselves for a staff position, [similar to how Wikipedia handles their admins](https://en.wikipedia.org/wiki/Wikipedia:Requests_for_adminship).`)
.addField("General standards", "On a normal basis, users who are of at least level 25 or above -- also known as being \"confirmed\", are at least 15 years of age and haven't had any infractions in the past month. The user being nominated must meet _all_ of these requirements, regardless of whether the nomination is from themselves or another user. If you are under level 25 _OR_ are of 13 or 14 years of age, it will be significantly more challenging for you to be accepted into the staff team.")
.addField("_ _","Without many positive contributions to the community, however, it is very unlikely that one may pass. People will look for a variety of factors in a candidate, and the discussion can be intense.");
const process = new Discord.RichEmbed()
.setTitle("Request for Staff Procedure")
.setColor(0x2f3136)
.addField("Publish.","A user can request to receive admin by simply submitting a form using the form at the bottom. Users can then notify an Elite that they've submitted their request.")
.addField("Discuss.","An ELITE will review the basic information, and then will make a channel specifically for the request, followed by a mention to the subject of the channel. All opinions and additional questions are asked in this channel, alongside discussion of what the user can and can't do.\nA pinned message will be placed to allow for voting on the user with reactions; a thumbs up (`:thumbsup:`) for yes, a thumbs down (`:thumbsdown:`) for no, or a question mark (`:grey_question:`) for neutral.")
.addField("Ask.","The user may have answered the base 3 questions, but they must also answer all questions by **quoting the original message, and keep the mention intact when the candidate responds to the query.** Elites will be requested to pin all answered questions to the channel for easy access. These questions can include \"what would you do in situation X?\" or \"what can you not do with discord that may hinder you?\". Keep the questions mature and civil; immaturity will result in mutes, kicks or bans.")
.addField("Decide.","Once you think you've learned enough, head to the pinned messages and jump to the decision message. React to **__ONE__** reaction on the message; multiple will make the reviewer assume you are unsure. You can change your votes at any time; be sure to keep it at one reaction only.")
.addField("Closure.","After around one week of the RfA being open, the Elites will close the request and tally the votes:\n - Users with at least 75% support will always pass\n - Users with support varying from 65% to 75% will be left with the Elites deciding\n - Users with **at most** 65% will most likely be declined\n\nIf your nomination fails, then please wait for a reasonable period of time before renominating yourself or accepting another nomination. Some candidates have tried again and succeeded within three months, but many people prefer to wait considerably longer before reapplying.");
const nomination = new Discord.RichEmbed()
.setTitle("Nomating users or yourself")
.setColor(0x2f3136)
.addField("Before you start,","If you're nominating someone else, make sure they're okay with it __before__ you make your nomination. If you're going with self-nomination, be sure you know exactly what you're doing.")
.addField("Nomation Form","Nominate yourself by clicking the form below, or if you are nominating someone else, use this form: https://forms.gle/zArWXC2a6oZ9oHS36");
const questions = new Discord.RichEmbed()
.setTitle("Candidate Questions")
.setColor(0x2f3136)
.setDescription("[Open the questions form by clicking this text.](https://forms.gle/ue28VSULnPpcGWJu8)")
async function sendRfAEmbeds() {
await output.edit("Sending intro... *(Embed 1/4)*");
await chnl.send({embed: intro});
await output.edit("Sending process for staff... *(Embed 2/4)*");
await chnl.send({embed: process});
await output.edit("Sending nomination guidelines... *(Embed 3/4)*");
await chnl.send({embed: nomination});
await output.edit("Sending questions embed... *(Embed 4/4)*");
await chnl.send({embed: questions});
await output.edit(`RfA guidelines have finished building in ${chnl}. This message will be removed in 5 seconds.`).then(output => {
output.delete(5000)
})
.catch(() => { });
}
sendRfAEmbeds();
};
exports.conf = {
enabled: true,
guildOnly: false,
aliases: [],
permLevel: "Bot Owner"
};
exports.help = {
name: "rfa",
category: "Channel Building",
description: "Builds the Requests for Adminship channel by purging the whole channel and sending embeds. Builds in first channel named **rfa-info** if no arguments are provided.",
usage: "rfa channel"
};

View File

@ -1,54 +1,132 @@
const { RichEmbed } = require('discord.js');
const stripIndents = require('common-tags').stripIndents;
exports.run = (client, message, args, level) => {
exports.run = async (client, message, args, level) => {
message.delete();
if (!args[0]) {
const myCommands = message.guild ? client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level) : client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level && cmd.conf.guildOnly !== true);
const commandNames = myCommands.keyArray();
const longest = commandNames.reduce((long, str) => Math.max(long, str.length), 0);
let currentCategory = "";
let output = `= Command List =\n\n[Use ${message.settings.prefix}help <commandname> for details]\n`;
const sorted = myCommands.array().sort((p, c) => p.help.category > c.help.category ? 1 : p.help.name > c.help.name && p.help.category === c.help.category ? 1 : -1 );
sorted.forEach( c => {
const cat = c.help.category.toProperCase();
if (currentCategory !== cat) {
output += `\u200b\n== ${cat} ==\n`;
currentCategory = cat;
let commands = client.commands;
let title = "Categories";
if(args[0]) {
if(args[0] === "category" || args[0] === "type") {
if(!args[1]) {
return (await message.reply("you must specify a valid category!")).delete(5000).catch(() => { });
}
output += `${message.settings.prefix}${c.help.name}${" ".repeat(longest - c.help.name.length)} :: ${c.help.description}\n`;
});
message.channel.send(output, {code: "asciidoc", split: { char: "\u200b" }});
} else {
let command = args[0];
if (client.commands.has(command)) {
command = client.commands.get(command);
if (level < client.levelCache[command.conf.permLevel]) return;
message.channel.send({embed: client.embed(`Command information: "${command.help.name}"`, command.help.description, [
commands = client.commands.filter(cmd => cmd.help.category === args[1]);
title = `== ${args[1]} commands ==`;
} else if(args[0] === "all" || args[0] === "full" || args[0] === "every") {
commands = message.guild ? client.commands : client.commands.filter(cmd.conf.guildOnly !== true);
title = "== All Commands =="
} else if(args[0] === "mine" || args[0] === "usable") {
commands = message.guild ? client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level) : client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level && cmd.conf.guildOnly !== true);
title = `== ${message.author.username}'s Usable Commands ==`
} else {
let command = args[0];
if (client.commands.has(command)) {
command = client.commands.get(command);
if (level < client.levelCache[command.conf.permLevel]) return;
message.channel.send({embed: client.embed(`Command information: "${command.help.name}"`, command.help.description, [
{
name: 'Category',
value: command.help.category !== "" ? command.help.category : "none",
inline: true
},
{
name: 'Usage',
value: command.help.usage,
inline: true
},
{
name: 'Aliases',
value: command.conf.aliases.join(", ") !== "" ? command.conf.aliases.join(", ") : "none",
inline: true
}
],
{
name: 'Category',
value: command.help.category !== "" ? command.help.category : "none",
inline: true
},
{
name: 'Usage',
value: command.help.usage,
inline: true
},
{
name: 'Aliases',
value: command.conf.aliases.join(", ") !== "" ? command.conf.aliases.join(", ") : "none",
inline: true
}
],
{
author: message.author.tag,
authorIcon: message.author.avatarURL
})
});
author: message.author.tag,
authorIcon: message.author.avatarURL
})
});
}
}
}
if(commands.length > 0) {
let fields = commands
.sort((a,b) => a.help.name.localeCompare(b.help.name))
.map(c => getHelp(client, c, commands.length === 1));
let maxLength = 1900;
let messages = [];
while(fields.length > 0) {
let len = 0;
let i = 0;
while(len < maxLength) {
if(i >= fields.length) break;
let field = fields[i];
len += field.name.length + field.value.length;
if(len >= maxLength) break;
i++;
}
messages.push({ fields: fields.splice(0,i) });
}
message.delete().catch(() => { });
messages.map(m => m.fields).forEach(async fields => {
(await message.channel.send({
embed: client.embed(title,'_This message will self-destruct in 90 seconds._ :boom:',fields)
})).delete(90000).catch(() => { });
});
} else {
// let categories = client.categories().sort();
let categories;
(await message.channel.send({
embed: client.embed(title,stripIndents
`**Available categories:**
${categories.map(c => `- __${c}__`).join('\n')}
\`\`\`asciidoc
== Usage ==
${message.settings.prefix}help category <name> :: Provides a list of comamnds in a specific category.
${message.settings.prefix}help all :: Shows a list of every command available for this bot.
${message.settings.prefix}help mine :: Presents a list of all commands that your permission level has access to.
${message.settings.prefix}help <command> :: Sends extended command help and extra options.
\`\`\``)
})).delete(15000);
}
};
const getHelp = (bot, command, single) => {
let description = stripIndents`
**Usage:** \`${message.settings.prefix}${command.help.usage || command.help.name}\`
**Description:** ${command.help.description || '<no description>'}
**Category:** __${command.help.category}__`;
if (command.help.credits)
description += `\n**Credits:** *${command.help.credits}*`;
if (single && command.help.examples)
description += `\n**Examples:**\n${command.help.examples.map(example => `\`${message.settings.prefix}${example}\``).join('\n')}`;
if (single && command.help.options instanceof Array) {
let options = command.help.options.map(option => {
return stripIndents`
**${option.name}**
*Usage:* \`${option.usage || option.name}\`
*Description:* ${option.description}
`;
});
description += `\n**Options:**\n\n${options.join('\n\n')}`;
}
return {
name: single ? '\u200b' : command.help.name,
value: description
};
};
exports.conf = {
@ -64,3 +142,22 @@ exports.help = {
description: "Displays all the available commands for your permission level.",
usage: "help [command]"
};
/*
const myCommands = message.guild ? client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level && cmd.help.category === args[1]) : client.commands.filter(cmd => client.levelCache[cmd.conf.permLevel] <= level && cmd.conf.guildOnly !== true && cmd.help.category === args[1]);
const commandNames = myCommands.keyArray();
const longest = commandNames.reduce((long, str) => Math.max(long, str.length), 0);
let currentCategory = "";
let output;
const sorted = myCommands.array().sort((p, c) => p.help.category > c.help.category ? 1 : p.help.name > c.help.name && p.help.category === c.help.category ? 1 : -1 );
sorted.forEach( c => {
const cat = c.help.category.toProperCase();
if (currentCategory !== cat) {
output += `\u200b\n== ${cat} ==\n`;
currentCategory = cat;
}
output += `${message.settings.prefix}${c.help.name}${" ".repeat(longest - c.help.name.length)} :: ${c.help.description}\n`;
});
*/

View File

@ -15,7 +15,7 @@ exports.run = async (client, message, [action, key, ...value], level) => {
client.settings.set(message.guild.id, joinedValue, key);
message.reply(`Key \`${key}\` has successfully been changed to \`${joinedValue}\`.`);
message.reply(`${key} successfully edited to ${joinedValue}`);
} else
if (action === "del" || action === "reset") {

View File

@ -1,35 +0,0 @@
const got = require("got");
exports.run = async (client, message, args, level) => {
const pgAmount = args[0] || 2;
const out = await got(`https://loripsum.net/api/${pgAmount}/decorate/code`);
let final = out.body;
final = final.then(
.replace("<b>", "**")).then(
.replace("</b>", "**")).then(
.replace("<p>", "")).then(
.replace(" </p>", "")).then(
.replace("<i>", "_")).then(
.replace("</i>", "_")).then(
.replace("<mark>", "||").then(
.replace("</mark>", "||").then(
.replace("<pre>","```").then(
.replace("</pre>","```");
message.channel.send(final);
};
exports.conf = {
enabled: true,
guildOnly: false,
aliases: [],
permLevel: "Bot Owner"
};
exports.help = {
name: "test",
category: "",
description: "Sends randomly-generated Lorem Ipsum demo text.",
usage: "test [paragraphCount:2]"
};

View File

@ -52,6 +52,6 @@ module.exports = async (client, message) => {
message.flags.push(args.shift().slice(1));
}
client.logger.cmd(`${client.config.permLevels.find(l => l.level === level).name} ${message.author.username} (${message.author.id}) ran ${cmd.help.name}`);
client.logger.cmd(`[CMD] ${client.config.permLevels.find(l => l.level === level).name} ${message.author.username} (${message.author.id}) ran command ${cmd.help.name}`);
cmd.run(client, message, args, level);
};

View File

@ -38,7 +38,7 @@ const init = async () => {
await crawl("commands",cmdFiles);
client.logger.log(`Loading a total of ${cmdFiles.length} commands.`);
cmdFiles.forEach(f => {
if (!f.endsWith(".js") || f.startsWith("commands\\_")) return;
if (!f.endsWith(".js") || f.startsWith("commands/_")) return;
const response = client.loadCommand(f);
if (response) console.log(response);
});

View File

@ -18,7 +18,7 @@ module.exports = (client) => {
}
return permlvl;
};
const defaultSettings = {
"prefix": "b&",
"modLogChannel": "mod-log",
@ -29,14 +29,14 @@ module.exports = (client) => {
"welcomeMessage": "Say hello to {{user}}, everyone! We all need a warm welcome sometimes :D",
"welcomeEnabled": "false"
};
client.getSettings = (guild) => {
client.settings.ensure("default", defaultSettings);
if(!guild) return client.settings.get("default");
const guildConf = client.settings.get(guild.id) || {};
return ({...client.settings.get("default"), ...guildConf});
};
client.awaitReply = async (msg, question, limit = 60000) => {
const filter = m => m.author.id === msg.author.id;
await msg.channel.send(question);
@ -47,22 +47,7 @@ module.exports = (client) => {
return false;
}
};
client.caseNumber = async (client, modlog) => {
const messages = await modlog.fetchMessages({limit:5});
const log = messages.filter(m => m.author.id === client.user.id &&
m.embeds[0] &&
m.embeds[0].type === 'rich' &&
m.embeds[0].footer &&
m.embeds[0].footer.text.startsWith('Case')
).first();
if (!log) return 1;
const thisCase = /Case\s(\d+)/.exec(log.embeds[0].footer.text);
return thisCase ? parseInt(thisCase[1]) + 1 : 1;
};
client.clean = async (client, text) => {
if (text && text.constructor.name == "Promise")
text = await text;
@ -94,41 +79,41 @@ module.exports = (client) => {
}
};
client.unloadCommand = async (commandName) => {
let command;
if (client.commands.has(commandName)) {
command = client.commands.get(commandName);
} else if (client.aliases.has(commandName)) {
command = client.commands.get(client.aliases.get(commandName));
}
if (!command) return `The command \`${commandName}\` doesn\'t seem to exist, nor is it an alias. Try again!`;
client.unloadCommand = async (commandName) => {
let command;
if (client.commands.has(commandName)) {
command = client.commands.get(commandName);
} else if (client.aliases.has(commandName)) {
command = client.commands.get(client.aliases.get(commandName));
}
if (!command) return `The command \`${commandName}\` doesn\'t seem to exist, nor is it an alias. Try again!`;
if (command.shutdown) {
await command.shutdown(client);
}
const mod = require.cache[require.resolve(`../commands/${command.help.category}/${command.help.name}`)];
delete require.cache[require.resolve(`../commands/${command.help.category}/${command.help.name}.js`)];
for (let i = 0; i < mod.parent.children.length; i++) {
if (mod.parent.children[i] === mod) {
mod.parent.children.splice(i, 1);
break;
}
}
return false;
if (command.shutdown) {
await command.shutdown(client);
}
const mod = require.cache[require.resolve(`../commands/${command.help.category}/${command.help.name}`)];
delete require.cache[require.resolve(`../commands/${command.help.category}/${command.help.name}.js`)];
for (let i = 0; i < mod.parent.children.length; i++) {
if (mod.parent.children[i] === mod) {
mod.parent.children.splice(i, 1);
break;
}
}
return false;
};
Object.defineProperty(String.prototype, "toProperCase", {
value: function() {
return this.replace(/([^\W_]+[^\s-]*) */g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
}
});
Object.defineProperty(Array.prototype, "random", {
value: function() {
return this[Math.floor(Math.random() * this.length)];
}
});
client.wait = require("util").promisify(setTimeout);
client.randomSelection = choices => choices[Math.floor(Math.random() * choices.length)];
@ -346,9 +331,24 @@ module.exports = (client) => {
client.quoteRegex = input => `${input}`.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&');
client.fetchURL = (url, options = {}) => {
options.headers = options.headers ? { ...options.headers, "User-Agent": client.user } : { "User-Agent": client.user };
return fetch(url, options, options.type || "json").catch(error => {
client.Logger.error(error);
});
}
};
options.headers = options.headers ? { ...options.headers, "User-Agent": client.user } : { "User-Agent": client.user };
return fetch(url, options, options.type || "json").catch(error => {
client.Logger.error(error);
});
}
client.caseNumber = async (client, modlog) => {
const messages = await modlog.fetchMessages({limit:5});
const log = messages.filter(m => m.author.id === client.user.id &&
m.embeds[0] &&
m.embeds[0].type === 'rich' &&
m.embeds[0].footer &&
m.embeds[0].footer.text.startsWith('Case')
).first();
if (!log) return 1;
const thisCase = /Case\s(\d+)/.exec(log.embeds[0].footer.text);
return thisCase ? parseInt(thisCase[1]) + 1 : 1;
};
};

75
package-lock.json generated
View File

@ -90,9 +90,9 @@
}
},
"chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
},
"cli-cursor": {
"version": "2.1.0",
@ -137,19 +137,12 @@
"requires": {
"colors": ">= 0.6.0-1",
"first": "0.0.x",
"mime": "1.2.x",
"mime": ">=1.4.1",
"node_hash": "0.2.x",
"optimist": "0.3.x",
"prettyjson": "0.7.x",
"simplecrawler": "0.0.x",
"underscore": "1.4.x"
},
"dependencies": {
"mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
}
}
},
"create-error-class": {
@ -276,11 +269,11 @@
"integrity": "sha1-EpqTHr+B01BdhffAXHti0MTOag4="
},
"fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
"integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
"requires": {
"minipass": "^2.6.0"
"minipass": "^2.2.1"
}
},
"get-stream": {
@ -393,9 +386,9 @@
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"lodash": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
},
"lodash.assignin": {
"version": "4.2.0",
@ -472,39 +465,43 @@
"resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
"integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw="
},
"mime": {
"version": ">=1.4.1",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"requires": {
"minipass": "^2.9.0"
"minipass": "^2.2.1"
}
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "^1.2.5"
"minimist": "0.0.8"
}
},
"moment": {
@ -719,13 +716,13 @@
}
},
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
"integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minipass": "^2.3.5",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
@ -806,9 +803,9 @@
}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
}
}
}

View File

@ -3,18 +3,22 @@
"version": "1.0.0",
"description": "Discord bot that manages everything at my discord server.",
"main": "index.js",
"scripts": {
"start": "node index.js",
"postinstall": "node setup.js"
},
"engines": {
"node": ">=8"
},
"repository": {
"type": "git",
"url": "git+https://gitdab.com/rhearmas/cardboardbox.git"
"url": "git+https://github.com/rhearmas/cardboardbot.git"
},
"author": "rhearmas <rhearmas@gmail.com> (http://rhearmas.carrd.co)",
"bugs": {
"url": "https://gitdab.com/rhearmas/cardboardbox/issues"
"url": "https://github.com/rhearmas/cardboardbot/issues"
},
"homepage": "https://gitdab.com/rhearmas/cardboardbox#readme",
"homepage": "https://github.com/rhearmas/cardboardbot#readme",
"dependencies": {
"better-sqlite3": "^5.4.0",
"chalk": "^2.4.2",
@ -32,5 +36,8 @@
"recrawl": "^2.0.0",
"roll": "^1.2.0",
"webdict": "^0.3.0"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
}
}

View File

@ -42,7 +42,7 @@ let prompts = [
];
(async function () {
console.log("Setting Up Cardboard Box Configuration...");
console.log("Setting Up Cardboard Bot Configuration...");
await settings.defer;
if (!settings.has("default")) {
prompts = prompts.slice(1);
@ -62,6 +62,7 @@ let prompts = [
.replace("{{token}}", `"${answers.token}"`);
fs.writeFileSync("./config.js", baseConfig);
console.log("Configuration has been written, have fun!");
console.log("REMEMBER TO NEVER SHARE YOUR TOKEN WITH ANYONE!");
console.log("Configuration has been written, enjoy!");
await settings.close();
}());