Initial Commit
This commit is contained in:
commit
a0326ce5f0
|
@ -0,0 +1,4 @@
|
|||
# Prevent items from being copied into container.
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.DS_Store
|
|
@ -0,0 +1,18 @@
|
|||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.json]
|
||||
insert_final_newline = false
|
||||
|
||||
[*.md]
|
||||
indent_size = unset
|
||||
tab_width = unset
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"chase"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-restricted-syntax": [
|
||||
"warn",
|
||||
{
|
||||
"selector": "CallExpression[callee.object.name='console'][callee.property.name=/^(log)$/]",
|
||||
"message": "Do not console.log"
|
||||
}
|
||||
]
|
||||
},
|
||||
"globals": {
|
||||
"reactionMessageIds": "writable",
|
||||
"getInfoById": "readonly",
|
||||
"getConfiguration": "readonly",
|
||||
"setInfo": "writable",
|
||||
"setConfiguration": "writable",
|
||||
"elevatedServers": "readonly",
|
||||
"APIUrl": "readonly",
|
||||
"gLocale": "writable"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
* text=auto eol=lf
|
|
@ -0,0 +1,6 @@
|
|||
# Commit Options
|
||||
|
||||
* `[skip ci]` - Skip all CI
|
||||
* `[skip test]` - Skips testing if the bot can start, this also skips updating the bot
|
||||
* `[skip update]` - Skip updating production bot
|
||||
* `[skip lint]` - Skips linting
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
name: Bug Report
|
||||
about: Report incorrect or unexpected behavior
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
<!--
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files into it.
|
||||
-->
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Do '...'
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: true
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for the project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the feature request you'd like**
|
||||
A clear and concise description of what you want to have added.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
|
@ -0,0 +1,105 @@
|
|||
**Please describe the changes this PR makes and why it should be merged:**
|
||||
|
||||
<!--
|
||||
Please move lines that apply to you out of the comment:
|
||||
- Code changes have been fully tested, or there are no code changes
|
||||
- This PR includes breaking changes (methods removed or renamed, parameters moved or removed)
|
||||
- This PR **only** includes non-code changes, like changes to documentation, README, etc.
|
||||
- I have linted this PR and it passes all tests
|
||||
-->
|
||||
|
||||
<!--
|
||||
Testing Checklist Template
|
||||
|
||||
If you are doing a big change, uncomment this.
|
||||
|
||||
- [ ] Ensure submitting Ban Appeals works.
|
||||
- [ ] Ensure rejecting Ban Appeals works.
|
||||
- [ ] Ensure accepting Ban Appeals works.
|
||||
- [ ] Ensure webfront editing settings works as intended.
|
||||
- [ ] `!bl` / `/info banlist`
|
||||
- [ ] `!epoch`
|
||||
- [ ] `!gl` / `/info guildlist`
|
||||
- [ ] `!help`
|
||||
- [ ] `!invite`
|
||||
- [ ] `!membercount` / `/info membercount`
|
||||
- [ ] `!ml` / `/info mutelist`
|
||||
- [ ] `!ping` / `/info ping`
|
||||
- [ ] `!sinfo` / `/info server`
|
||||
- [ ] `!version` / `/botowner version`
|
||||
- [ ] Ensure `/alloweddiscords list` returns a list of allowed discord servers, or a message saying there is none.
|
||||
- [ ] Ensure `/alloweddiscords add` adds the discord server to the whitelist.
|
||||
- [ ] Ensure `/alloweddiscords remove` removes the discord server from the whitelist.
|
||||
- [ ] Ensure `/links list` returns a list of allowed links, or a message saying there is none.
|
||||
- [ ] Ensure `/links add` adds the link to the whitelist.
|
||||
- [ ] Ensure `/links remove` removes the link from the whitelist.
|
||||
- [ ] Ensure `/autoban list` returns a list of auto banned phrases, or a message saying there is none.
|
||||
- [ ] Ensure `/autoban add` adds the phrase to the blacklist.
|
||||
- [ ] Ensure `/autoban remove` removes the phrase from the blacklist.
|
||||
- [ ] Ensure `/autoreply list` returns a list of auto replied phrases, or a message saying there is none.
|
||||
- [ ] Ensure `/autoreply add` adds the trigger and response to the appropriate list.
|
||||
- [ ] Ensure `/autoreply remove` removes the trigger and response from the appropriate list.
|
||||
- [ ] Ensure `/badword list` returns a list of bad words, or a message saying there is none.
|
||||
- [ ] Ensure `/badword add` adds the word to the blacklist.
|
||||
- [ ] Ensure `/badword remove` removes the word from the blacklist.
|
||||
- [ ] Ensure `/ignoredm list` returns a list of ignored users, or a message saying there is none.
|
||||
- [ ] Ensure `/ignoredm add` adds the word to the ignored users.
|
||||
- [ ] Ensure `/ignoredm remove` removes the word from the ignored users.
|
||||
- [ ] Ensure `/ban` (In Guild) works as intended, and that it sends them a DM if their DMs are open.
|
||||
- [ ] Ensure `/ban` (Not In Guild) works as intended.
|
||||
- [ ] Ensure `/clearhistory` removes every punishment from said user. Use `/lookup` to confirm.
|
||||
- [ ] Ensure `/clearwarns` removes every warning from said user. Use `/lookup` to confirm.
|
||||
- [ ] Ensure `/duration` changes a users punishments. Use `/lookup` to confirm.
|
||||
- [ ] Ensure `/editcase` edits the case, and has the correct spacing.
|
||||
- [ ] Ensure `/kick` works as intended.
|
||||
- [ ] Ensure `/lockdown start` works as intended.
|
||||
- [ ] Ensure `/lockdown end` works as intended.
|
||||
- [ ] Ensure `/lookup` shows punishment information.
|
||||
- [ ] Ensure `/lookup` (Hide punishments) works as intended.
|
||||
- [ ] Ensure `/mute` (Perma) (In Guild) works as intended.
|
||||
- [ ] Ensure `/mute` (Perma) (Not In Guild) works as intended.
|
||||
- [ ] Ensure `/mute` (Temp) (In Guild) works as intended.
|
||||
- [ ] Ensure `/mute` (Temp) (Not In Guild) works as intended.
|
||||
- [ ] Ensure `/nick` works as intended.
|
||||
- [ ] Ensure `/note add` works as intended.
|
||||
- [ ] Ensure `/note remove` works as intended.
|
||||
- [ ] Ensure `/prune amount` works as intended.
|
||||
- [ ] Ensure `/prune user` works as intended.
|
||||
- [ ] Ensure `/prune after` works as intended.
|
||||
- [ ] Ensure `/slowmode start` works as intended.
|
||||
- [ ] Ensure `/slowmode end` works as intended.
|
||||
- [ ] Ensure `/softban` works as intended.
|
||||
- [ ] Ensure `/unban` works as intended.
|
||||
- [ ] Ensure `/unmute` works as intended.
|
||||
- [ ] Ensure `/warn` works as intended.
|
||||
- [ ] Ensure `/broadcast` works as intended.
|
||||
- [ ] Ensure `/debug` treats you as a normal user. (Test with auto replies?)
|
||||
- [ ] Ensure `/say` works (normal text, just image, multiple images, normal text + image, normal text + multiple images) as intended.
|
||||
- [ ] Ensure `/edit` works as intended.
|
||||
- [ ] Ensure `/embed` works as intended.
|
||||
- [ ] Ensure `Apps > Translate` works as intended.
|
||||
- [ ] Ensure `/botowner generateinvite` works as intended.
|
||||
- [ ] Ensure `/respond` works as intended.
|
||||
- [ ] Ensure `/pfp` works as intended. (Self & Other User)
|
||||
- [ ] Ensure `/remindme` works as intended.
|
||||
- [ ] Ensure `/sale` works as intended.
|
||||
- [ ] Ensure `/schedule` works as intended.
|
||||
- [ ] Ensure `/botowner senddm` works as intended.
|
||||
- [ ] Ensure `/suggest` works as intended.
|
||||
- [ ] Ensure `Apps > Report Message` works as intended.
|
||||
- [ ] Ensure `Apps > User Information` works as intended.
|
||||
- [ ] Ensure `/botowner banserver` works as intended.
|
||||
- [ ] Ensure `/botowner unbanserver` works as intended.
|
||||
- [ ] Ensure `/botowner version` works as intended.
|
||||
- [ ] Ensure `/botowner purgename` works as intended.
|
||||
- [ ] Ensure `/botowner printroles` works as intended.
|
||||
- [ ] Ensure `/botowner printchannels` works as intended.
|
||||
- [ ] Ensure `/botowner badnames` works as intended.
|
||||
- [ ] Ensure `/rolepersist` works as intended.
|
||||
- [ ] Ensure `/giveaway` works as intended.
|
||||
- [ ] Ensure `/bootstrap` works as intended.
|
||||
- [ ] Ensure `/selectroles` works as intended.
|
||||
- [ ] Ensure `/ticket` works as intended.
|
||||
- [ ] Ensure `/serverstats` works as intended.
|
||||
|
||||
-->
|
|
@ -0,0 +1,6 @@
|
|||
# Secrets
|
||||
|
||||
* `GH_PAT` - A GitHub [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) with `repo` permissions.
|
||||
* `HOST` - A hostname of a SSH server to use for the `update.yml` workflow.
|
||||
* `PRIVATE_KEY` - A private SSH key to use for the `update.yml` workflow.
|
||||
* `VALID_CONFIG_TESTING` - An entire valid `config.json` file with `isWorkflow` set to `true` for the `test.yml` workflow. (Creating a dummy bot in one server is recommended.)
|
|
@ -0,0 +1,15 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The only supported version of the bot is the latest commit. Nothing else is supported by us.
|
||||
|
||||
## Testing
|
||||
|
||||
If you believe you have found a vulnerability, be sure you test it in the latest commit.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you believe you have discovered a vulnerability or exploit and ensured it happens on the latest commit, please reach out to `c@chse.dev`
|
||||
|
||||
**Do not make a GitHub Issue for a security vulnerability.**
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
bot:
|
||||
- commands/**/*
|
||||
- events/**/*
|
||||
- utils/**/*
|
||||
- config.json.example
|
||||
- index.js
|
||||
|
||||
epoch:
|
||||
- webfront/epoch/**/*
|
||||
|
||||
webfront:
|
||||
- any: ["webfront/**/*", "!webfront/epoch/**/*"]
|
||||
|
||||
localization:
|
||||
- locale/**/*
|
||||
|
||||
dependencies:
|
||||
- package.json
|
||||
- package-lock.json
|
||||
- .github/**/*
|
||||
|
||||
misc:
|
||||
- README.md
|
||||
- LICENSE.md
|
||||
- .gitignore
|
||||
- .gitattributes
|
||||
- .eslintrc.json
|
||||
- .github/**/*
|
||||
- .vscode/**/*
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
- name: "bot"
|
||||
color: "e7e7e7"
|
||||
description: "Changes related to the main bot"
|
||||
- name: "bug"
|
||||
color: "d73a4a"
|
||||
description: "Something isn't working"
|
||||
- name: "dependencies"
|
||||
color: "0052cc"
|
||||
description: "Pull requests that update a dependency file"
|
||||
- name: "documentation"
|
||||
color: "0075ca"
|
||||
description: "Improvements or additions to documentation"
|
||||
- name: "duplicate"
|
||||
color: "cfd8d7"
|
||||
description: "This issue or pull request already exists"
|
||||
- name: "enhancement"
|
||||
color: "a22eef"
|
||||
description: "New feature or request"
|
||||
- name: "epoch"
|
||||
color: "f8f8f2"
|
||||
description: "Changes related to epoch site"
|
||||
- name: "github_actions"
|
||||
color: "f8f8f2"
|
||||
description: "Pull requests that update GitHub Actions code"
|
||||
- name: "good first issue"
|
||||
color: "7057ff"
|
||||
description: "Good for newcomers"
|
||||
- name: "held up"
|
||||
color: "f8f8f2"
|
||||
description: "This issue or pull request is held up"
|
||||
- name: "help wanted"
|
||||
color: "008672"
|
||||
description: "Extra attention is needed"
|
||||
- name: "invalid"
|
||||
color: "e6e6fa"
|
||||
description: "This doesn't seem right"
|
||||
- name: "localization"
|
||||
color: "0052cc"
|
||||
description: "Pull requests that update localization files"
|
||||
- name: "misc"
|
||||
color: "ffffff"
|
||||
description: "Changes that aren't directly related to any source"
|
||||
- name: "question"
|
||||
color: "cc317c"
|
||||
description: "Further information is needed"
|
||||
- name: "webfront"
|
||||
color: "f8f8f2"
|
||||
description: "Changes related to the webfront"
|
||||
- name: "wontfix"
|
||||
color: "ffffff"
|
||||
description: "This will not be worked on"
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
##########################
|
||||
## Hadolint config file ##
|
||||
##########################
|
||||
ignored: [DL3018]
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"tagname-lowercase": true,
|
||||
"attr-lowercase": true,
|
||||
"attr-value-double-quotes": true,
|
||||
"attr-value-not-empty": false,
|
||||
"attr-no-duplication": true,
|
||||
"doctype-first": true,
|
||||
"tag-pair": true,
|
||||
"tag-self-close": false,
|
||||
"spec-char-escape": false,
|
||||
"id-unique": true,
|
||||
"src-not-empty": true,
|
||||
"title-require": false,
|
||||
"alt-require": true,
|
||||
"doctype-html5": true,
|
||||
"id-class-value": false,
|
||||
"style-disabled": false,
|
||||
"inline-style-disabled": false,
|
||||
"inline-script-disabled": false,
|
||||
"space-tab-mixed-disabled": "space",
|
||||
"id-class-ad-disabled": false,
|
||||
"href-abs-or-rel": false,
|
||||
"attr-unsafe-chars": true,
|
||||
"head-script-disabled": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "stylelint-config-standard",
|
||||
"rules": {
|
||||
"selector-class-pattern": null,
|
||||
"no-missing-end-of-source-newline": null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
name: "📦️ Auto Merge Dependency Updates"
|
||||
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tjenkinson/gh-action-auto-merge-dependency-updates@v1
|
||||
with:
|
||||
allowed-actors: dependabot[bot]
|
||||
allowed-update-types: devDependencies:minor, devDependencies:patch, devDependencies:major
|
||||
merge-method: squash
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
name: "🏷️ Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
sync-labels: true
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: "🏷️ Label Sync"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/labels.yml"
|
||||
jobs:
|
||||
labelsync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "🏷️ Label Sync"
|
||||
uses: crazy-max/ghaction-github-labeler@v4
|
||||
with:
|
||||
github-token: ${{ secrets.GH_PAT }}
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
name: "🎨 Lint"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip lint]')
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "📦️ Install Dependencies"
|
||||
run: |
|
||||
npm install
|
||||
|
||||
- name: "🎨 ESLint"
|
||||
run: npx eslint . --ext .js,.jsx,.ts,.tsx
|
||||
|
||||
- name: "🎨 Super-Linter"
|
||||
uses: github/super-linter/slim@v4
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
DEFAULT_BRANCH: main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VALIDATE_JAVASCRIPT_ES: false
|
||||
VALIDATE_JAVASCRIPT_STANDARD: false
|
||||
VALIDATE_JSX: false
|
||||
VALIDATE_TSX: false
|
||||
VALIDATE_TYPESCRIPT_ES: false
|
||||
VALIDATE_TYPESCRIPT_STANDARD: false
|
||||
VALIDATE_JSCPD: false
|
||||
VALIDATE_MARKDOWN: false
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
name: "🔒 Lock Resolved Issues/PRs"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
issues:
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: chxseh/action-lock-unlock@v1.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
lock: true
|
||||
lock-reason: resolved
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
name: "🔓 Unlock Reopened Issues/PRs"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- reopened
|
||||
issues:
|
||||
types:
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: chxseh/action-lock-unlock@v1.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
lock: false
|
|
@ -0,0 +1,50 @@
|
|||
name: Sync Docs to Wiki
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "docs/**"
|
||||
repository_dispatch:
|
||||
types: [docs]
|
||||
gollum:
|
||||
|
||||
env:
|
||||
GIT_AUTHOR_NAME: Actionbot
|
||||
GIT_AUTHOR_EMAIL: actions@github.com
|
||||
|
||||
jobs:
|
||||
job-sync-docs-to-wiki:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'gollum'
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Sync docs to wiki
|
||||
uses: newrelic/wiki-sync-action@master
|
||||
with:
|
||||
source: docs
|
||||
destination: wiki
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
gitAuthorName: ${{ env.GIT_AUTHOR_NAME }}
|
||||
gitAuthorEmail: ${{ env.GIT_AUTHOR_EMAIL }}
|
||||
|
||||
job-sync-wiki-to-docs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'gollum'
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }} # allows us to push back to repo
|
||||
ref: main
|
||||
- name: Sync Wiki to Docs
|
||||
uses: newrelic/wiki-sync-action@master
|
||||
with:
|
||||
source: wiki
|
||||
destination: docs
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
gitAuthorName: ${{ env.GIT_AUTHOR_NAME }}
|
||||
gitAuthorEmail: ${{ env.GIT_AUTHOR_EMAIL }}
|
||||
branch: main
|
|
@ -0,0 +1,12 @@
|
|||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Private Data
|
||||
config.json
|
||||
db.*
|
||||
## Ignore all guild import/export data:
|
||||
*port.json
|
||||
|
||||
# Misc
|
||||
*.bak
|
||||
.DS_Store
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"github.vscode-pull-request-github",
|
||||
"eamodio.gitlens",
|
||||
"aaron-bond.better-comments",
|
||||
"EditorConfig.EditorConfig"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": true,
|
||||
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||
"javascript.format.placeOpenBraceOnNewLineForFunctions": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": true,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.tabSize": 4,
|
||||
"files.eol": "\n",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
FROM node:16-alpine
|
||||
RUN apk add --no-cache git
|
||||
USER daemon
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production
|
||||
COPY . .
|
||||
# EXPOSE 5000
|
||||
# HEALTHCHECK --interval=5m --timeout=3s \
|
||||
# CMD curl -f http://localhost:5000/debug || exit 1
|
||||
# CMD [ "node", "." ]
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 Chase
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,52 @@
|
|||
<div align="center">
|
||||
<h1>Discord Bot<br>
|
||||
<a href="https://github.com/chxseh/discord-bot/actions/workflows/linter.yml"><img alt="GitHub Actions Status" src="https://github.com/chxseh/discord-bot/actions/workflows/linter.yml/badge.svg"></a>
|
||||
<a href="https://github.com/chxseh/discord-bot/stargazers"><img alt="GitHub stars" src="https://badges.chse.dev:/github/stars/chxseh/discord-bot"></a>
|
||||
<a href="https://github.com/chxseh/discord-bot/issues"><img alt="GitHub issues" src="https://badges.chse.dev:/github/issues/chxseh/discord-bot"></a>
|
||||
<a href="https://github.com/chxseh/discord-bot/pulls"><img alt="GitHub Pull Requests" src="https://badges.chse.dev:/github/issues-pr/chxseh/discord-bot"></a>
|
||||
<a href="https://github.com/chxseh/discord-bot/network"><img alt="GitHub forks" src="https://badges.chse.dev:/github/forks/chxseh/discord-bot"></a>
|
||||
<a href="https://github.com/chxseh/discord-bot/blob/main/LICENSE.md"><img alt="GitHub license" src="https://badges.chse.dev:/github/license/chxseh/discord-bot"></a>
|
||||
</h1></div>
|
||||
|
||||
# Table of Contents <!-- omit in toc -->
|
||||
- [Installation](#installation)
|
||||
- [Setup](#setup)
|
||||
- [Normal Installation](#normal-installation)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation-1)
|
||||
- [Webfront Setup](#webfront-setup)
|
||||
|
||||
## Installation
|
||||
|
||||
### Setup
|
||||
1. Create a new [Discord Application](https://discord.com/developers/applications).
|
||||
2. Make it a Bot account.
|
||||
3. Enable `Server Members Intent`, and `Message Content Intent` under Privileged Gateway Intents.
|
||||
4. Proceed with the [installation](#installation).
|
||||
5. Setup the [Webfront Configuration](#webfront-configuration)
|
||||
|
||||
### Normal Installation
|
||||
|
||||
#### Requirements
|
||||
- [Git](https://git-scm.com/)
|
||||
- [Node.js](https://nodejs.org/) >= v16.14.0
|
||||
- [pm2](https://www.npmjs.com/package/pm2) (`npm i -g pm2`)
|
||||
|
||||
#### Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/chxseh/discord-bot.git
|
||||
cd bot
|
||||
npm ci
|
||||
```
|
||||
> For the initial setup, use `npm start`. After initial setup is completed you can use `pm2 start npm --name "bot" -- start` to keep the bot running.
|
||||
|
||||
### Webfront Setup
|
||||
|
||||
For the webfront to work, you must set a OAuth2 Redirect URL in your Discord Application.
|
||||
|
||||
The redirect should be `https://yourDomain.com/discord/callback`
|
||||
|
||||
![img](https://i.imgur.com/f6KsPBs.png)
|
||||
|
||||
<!-- ### For more information, please see [the wiki](https://github.com/chxseh/discord-bot/wiki). --> <!-- omit in toc -->
|
|
@ -0,0 +1,10 @@
|
|||
version: '2'
|
||||
services:
|
||||
bot:
|
||||
build: .
|
||||
command: node .
|
||||
volumes:
|
||||
- .:/app/
|
||||
- /app/node_modules
|
||||
ports:
|
||||
- "5000:5000"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "bot",
|
||||
"version": "1.0.0",
|
||||
"description": "A powerful Discord Bot for large servers.",
|
||||
"main": "./src/app.js",
|
||||
"engines": {
|
||||
"node": ">=16.14.0"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node .",
|
||||
"lint": "eslint --fix --ext .js .",
|
||||
"sync-i18n": "sync-i18n --files ./locale/*.json --primary en --space 4"
|
||||
},
|
||||
"author": "Chase <c@chse.dev> (https://chse.dev)",
|
||||
"contributors": [
|
||||
"mikzy <> (https://github.com/mjkzy)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "8.0.1",
|
||||
"chalk": "5.2.0",
|
||||
"dbd-dark-dashboard": "1.6.592",
|
||||
"discord-dashboard": "2.3.492",
|
||||
"discord.js": "14.7.1",
|
||||
"node-fetch": "3.3.0",
|
||||
"readline-sync": "1.4.10",
|
||||
"string-table": "0.1.5",
|
||||
"unidecode-plus": "1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.33.0",
|
||||
"eslint-config-chase": "1.0.5",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsdoc": "39.7.5",
|
||||
"eslint-plugin-unicorn": "45.0.2",
|
||||
"i18next-json-sync": "3.1.2"
|
||||
},
|
||||
"homepage": "https://github.com/chxseh/discord-bot",
|
||||
"keywords": [
|
||||
"discord",
|
||||
"discord.js",
|
||||
"discordjs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chxseh/discord-bot.git"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
import fs from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import Discord from "discord.js";
|
||||
import SQLite from "better-sqlite3";
|
||||
import bootWeb from "./webfront/index.js";
|
||||
import logging from "./utils/logging.js";
|
||||
import common from "./utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
const client = new Discord.Client({
|
||||
partials: [Discord.Partials.Channel],
|
||||
intents: [
|
||||
Discord.GatewayIntentBits.Guilds,
|
||||
Discord.GatewayIntentBits.GuildMembers,
|
||||
Discord.GatewayIntentBits.GuildBans,
|
||||
Discord.GatewayIntentBits.GuildMessages,
|
||||
Discord.GatewayIntentBits.MessageContent,
|
||||
Discord.GatewayIntentBits.GuildMessageReactions,
|
||||
Discord.GatewayIntentBits.DirectMessages,
|
||||
Discord.GatewayIntentBits.GuildVoiceStates,
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* @name loadLocalization
|
||||
* @description Loads the localization files.
|
||||
*/
|
||||
async function loadLocalization()
|
||||
{
|
||||
global.locale = {};
|
||||
// Load all JSON files in ./locale and JSON parse them, then add them to the global.locale object
|
||||
const locales = fs.readdirSync(`./src/locale`).filter((file) => file.endsWith(`.json`));
|
||||
for (const locale of locales)
|
||||
{
|
||||
const data = JSON.parse(fs.readFileSync(`./src/locale/${ locale }`));
|
||||
const localeName = locale.split(`.`)[0];
|
||||
global.locale[localeName] = data;
|
||||
}
|
||||
|
||||
// Get the defined locale from the config file
|
||||
const { locale } = require(`./config.json`);
|
||||
global.gLocale = locale;
|
||||
}
|
||||
|
||||
await initSetup();
|
||||
|
||||
await loadLocalization(); // load all localizations first, so we can translate everything below.
|
||||
|
||||
const { token, isWorkflow, debugMode } = require(`./config.json`);
|
||||
if (token.length < 50)
|
||||
logging.error(`${ global.locale[global.gLocale].invalidToken } `, true);
|
||||
|
||||
global.reactionMessageIds = []; // React to Delete Bot Message 1
|
||||
global.elevatedServers = [`808962821697306654`, `872330479565680640`]; // Prod & testing
|
||||
|
||||
await setupDB();
|
||||
await setupCommands();
|
||||
|
||||
client.login(token);
|
||||
bootWeb(client, Discord);
|
||||
|
||||
if (!isWorkflow && !debugMode)
|
||||
{ // catch everything if not workflow AND not dev env
|
||||
process.on(`unhandledRejection`, (error) =>
|
||||
{
|
||||
const d8 = new Date(Date.now());
|
||||
logging.error(`${ global.locale[global.gLocale].unhandledRejection } [${ d8.toDateString() } ${ d8.toTimeString() }]: ${ error }`, false, true);
|
||||
});
|
||||
|
||||
process.on(`uncaughtException`, (error) =>
|
||||
{
|
||||
const d8 = new Date(Date.now());
|
||||
logging.error(`${ global.locale[global.gLocale].uncaughtException } [${ d8.toDateString() } ${ d8.toTimeString() }]: ${ error }`, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name initSetup
|
||||
* @description Setup config.json if it doesn't exist.
|
||||
*/
|
||||
async function initSetup()
|
||||
{
|
||||
if (fs.existsSync(`./src/config.json`))
|
||||
{
|
||||
const rawConfig = fs.readFileSync(`./src/config.json`);
|
||||
const config = JSON.parse(rawConfig);
|
||||
const rawDefaultConfig = fs.readFileSync(`./src/config.json.example`);
|
||||
const defaultConfig = JSON.parse(rawDefaultConfig);
|
||||
for (const key in defaultConfig)
|
||||
{ // If we already have a config, check and see if everything from defaultConfig is set.
|
||||
if (!(key in config))
|
||||
config[key] = defaultConfig[key];
|
||||
}
|
||||
for (const key in config)
|
||||
{ // Clean Legacy Config Options. (If something in config is not in defaultConfig, remove it from config).
|
||||
if (!(key in defaultConfig))
|
||||
delete config[key];
|
||||
}
|
||||
fs.writeFileSync(`./src/config.json`, JSON.stringify(config, undefined, 4));
|
||||
return;
|
||||
}
|
||||
|
||||
fs.copyFileSync(`./src/config.json.example`, `./src/config.json`);
|
||||
|
||||
var readlineSync = require(`readline-sync`);
|
||||
|
||||
let localeList = fs.readdirSync(`./src/locale`).filter((file) => file.endsWith(`.json`));
|
||||
localeList = localeList.map((file) => file.split(`.`)[0]);
|
||||
localeList = localeList.join(`, `);
|
||||
|
||||
let locale = readlineSync.question(`Please enter your locale (${ localeList }): `).trim().toLowerCase();
|
||||
const locales = fs.readdirSync(`./src/locale`).filter((file) => file.endsWith(`.json`));
|
||||
if (!locales.includes(`${ locale }.json`))
|
||||
locale = `en`; // Set to en if the locale is not found.
|
||||
|
||||
// Load locales
|
||||
await loadLocalization();
|
||||
|
||||
let token = ``;
|
||||
do
|
||||
{
|
||||
token = readlineSync.question(`${ global.locale[locale].setupBotToken } `, {
|
||||
hideEchoBack: true,
|
||||
});
|
||||
}
|
||||
while (token.length < 50);
|
||||
|
||||
let clientSecret = ``;
|
||||
do
|
||||
{
|
||||
clientSecret = readlineSync.question(`${ global.locale[locale].setupClientSecret } `, {
|
||||
hideEchoBack: true,
|
||||
});
|
||||
}
|
||||
while (clientSecret.length < 20);
|
||||
|
||||
let botOwners = readlineSync.question(`${ global.locale[locale].setupBotOwners } `);
|
||||
if (botOwners.length > 1)
|
||||
{
|
||||
botOwners = botOwners.split(`,`);
|
||||
for (let index = 0; index < botOwners.length; index++)
|
||||
botOwners[index] = botOwners[index].trim(); // this also handles "1, 2, 3"
|
||||
}
|
||||
else
|
||||
botOwners = [];
|
||||
|
||||
const playingStatus = readlineSync.question(`${ global.locale[locale].setupPlayingStatus } `);
|
||||
|
||||
let debugMode = readlineSync.question(`${ global.locale[locale].setupDebugMode } `);
|
||||
debugMode = !(debugMode.toLowerCase() !== `true` && debugMode.toLowerCase() !== `y` && debugMode.toLowerCase !== `yes`);
|
||||
|
||||
let forwardDMs = readlineSync.question(`${ global.locale[locale].setupForwardDM } `);
|
||||
forwardDMs = !(forwardDMs.toLowerCase() !== `true` && forwardDMs.toLowerCase() !== `y` && forwardDMs.toLowerCase !== `yes`);
|
||||
|
||||
// ask what port to use
|
||||
let webfrontPort = readlineSync.question(`${ global.locale[locale].setupWebfrontPort } `);
|
||||
webfrontPort = webfrontPort.trim();
|
||||
webfrontPort = webfrontPort.length === 0 ? 5000 : Number.parseInt(webfrontPort, 10);
|
||||
if (Number.isNaN(webfrontPort) || webfrontPort < 1000 || webfrontPort > 65_534)
|
||||
{
|
||||
webfrontPort = 5000;
|
||||
logging.log(`${ global.locale[locale].setupInvalidPort }`);
|
||||
}
|
||||
|
||||
// ask what url to use (default: http://localhost:port)
|
||||
var url = readlineSync.question(`${ global.locale[locale].setupWebfrontURL.replaceAll(`%webfrontPort%`, `${ webfrontPort }`) } `);
|
||||
if (url.length === 0 || !url.startsWith(`http`))
|
||||
url = `http://localhost:${ webfrontPort }`;
|
||||
// remove trailing slash if found
|
||||
if (url.endsWith(`/`))
|
||||
url = url.slice(0, Math.max(0, url.length - 1));
|
||||
|
||||
// ask for their webfront api key
|
||||
var webfrontAPIKey = ``;
|
||||
do
|
||||
webfrontAPIKey = readlineSync.question(`${ global.locale[locale].setupWebfrontAPIKey } `);
|
||||
while (webfrontAPIKey.length < 20);
|
||||
|
||||
readlineSync.question(`\n${ global.locale[locale].setupOauthRedirect.replaceAll(`%url%`, `${ url }`) }\n`);
|
||||
|
||||
const config = require(`./config.json`);
|
||||
config.token = token.trim();
|
||||
config.locale = locale;
|
||||
config.botOwnerID = botOwners;
|
||||
config.playingStatus = playingStatus.trim();
|
||||
config.clientSecret = clientSecret.trim();
|
||||
config.debugMode = debugMode;
|
||||
config.forwardDMs = forwardDMs;
|
||||
config.webfrontPort = webfrontPort;
|
||||
config.webfrontURL = url.trim();
|
||||
config.webfrontAPIKey = webfrontAPIKey.trim();
|
||||
fs.writeFileSync(`./src/config.json`, JSON.stringify(config, undefined, 4)); // save settings to config
|
||||
}
|
||||
|
||||
/**
|
||||
* @name setupCommands
|
||||
* @description Loads and prepares Chat/Slash Commands & Events.
|
||||
*/
|
||||
async function setupCommands()
|
||||
{
|
||||
// slash commands
|
||||
client.commands = new Discord.Collection();
|
||||
client.chatcommands = new Discord.Collection();
|
||||
|
||||
const commandFolders = fs.readdirSync(`./src/commands/slash_commands`);
|
||||
const chatcommandFolders = fs.readdirSync(`./src/commands/chat_commands`);
|
||||
|
||||
let numberFailed = 0;
|
||||
|
||||
for (const folder of commandFolders)
|
||||
{
|
||||
const commandFiles = fs.readdirSync(`./src/commands/slash_commands/${ folder }`).filter((file) => file.endsWith(`.js`));
|
||||
for (const file of commandFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
let command = await import(`./commands/slash_commands/${ folder }/${ file }`);
|
||||
command = command.default || command;
|
||||
command = await injectLocale(command);
|
||||
client.commands.set(command.name, command);
|
||||
if (command.elevatedOnly)
|
||||
common.elevatedCommands.push(command);
|
||||
else
|
||||
common.commands.push(command);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logging.error(`${ global.locale[global.gLocale].failedToLoadCommand.replaceAll(`%file%`, file).replaceAll(`%error%`, error) }`);
|
||||
numberFailed += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const folder of chatcommandFolders)
|
||||
{
|
||||
const commandFiles = fs.readdirSync(`./src/commands/chat_commands/${ folder }`).filter((file) => file.endsWith(`.js`));
|
||||
for (const file of commandFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
let command = await import(`./commands/chat_commands/${ folder }/${ file }`);
|
||||
command = command.default || command;
|
||||
client.chatcommands.set(command.name, command);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
logging.error(`${ global.locale[global.gLocale].failedToLoadCommand.replaceAll(`%file%`, file).replaceAll(`%error%`, error) }`);
|
||||
numberFailed += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logging.log(`${ global.locale[global.gLocale].loadedCommands.replaceAll(`%numberFailed%`, numberFailed) }`);
|
||||
|
||||
// events
|
||||
const eventFiles = fs.readdirSync(`./src/events`).filter((file) => file.endsWith(`.js`));
|
||||
for (const file of eventFiles)
|
||||
{
|
||||
let event = await import(`./events/${ file }`);
|
||||
event = event.default || event;
|
||||
if (event.once)
|
||||
client.once(event.name, (...ourArguments) => event.execute(...ourArguments, Discord, client));
|
||||
else
|
||||
client.on(event.name, (...ourArguments) => event.execute(...ourArguments, Discord, client));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name setupDB
|
||||
* @description Create the database if it doesn't exist.
|
||||
*/
|
||||
async function setupDB()
|
||||
{
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS punishments (guildAndUserId TEXT, guildId TEXT, id TEXT, warns TEXT, mutes TEXT, kicks TEXT, bans TEXT, punishmentreason TEXT, punishmentinfo TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_punishments ON punishments (guildAndUserId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS mutes (guildAndUserId TEXT, guildId TEXT, userId TEXT, time TEXT, moderatorId TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_mutes ON mutes (guildAndUserId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS allowedLinks (guildId TEXT, link TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS autoBannedPhrases (guildId TEXT, phrase TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS badWords (guildId TEXT, word TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS badNames (guildId TEXT, name TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS allowedDiscords (guildId TEXT, id TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS keywords (guildId TEXT, phrase TEXT, response TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS keywordsRegional (guildId TEXT, phrase TEXT, response TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS scheduledMessages (guildId TEXT, channelId TEXT, time TEXT, content TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS memberCounts (guildId TEXT, count TEXT, time TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_mc_gid ON memberCounts (guildId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS banAppealTokens (guildId TEXT, userId TEXT, token TEXT, threadId TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS configuration (guildId TEXT PRIMARY KEY, config TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_configuration_guildId ON configuration (guildId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS keywordSpam (guildId TEXT, userId TEXT, count TEXT, time TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS doNotForwardDMsFrom (userId TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS userNotes (guildAndUserId TEXT, userId TEXT, guildId TEXT, note TEXT, meta TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_userNotes_guildAndUserId ON userNotes (guildAndUserId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS bannedServers (guildId TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS tempbanUsers (guildAndUserId TEXT, guildId TEXT, userId TEXT, time TEXT, moderatorId TEXT);`).run();
|
||||
sql.prepare(`CREATE UNIQUE INDEX IF NOT EXISTS idx_tempbans ON tempbanUsers (guildAndUserId);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS rolePersists (guildId TEXT, userId TEXT, roleArray TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS giveaways (guildId TEXT, messageId TEXT, time TEXT, amountOfWinners TEXT, channelId TEXT);`).run();
|
||||
sql.prepare(`CREATE TABLE IF NOT EXISTS giveawayEntries (guildId TEXT, messageId TEXT, userId TEXT);`).run();
|
||||
sql.pragma(`synchronous = 1`);
|
||||
sql.pragma(`journal_mode = wal`);
|
||||
process.on(`exit`, () => sql.close());
|
||||
process.on(`SIGHUP`, () => process.exit(128 + 1));
|
||||
process.on(`SIGINT`, () => process.exit(128 + 2));
|
||||
process.on(`SIGTERM`, () => process.exit(128 + 15));
|
||||
|
||||
// punishment variables (quick access)
|
||||
global.getInfoById = sql.prepare(`SELECT * FROM punishments WHERE guildId = ? AND id = ?;`);
|
||||
global.setInfo = sql.prepare(`INSERT OR REPLACE INTO punishments (guildAndUserId, guildId, id, warns, mutes, kicks, bans, punishmentreason, punishmentinfo) VALUES (@guildAndUserId, @guildId, @id, @warns, @mutes, @kicks, @bans, @punishmentreason, @punishmentinfo);`);
|
||||
|
||||
// guild configuration variables
|
||||
global.getConfiguration = sql.prepare(`SELECT * FROM configuration WHERE guildId = ?`);
|
||||
global.setConfiguration = sql.prepare(`INSERT OR REPLACE INTO configuration (guildId, config) VALUES (@guildId, @config);`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name injectLocale
|
||||
* @description Inject Localization into Slash Commands (https://discord.com/developers/docs/interactions/application-commands#localization)
|
||||
* @param {object} command The command object to inject the locale into.
|
||||
*/
|
||||
async function injectLocale(command)
|
||||
{
|
||||
// https://discord.com/developers/docs/reference#locales
|
||||
const discordLocales = [`da`, `de`, `en-GB`, `en-US`, `es-ES`, `fr`, `hr`, `it`, `lt`, `hu`, `nl`, `no`, `pl`, `pt-BR`, `ro`, `fi`, `sv-SE`, `vi`, `tr`, `cs`, `el`, `bg`, `ru`, `uk`, `hi`, `th`, `zh-CN`, `ja`, `zh-TW`, `ko`];
|
||||
command.nameLocalizations = {};
|
||||
command.descriptionLocalizations = {};
|
||||
for (const locale of discordLocales)
|
||||
{
|
||||
let splitLocale = locale;
|
||||
if (splitLocale.includes(`-`))
|
||||
splitLocale = splitLocale.split(`-`)[0];
|
||||
|
||||
// Inject nameLocalizations & descriptionLocalizations into the command
|
||||
let commandName = `${ command.name }CommandName`;
|
||||
commandName = commandName.replaceAll(` `, `_`);
|
||||
const commandDescription = `${ command.name }CommandDescription`;
|
||||
const workingLocale = global.findLocale(undefined, splitLocale);
|
||||
if (workingLocale !== `en`)
|
||||
{
|
||||
// Add commandName to the findLocale
|
||||
command.nameLocalizations = { ...command.nameLocalizations, [locale]: global.findLocaleString(workingLocale, commandName) };
|
||||
if (command.description)
|
||||
// eslint-disable-next-line max-len
|
||||
command.descriptionLocalizations = { ...command.descriptionLocalizations, [locale]: global.findLocaleString(workingLocale, commandDescription) };
|
||||
|
||||
// For each option in the command, inject the locale into the option
|
||||
if (command.options)
|
||||
{
|
||||
for (let index = 0; index < command.options.length; index++)
|
||||
{
|
||||
const option = command.options[index];
|
||||
let optionName = `${ command.name }OptionName${ index }`;
|
||||
optionName = optionName.replaceAll(` `, `_`);
|
||||
const optionDescription = `${ command.name }OptionDescription${ index }`;
|
||||
if (workingLocale !== `en`)
|
||||
{
|
||||
// Add optionName to the findLocale
|
||||
option.nameLocalizations = { ...option.nameLocalizations, [locale]: global.findLocaleString(workingLocale, optionName) };
|
||||
if (option.description)
|
||||
// eslint-disable-next-line max-len
|
||||
option.descriptionLocalizations = { ...option.descriptionLocalizations, [locale]: global.findLocaleString(workingLocale, optionDescription) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { banlist } from "../../commands/informational/banlist.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `banlist`,
|
||||
aliases: [`bl`],
|
||||
async execute(message)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
banlist(message, false);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { webfrontURL } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `epoch`,
|
||||
async execute(message)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].seeWebfrontEpoch.replaceAll(`%webfrontURL%`, `${ webfrontURL }`) }`)
|
||||
.then((message) =>
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
message.delete();
|
||||
}, 15_000);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { createRequire } from "node:module";
|
||||
import { guildlist } from "../../commands/informational/guildlist.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `guildlist`,
|
||||
aliases: [`gl`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
guildlist(message, false, Discord, client, (ourArguments[0] === `true`));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { webfrontURL } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `help`,
|
||||
aliases: [`h`, `commands`, `cmd`, `cmds`, `command`],
|
||||
async execute(message)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].helpText.replaceAll(`%webfrontURL%`, `${ webfrontURL }`) }`)
|
||||
.then((message) =>
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
message.delete();
|
||||
}, 15_000);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
export default {
|
||||
name: `invite`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].botInviteText }\nhttps://discord.com/api/oauth2/authorize?client_id=${ client.user.id }&permissions=8&scope=bot%20applications.commands`)
|
||||
.then((message) =>
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
message.delete();
|
||||
}, 10_000);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
import { membercount } from "../../commands/informational/membercount.js";
|
||||
|
||||
export default {
|
||||
name: `membercount`,
|
||||
aliases: [`mc`, `members`, `membercounts`],
|
||||
async execute(message)
|
||||
{
|
||||
// If you do not have a role, you cannot use this command.
|
||||
if (message.member.roles.cache.size <= 1)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
membercount(message, false);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
import { mutelist } from "../../commands/informational/mutelist.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `mutelist`,
|
||||
aliases: [`ml`],
|
||||
async execute(message)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
mutelist(message, false);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
import { ping } from "../../commands/informational/ping.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `ping`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
ping(message, false, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
import { serverinfo } from "../../commands/informational/serverinfo.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `serverinfo`,
|
||||
aliases: [`sinfo`, `guildinfo`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (ourArguments[0])
|
||||
var guild = client.guilds.cache.get(ourArguments[0]);
|
||||
else
|
||||
var guild = client.guilds.cache.get(message.guild.id);
|
||||
|
||||
serverinfo(message, false, guild, Discord);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import { createRequire } from "node:module";
|
||||
import version from "../../commands/informational/version.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `version`,
|
||||
aliases: [`ver`],
|
||||
|
||||
async execute(message)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
await version.getCommitInfo(message, message.channel, false);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
import { list, add, remove } from "../../commands/manipulation/allowed-discords.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `alloweddiscords`,
|
||||
aliases: [`ad`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no ourArguments
|
||||
|
||||
if (ourArguments[0] !== `list` && !ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyDiscord }`);
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, message.guild.id, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
const invite = ourArguments[1];
|
||||
add(message, false, message.guild.id, invite, Discord, client);
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
const invite = ourArguments[1];
|
||||
remove(message, false, message.guild.id, invite, Discord, client);
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
import { list, add, remove } from "../../commands/manipulation/allowed-links.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `links`,
|
||||
aliases: [`link`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no argument is given
|
||||
else if (ourArguments[0] !== `list` && !ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyLink }`);
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
const newLink = ourArguments[1].toLowerCase();
|
||||
add(message, false, message.guild.id, newLink);
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
const linkToRemove = ourArguments[1].toLowerCase();
|
||||
remove(message, false, message.guild.id, linkToRemove);
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
import { list, add, remove } from "../../commands/manipulation/auto-banned-phrases.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `autoban`,
|
||||
aliases: [`ab`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no ourArguments
|
||||
|
||||
if (ourArguments[0] !== `list` && !ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyPhrases }`);
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
const newWord = ourArguments.slice(1).join(` `).toLowerCase();
|
||||
add(message, false, newWord);
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
const searchKeyword = ourArguments.slice(1).join(` `).toLowerCase();
|
||||
remove(message, false, message.guild.id, searchKeyword);
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
import { list, add, remove } from "../../commands/manipulation/auto-replies.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `autoreply`,
|
||||
aliases: [`ar`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no ourArguments
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, message.guild.id, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
if (!ourArguments[1] || !ourArguments[2] || !ourArguments[3])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyResponse }`);
|
||||
|
||||
if (ourArguments[1] === `true`)
|
||||
{
|
||||
var trigger = message.content.split(`"`)[1];
|
||||
var response = message.content.split(`"`)[3];
|
||||
if (trigger.length > 1900 || response.length > 1900)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].shortenTrig }`);
|
||||
|
||||
add(message, false, message.guild.id, trigger, response, true);
|
||||
}
|
||||
else if (ourArguments[1] === `false`)
|
||||
{
|
||||
var trigger = message.content.split(`"`)[1];
|
||||
var response = message.content.split(`"`)[3];
|
||||
if (trigger.length > 1900 || response.length > 1900)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].shortenTrig }`);
|
||||
|
||||
add(message, false, message.guild.id, trigger, response, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
if (!ourArguments[1] || !ourArguments[2])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyResponse }`);
|
||||
|
||||
if (ourArguments[1] === `true`)
|
||||
{
|
||||
var itemToSearchFor = message.content.split(`"`)[1];
|
||||
remove(message, false, message.guild.id, itemToSearchFor, true);
|
||||
}
|
||||
else if (ourArguments[1] === `false`)
|
||||
{
|
||||
var itemToSearchFor = message.content.split(`"`)[1];
|
||||
remove(message, false, message.guild.id, itemToSearchFor, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
import { list, add, remove } from "../../commands/manipulation/bad-words.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `badword`,
|
||||
aliases: [`badwords`, `banwords`, `banword`, `bannedword`, `bannedwords`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no ourArguments
|
||||
|
||||
if (ourArguments[0] !== `list` && !ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyWord }`);
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
const newWord = ourArguments.slice(1).join(` `).toLowerCase();
|
||||
add(message, false, message.guild.id, newWord);
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
const searchKeyword = ourArguments.slice(1).join(` `).toLowerCase();
|
||||
remove(message, false, message.guild.id, searchKeyword);
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
import { createRequire } from "node:module";
|
||||
import { list, add, remove } from "../../commands/manipulation/ignore-dms.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `ignoredms`,
|
||||
aliases: [`ignoredm`, `blockdm`, `blockdms`, `ignore`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id)) // dev only cuz we're cool
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = `list`; // default to list if no ourArguments
|
||||
|
||||
if (ourArguments[0] !== `list` && !ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyUserID }`);
|
||||
|
||||
switch (ourArguments[0])
|
||||
{
|
||||
case `list`: {
|
||||
list(message, false, Discord);
|
||||
break;
|
||||
}
|
||||
case `add`: {
|
||||
const uid = ourArguments[1];
|
||||
add(message, false, uid);
|
||||
break;
|
||||
}
|
||||
case `remove`:
|
||||
case `delete`:
|
||||
case `del`:
|
||||
case `rm`: {
|
||||
const uid = ourArguments[1];
|
||||
remove(message, false, uid);
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,128 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import sqlite from "../../../utils/sqlite.js";
|
||||
import mentions from "../../../utils/mentions.js";
|
||||
import logging from "../../../utils/logging.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import ban from "../../commands/moderation/ban.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `ban`,
|
||||
aliases: [`b`],
|
||||
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
const { sendDmOnBan, banAppealsLink } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!common.canRunCommand(message, `BanMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const row = sql.prepare(`SELECT * FROM tempbanUsers WHERE guildId = ? AND userId = ?`).get(message.guild.id, id);
|
||||
|
||||
if (ourArguments[1])
|
||||
{ // args[1] can either be a duration or a reason
|
||||
const Time = ourArguments[1];
|
||||
var time = await common.getEpoch(Time, false);
|
||||
if (time === -1337)
|
||||
{
|
||||
time = -1337; // perma ban
|
||||
var reason = ourArguments.slice(1).join(` `);
|
||||
if (!reason || !ourArguments[1])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
}
|
||||
else
|
||||
{
|
||||
var reason = ourArguments.slice(2).join(` `);
|
||||
if (!reason || !ourArguments[2])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
|
||||
if (row && row.time > 1)
|
||||
{ // If they are already muted, and have a punishment, take their current mute time and add the new time to it.
|
||||
time = Number.parseInt(row.time, 10) + time;
|
||||
sql.prepare(`UPDATE tempbanUsers SET time = ?, moderatorId = ? WHERE guildId = ? AND userId = ?`).run(time, message.author.id, message.guild.id, id);
|
||||
}
|
||||
else if (row && row.time < 1)
|
||||
return message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].permBanned }`);
|
||||
else
|
||||
{ // fresh temp ban
|
||||
time += Date.now();
|
||||
sql.prepare(`INSERT INTO tempbanUsers VALUES (?, ?, ?, ?, ?)`).run(`${ message.guild.id }_${ id }`, message.guild.id, id, time, message.author.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const authorTag = message.author.tag;
|
||||
|
||||
var isSilent = false;
|
||||
if (reason.includes(`--silent`))
|
||||
{
|
||||
isSilent = true; // Do not send DM upon ban.
|
||||
reason = reason.replace(`--silent`, ``);
|
||||
}
|
||||
|
||||
if (time > 0)
|
||||
var timeForMuteMeta = `${ global.locale[global.findLocale(message.guild.id)].for } ${ ourArguments[1] }`;
|
||||
else
|
||||
var timeForMuteMeta = `${ global.locale[global.findLocale(message.guild.id)].permanently }`;
|
||||
|
||||
const guild = client.guilds.cache.get(message.guild.id);
|
||||
const member = await common.getGuildMember(client, message.guild.id, id);
|
||||
if (!member)
|
||||
{
|
||||
// prevent double banning
|
||||
let isBanned = true;
|
||||
await guild.bans.fetch(id).catch(() =>
|
||||
{
|
||||
isBanned = false;
|
||||
});
|
||||
if (isBanned && time < 0)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].alreadyBanned }`);
|
||||
if (isBanned && time > 0)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].banTimeUpdate.replaceAll(`%ourArguments%`, `${ ourArguments[1] }`) }`);
|
||||
|
||||
// They aren't in the server, try anyways
|
||||
await message.guild.members.ban(id, { deleteMessageSeconds: 7 * 24 * 60 * 60, reason: `${ authorTag } | ${ reason }` }).then(async () =>
|
||||
{
|
||||
ban.sendBanEmbed(Discord, client, id, id, message.author.id, reason, message.guild.id, time);
|
||||
var newReason = `🔨 ${ reason }`;
|
||||
await sqlite.modifyPunishmentsProfile(client, id, message.author.id, message.guild.id, `bans`, 1, newReason, timeForMuteMeta);
|
||||
}).catch((error) =>
|
||||
{
|
||||
logging.error(error);
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].mentionUser }`).then((message) =>
|
||||
{
|
||||
setTimeout(() =>
|
||||
{
|
||||
message.delete();
|
||||
}, 10_000);
|
||||
});
|
||||
});
|
||||
return; // we banned someone not in the server, so we're done here
|
||||
}
|
||||
|
||||
if ((member.roles.highest.position >= message.member.roles.highest.position && guild.ownerId !== message.author.id) || !member.bannable)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].couldntBanUser }`);
|
||||
|
||||
if (sendDmOnBan && banAppealsLink && banAppealsLink.length > 1 && isSilent === false)
|
||||
{
|
||||
const nitroSafety = `${ global.locale[global.findLocale(message.guild.id)].nitroSafety.replaceAll(`%guildName%`, `${ guild.name }`).replaceAll(`%banAppealsLink%`, `${ banAppealsLink }`) }`;
|
||||
const standardMessage = `${ global.locale[global.findLocale(message.guild.id)].standardBanDM.replaceAll(`%guildName%`, `${ guild.name }`).replaceAll(`%banAppealsLink%`, `${ banAppealsLink }`) }`;
|
||||
await (reason.toLowerCase().includes(`nitro`) || reason.toLowerCase().includes(`scam`) ? member.send(nitroSafety).catch(() => logging.log(`Could not DM, ignoring`)) : member.send(standardMessage).catch(() => logging.warn(`Could not DM, ignoring`)));
|
||||
}
|
||||
|
||||
member.ban({ deleteMessageSeconds: 7 * 24 * 60 * 60, reason: `${ authorTag } | ${ reason }` });
|
||||
ban.sendBanEmbed(Discord, client, member.id, member.user.username, message.author.id, reason, message.guild.id, time);
|
||||
var newReason = `🔨 ${ reason }`;
|
||||
await sqlite.modifyPunishmentsProfile(client, id, message.author.id, message.guild.id, `bans`, 1, newReason, timeForMuteMeta);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import { createRequire } from "node:module";
|
||||
import mentions from "../../../utils/mentions.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `clearhistory`,
|
||||
aliases: [`ch`],
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id)) // dev only
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
sql.prepare(`DELETE FROM punishments WHERE guildId = ${ message.guild.id } AND id = ${ id };`).run();
|
||||
sql.prepare(`DELETE FROM mutes WHERE guildId = ${ message.guild.id } AND userId = ${ id };`).run();
|
||||
sql.prepare(`DELETE FROM userNotes WHERE guildAndUserId = ?;`).run(`${ message.guild.id }_${ id }`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import { clearWarns } from "../../commands/moderation/clearwarns.js";
|
||||
|
||||
export default {
|
||||
name: `clearwarn`,
|
||||
aliases: [`cw`, `clearwarns`, `warnclear`, `wc`, `warnsclear`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
// we don't need GuildMember for this, only their ID and to confirm they are a valid account
|
||||
const member = await client.users.fetch(id)
|
||||
.catch(() => message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noId }`));
|
||||
|
||||
let reason = ourArguments.slice(1).join(` `);
|
||||
if (!reason || !ourArguments[1])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
|
||||
await clearWarns(client, Discord, message.guild.id, id, member, message.author.id, reason);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import { duration } from "../../commands/moderation/duration.js";
|
||||
|
||||
export default {
|
||||
name: `duration`,
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!common.canRunCommand(message, `ManageRoles`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyDuration }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const newDuration = ourArguments[1];
|
||||
let reason = ourArguments.slice(2).join(` `);
|
||||
if (!reason)
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
const time = await common.getEpoch(newDuration, true);
|
||||
if (time !== -1337)
|
||||
return duration(message, false, message.guild.id, id, message.author.id, time, newDuration, reason);
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badTimeUnit }`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { editcase } from "../../commands/moderation/editcase.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `editcase`,
|
||||
aliases: [`ecase`],
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!common.canRunCommand(message, `ManageRoles`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
if (!ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyCaseNumber }`);
|
||||
|
||||
if (!ourArguments[2])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyReason }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
// if case id contains a period, strip it
|
||||
if (ourArguments[1].includes(`.`))
|
||||
ourArguments[1] = ourArguments[1].replace(`.`, ``);
|
||||
|
||||
if (Number.isNaN(ourArguments[1]))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyCaseNumber }`);
|
||||
|
||||
const caseId = ourArguments[1];
|
||||
const reason = ourArguments.slice(2).join(` `);
|
||||
|
||||
await editcase(message, false, id, caseId, reason);
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].caseInfo.replaceAll(`%caseID%`, `${ caseId }`).replaceAll(`%id%`, `${ id }`).replaceAll(`%reason%`, `${ reason }`) }`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { kick } from "../../commands/moderation/kick.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `kick`,
|
||||
aliases: [`k`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
kick(message, false, id, message.author.id, reason, Discord, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
import { lockdown } from "../../commands/moderation/lockdown.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `lockdown`,
|
||||
aliases: [`lock`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
const { lockdownChannelIDs } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!common.canRunCommand(message, `Administrator`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
let singleChannel = false;
|
||||
if (ourArguments[0].startsWith(`<#`) || (ourArguments.length > 1 && ourArguments[1].startsWith(`<#`)))
|
||||
singleChannel = true;
|
||||
|
||||
if (!singleChannel && (!lockdownChannelIDs
|
||||
|| lockdownChannelIDs.length === 0))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badLockDownConfig }`);
|
||||
|
||||
if (ourArguments[0] !== `end`)
|
||||
{
|
||||
if (ourArguments[0].startsWith(`<#`))
|
||||
{
|
||||
var channelId = ourArguments[0].slice(2, -1);
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
return lockdown(true, message, false, reason, Discord, client, channelId);
|
||||
}
|
||||
let reason = [...ourArguments].join(` `);
|
||||
if (reason.startsWith(`start`))
|
||||
reason = reason.replace(`start`, ``);
|
||||
return lockdown(true, message, false, reason, Discord, client);
|
||||
}
|
||||
if (ourArguments[0] === `end`)
|
||||
{
|
||||
if (ourArguments[1].startsWith(`<#`))
|
||||
{
|
||||
var channelId = ourArguments[1].slice(2, -1);
|
||||
const reason = ourArguments.slice(2).join(` `);
|
||||
return lockdown(false, message, false, reason, Discord, client, channelId);
|
||||
}
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
return lockdown(false, message, false, reason, Discord, client);
|
||||
}
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].validSubCommand }`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
import lookup from "../../commands/moderation/lookup.js";
|
||||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `lookup`,
|
||||
aliases: [`l`, `info`, `uinfo`, `userinfo`, `history`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
if (ourArguments[1] === `--public`)
|
||||
var isPublic = true;
|
||||
else
|
||||
var isPublic = false;
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
return lookup.lookup(Discord, client, id, message.guild.id, isPublic, false, message);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,103 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import mute from "../../commands/moderation/mute.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `mute`,
|
||||
aliases: [`m`],
|
||||
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
const { mutedRoleID } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!common.canRunCommand(message, `ManageRoles`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if ((!mutedRoleID)
|
||||
|| mutedRoleID.length < 10)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noMuteRole }`);
|
||||
|
||||
const role = message.guild.roles.cache.find((r) => r.id === mutedRoleID);
|
||||
if (!role)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badMuteRole }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const guild = client.guilds.cache.get(message.guild.id);
|
||||
const member = await common.getGuildMember(client, message.guild.id, id);
|
||||
|
||||
if (member && member.roles.highest.position >= message.member.roles.highest.position && guild.ownerId !== message.author.id)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].cantMute }`);
|
||||
|
||||
var reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
let time = 0;
|
||||
var isExtending = false;
|
||||
const row = sql.prepare(`SELECT * FROM mutes WHERE guildId = ? AND userId = ?`).get(message.guild.id, id);
|
||||
|
||||
if (ourArguments[1])
|
||||
{ // args[1] can either be a duration or a reason
|
||||
const Time = ourArguments[1];
|
||||
time = await common.getEpoch(Time, false);
|
||||
if (time !== -1337)
|
||||
{
|
||||
reason = ourArguments.slice(2).join(` `);
|
||||
if (!reason || !ourArguments[2])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
|
||||
if (row && row.time > 1)
|
||||
{ // If they are already muted, and have a punishment, take their current mute time and add the new time to it.
|
||||
isExtending = true;
|
||||
time = Number.parseInt(row.time, 10) + time;
|
||||
await mute.sendMuteToDB(client, message.guild.id, message.author.id, id, time, reason, Time);
|
||||
}
|
||||
else if (row && row.time < 1)
|
||||
return message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].permMute }`);
|
||||
else if (member && member.roles.cache.some((r) => r.id === mutedRoleID)) // If they are muted, but do not have a punishment (i.e. a manual mute), assume the manual mute is what we want.
|
||||
return message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].manualMute }`);
|
||||
else
|
||||
{ // fresh temp mute
|
||||
await mute.sendMuteToDB(client, message.guild.id, message.author.id, id, Date.now() + time, reason, Time);
|
||||
}
|
||||
}
|
||||
else if (row && row.time > 1)
|
||||
{ // args[1] is a reason, so we perma mute
|
||||
reason = ourArguments.slice(1).join(` `);
|
||||
if (!reason || !ourArguments[1])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
time = -1;
|
||||
await mute.sendMuteToDB(client, message.guild.id, message.author.id, id, time, reason);
|
||||
}
|
||||
else
|
||||
{ // fresh perma mute
|
||||
reason = ourArguments.slice(1).join(` `); // We don't need to sanity check this since we know args[1] to be a reason.
|
||||
reason = common.truncateString(reason, 256);
|
||||
time = -1;
|
||||
await mute.sendMuteToDB(client, message.guild.id, message.author.id, id, time, reason);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // we did not provide args[1], so assume we want to perma mute without a reason.
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
time = -1;
|
||||
await mute.sendMuteToDB(client, message.guild.id, message.author.id, id, time, reason);
|
||||
}
|
||||
|
||||
const authorTag = message.author.tag;
|
||||
|
||||
// Boot them from VC
|
||||
if (member && member.voice)
|
||||
member.voice.disconnect();
|
||||
|
||||
mute.handleMute(Discord, client, member, message.author.id, role, authorTag, reason, time, isExtending, message.guild.id, id); // handles rest of mute process
|
||||
}
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { nick } from "../../commands/moderation/nick.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `nick`,
|
||||
aliases: [`n`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `ManageNicknames`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].enterNick }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const newName = ourArguments.slice(1).join(` `);
|
||||
|
||||
nick(message, false, id, newName, message.author.id, Discord, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
import { add, remove } from "../../commands/moderation/note.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import mentions from "../../../utils/mentions.js";
|
||||
|
||||
export default {
|
||||
name: `note`,
|
||||
aliases: [`notes`],
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noteSpecifyArgs }`);
|
||||
|
||||
if (!ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyUser }`);
|
||||
|
||||
var id = ourArguments[1];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(id);
|
||||
|
||||
if (ourArguments[0] === `add`)
|
||||
{
|
||||
if (!ourArguments[2])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyNote }`);
|
||||
const noteText = ourArguments.slice(2).join(` `);
|
||||
add(message, false, message.guild.id, id, message.author.id, noteText);
|
||||
}
|
||||
else if ((ourArguments[0] === `remove`) || ourArguments[0] === `delete` || ourArguments[0] === `del` || ourArguments[0] === `rm`)
|
||||
{
|
||||
if (!ourArguments[2])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyNoteID }`);
|
||||
// if case id contains a period, strip it
|
||||
if (ourArguments[2].includes(`.`))
|
||||
ourArguments[2] = ourArguments[2].replace(`.`, ``);
|
||||
|
||||
if (Number.isNaN(ourArguments[2]))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badNoteID }`);
|
||||
|
||||
const noteId = ourArguments[2];
|
||||
remove(message, false, message.guild.id, id, message.author.id, noteId);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { user, amount, after } from "../../commands/moderation/prune.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `prune`,
|
||||
aliases: [`purge`, `p`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `ManageMessages`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (ourArguments[0] && /^\d+$/.test(ourArguments[0]))
|
||||
{ // Prune X amount of messages
|
||||
const amountInt = Number.parseInt(ourArguments[0], 10);
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
amount(message, false, amountInt, reason, message.author.id, client, Discord);
|
||||
}
|
||||
else if (ourArguments[0] && ourArguments[0][0] === `<`)
|
||||
{ // Prune X amount of messages from a specific user
|
||||
var id = ourArguments[0];
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
const amount = ourArguments[1];
|
||||
const reason = ourArguments.slice(2).join(` `);
|
||||
user(message, false, id, amount, reason, message.author.id, client, Discord);
|
||||
}
|
||||
else if (ourArguments[0] && ourArguments[0] === `after`)
|
||||
{
|
||||
// Prune messages after a specific message
|
||||
var messageId = ourArguments[1];
|
||||
var reason = `No reason provided`;
|
||||
if (ourArguments[2])
|
||||
reason = ourArguments.slice(2).join(` `);
|
||||
after(message, false, messageId, reason, message.author.id, client, Discord);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
import { start, end } from "../../commands/moderation/slowmode.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `slowmode`,
|
||||
aliases: [`slow`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `ManageChannels`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifySlowTime }`);
|
||||
|
||||
const friendlyTime = ourArguments[0]; // "1h" or whatever
|
||||
if (/^\d+[hms]$/.test(friendlyTime)) // we know its in the right format, and not a reason.
|
||||
{
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
start(message, false, friendlyTime, message.author.id, message.channel.id, reason, Discord, client);
|
||||
}
|
||||
else
|
||||
{ // we assume this to be a reason to remove slowmode?
|
||||
const reason = [...ourArguments].join(` `);
|
||||
end(message, false, message.author.id, message.channel.id, reason, Discord, client);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { softban } from "../../commands/moderation/softban.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `softban`,
|
||||
aliases: [`sb`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `BanMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
softban(message, false, id, message.author.id, reason, Discord, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import unban from "../../commands/moderation/unban.js";
|
||||
|
||||
export default {
|
||||
name: `unban`,
|
||||
aliases: [`ub`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `BanMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
let reason = ourArguments.slice(1).join(` `);
|
||||
if (!reason || !ourArguments[1])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
const authorTag = message.author.tag;
|
||||
|
||||
await unban.unbanUser(message, id, message.author.id, authorTag, reason, Discord, client);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import unmute from "../../commands/moderation/unmute.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `unmute`,
|
||||
aliases: [`um`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
const { mutedRoleID } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!common.canRunCommand(message, `ManageRoles`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if ((!mutedRoleID)
|
||||
|| mutedRoleID.length < 10)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noMuteRole }`);
|
||||
|
||||
const mutedRole = message.guild.roles.cache.get(mutedRoleID);
|
||||
if (!mutedRole)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badMuteRole }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const reason = ourArguments.slice(1).join(` `);
|
||||
unmute.unmute(message, false, id, message.author.id, reason, client, Discord);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import common from "../../../utils/common.js";
|
||||
import warn from "../../commands/moderation/warn.js";
|
||||
|
||||
export default {
|
||||
name: `warn`,
|
||||
aliases: [`w`],
|
||||
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].mentionUser }`);
|
||||
|
||||
let reason = ourArguments.slice(1).join(` `);
|
||||
if (!reason
|
||||
|| !ourArguments[1])
|
||||
reason = `${ global.locale[global.findLocale(message.guild.id)].noReasonSpecified }`;
|
||||
reason = common.truncateString(reason, 256);
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(id);
|
||||
|
||||
await warn.warnUser(message, false, false, id, message.author.id, reason, undefined, Discord, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `bat`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!message.channel.isThread())
|
||||
return;
|
||||
|
||||
if (message.author.id !== client.user.id)
|
||||
return; // only the bot can use this command
|
||||
|
||||
const guildId = message.guild.id;
|
||||
const userId = ourArguments[0];
|
||||
const token = ourArguments[1];
|
||||
const threadId = ourArguments[2];
|
||||
|
||||
sql.prepare(`INSERT INTO banAppealTokens (guildId, userId, token, threadId) VALUES (?, ?, ?, ?)`).run(guildId, userId, token, threadId);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `broadcast`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noMessage }`);
|
||||
|
||||
const messageToSend = ourArguments.join(` `);
|
||||
if (messageToSend.length > 2000)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].messageTooLong }`);
|
||||
|
||||
const guilds = client.guilds.cache.map((guild) => guild.id);
|
||||
for (const guildId of guilds)
|
||||
{
|
||||
const guild = client.guilds.cache.get(guildId);
|
||||
const { auditChannelID } = common.getGuildConfig(guildId);
|
||||
|
||||
if (auditChannelID)
|
||||
{
|
||||
const auditChannel = guild.channels.cache.get(auditChannelID);
|
||||
if (auditChannel)
|
||||
auditChannel.send(messageToSend);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
const debugUsers = [];
|
||||
|
||||
export default {
|
||||
name: `debug`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id)) // dev only cuz we're cool
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
const { auditChannelID } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!auditChannelID || auditChannelID.length < 10)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].debugBadSetup }`);
|
||||
|
||||
const auditChannel = client.channels.cache.get(auditChannelID);
|
||||
|
||||
// temp table for debugging
|
||||
if (!debugUsers.includes(message.author.id))
|
||||
{
|
||||
debugUsers.push(message.author.id);
|
||||
return auditChannel.send(`<@${ message.author.id }> ${ global.locale[global.findLocale(message.guild.id)].enabledDebug }`);
|
||||
}
|
||||
debugUsers.splice(debugUsers.indexOf(message.author.id), 1);
|
||||
auditChannel.send(`<@${ message.author.id }> ${ global.locale[global.findLocale(message.guild.id)].disabledDebug }`);
|
||||
},
|
||||
/**
|
||||
* @name isDebugUser
|
||||
* @description Checks if the user is in debug mode.
|
||||
* @param {string} id The ID of the user.
|
||||
* @returns {boolean} Whether or not the user is in debug mode.
|
||||
*/
|
||||
isDebugUser(id)
|
||||
{
|
||||
if (debugUsers.includes(id))
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
debugUsers
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `edit`,
|
||||
aliases: [`e`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `Administrator`)
|
||||
&& !botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].messageToEdit }`);
|
||||
|
||||
if (!ourArguments[1])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badEdit }`);
|
||||
|
||||
const messageToEdit = ourArguments[0];
|
||||
const content = ourArguments.slice(1).join(` `);
|
||||
|
||||
var message = await client.channels.cache.get(message.channel.id).messages.fetch(messageToEdit);
|
||||
if (!message)
|
||||
return;
|
||||
if (message.author.id === client.user.id && content.length <= 2000)
|
||||
message.edit(content);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
import embed from "../../commands/utility/embed.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `embed`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if ((!common.canRunCommand(message, `ADMINISTRATOR`)
|
||||
&& !botOwnerID.includes(message.author.id) && message.author.id !== client.user.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
ourArguments[0] = message.channel.id;
|
||||
else if (ourArguments[0].startsWith(`<#`))
|
||||
ourArguments[0] = ourArguments[0].slice(2, -1);
|
||||
embed.embedGenerator(message, false, ourArguments[0], Discord);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
import { en } from "../../commands/utility/en.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `en`,
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].translate }`);
|
||||
|
||||
const { DeepLAPIKey } = common.getGuildConfig(message.guild.id);
|
||||
|
||||
if (!DeepLAPIKey)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].deeplNoKey }`);
|
||||
|
||||
const sourceText = ourArguments.join(` `);
|
||||
await en(message, false, sourceText);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
export default {
|
||||
name: `eval`,
|
||||
// Here we actually want to pass Discord & client in so we can use them in the eval code.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (message.author.id !== `666843518802591764`)
|
||||
return;
|
||||
|
||||
let evalResult;
|
||||
try
|
||||
{
|
||||
// Yes yes I know how dangerous eval is.
|
||||
// eslint-disable-next-line no-eval
|
||||
evalResult = eval(ourArguments.join(` `));
|
||||
message.channel.send(`\`\`\`js\n${ evalResult }\n\`\`\``);
|
||||
}
|
||||
catch
|
||||
{
|
||||
message.channel.send(`\`ERROR\` \`\`\`xl\n${ evalResult }\n\`\`\``);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
import { createRequire } from "node:module";
|
||||
|
||||
import common from "../../../utils/common.js";
|
||||
import logging from "../../../utils/logging.js";
|
||||
|
||||
import unban from "../../commands/moderation/unban.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { clientSecret, token } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `forcejoin`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (message.author.id !== client.user.id)
|
||||
return; // only the bot can use this command
|
||||
|
||||
const userId = ourArguments[0];
|
||||
const token = ourArguments[1];
|
||||
|
||||
const successForceJoin = await this.forceJoinUser(message, userId, token, undefined, Discord, client);
|
||||
if (!successForceJoin.success)
|
||||
message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].somethingWentWrong } ${ successForceJoin.error }`);
|
||||
},
|
||||
|
||||
async forceJoinUser(interactionOrMessage, userId, refreshToken, reason, Discord, client)
|
||||
{
|
||||
if (!refreshToken || !userId)
|
||||
return { success: false, error: `Missing token or user ID.` };
|
||||
|
||||
const { banAppealsLink } = common.getGuildConfig(interactionOrMessage.guild.id);
|
||||
const clientId = client.user.id;
|
||||
|
||||
// get fresh & new access token
|
||||
/* eslint-disable camelcase */
|
||||
const oauthData = await common.fetchJsonResponse(
|
||||
`${ common.DISCORD_API_URL }/oauth2/token`,
|
||||
{
|
||||
method: `POST`,
|
||||
body: new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
refresh_token: refreshToken,
|
||||
grant_type: `refresh_token`
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': `application/x-www-form-urlencoded`,
|
||||
}
|
||||
}
|
||||
);
|
||||
/* eslint-enable camelcase */
|
||||
if (!oauthData)
|
||||
return { success: false, error: `Failed to regenerate oauth token for ${ userId }.` };
|
||||
|
||||
if (!reason)
|
||||
reason = `Auto Mod: Solved captcha for account age.`;
|
||||
|
||||
const accessToken = oauthData.access_token;
|
||||
await unban.unbanUser(interactionOrMessage, userId, client.user.id, client.user.tag, reason, Discord, client).catch(() =>
|
||||
{
|
||||
logging.warn(`Could not unban or user is not banned.`);
|
||||
});
|
||||
await common.sleep(1500); // give discord time to process
|
||||
|
||||
// before sending the PUT request, add the user to a whitelist list where they can bypass future alt checks
|
||||
common.whitelistedAltUsers.push(userId);
|
||||
await common.sleep(1500); // give some time to process
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
const unbanRequest = await common.fetchJsonResponse(
|
||||
`${ common.DISCORD_API_URL }/guilds/${ interactionOrMessage.guild.id }/members/${ userId }`,
|
||||
{
|
||||
method: `PUT`,
|
||||
body: JSON.stringify({
|
||||
access_token: accessToken
|
||||
}),
|
||||
headers: {
|
||||
Authorization: `Bot ${ token }`,
|
||||
'Content-Type': `application/json`
|
||||
}
|
||||
}
|
||||
);
|
||||
/* eslint-enable camelcase */
|
||||
if (!unbanRequest)
|
||||
return { success: false, error: `Could not PUT user ${ userId } into guild.` };
|
||||
|
||||
const member = await common.getGuildMember(client, interactionOrMessage.guild.id, userId, true);
|
||||
if (member && banAppealsLink && banAppealsLink.length > 1)
|
||||
await member.send(`:partying_face: ${ global.locale[global.findLocale(interactionOrMessage.guild.id)].unbanDM } <${ banAppealsLink }/revoke-permissions>`).catch(() => logging.warn(`Could not DM, ignoring`));
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
import { createRequire } from "node:module";
|
||||
import logging from "../../../utils/logging.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `generateinvite`,
|
||||
aliases: [`geninv`, `getinv`, `getinvite`, `geninvite`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id)) // dev only cuz we're cool
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].specifyGuild }`);
|
||||
|
||||
const guild = client.guilds.cache.get(ourArguments[0]);
|
||||
if (!guild)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noGuild.replaceAll(`%ourArgs%`, `${ ourArguments[0] }`) } `);
|
||||
|
||||
// Find the first channel & make an invite link
|
||||
const channel = guild.channels.cache.find((c) => c.type === `GUILD_TEXT`);
|
||||
if (!channel)
|
||||
return message.channel.send(`<@!${ message.author.id }>,${ global.locale[global.findLocale(message.guild.id)].noTextChan.replaceAll(`%guildName%`, `${ guild.name }`) } `);
|
||||
|
||||
const invite = await channel.createInvite({
|
||||
maxAge: 0,
|
||||
maxUses: 0
|
||||
}).catch((error) =>
|
||||
{
|
||||
logging.error(error);
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noInvite.replaceAll(`%guildName%`, `${ guild.name }`) }`);
|
||||
});
|
||||
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission.replaceAll(`%guildName%`, `${ guild.name }`).replaceAll(`%invite%`, `${ invite.url }`) }`);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
import { respond } from "../../commands/utility/manually-respond.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `respond`,
|
||||
aliases: [`r`, `trigger`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (ourArguments.length === 0)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noTrigger }`);
|
||||
|
||||
const trigger = ourArguments.join(` `);
|
||||
if (message.type === `REPLY`) // reply w image + caption
|
||||
respond(message, false, trigger, message.author.id, message.reference.messageId, Discord);
|
||||
else
|
||||
respond(message, false, trigger, message.author.id, undefined, Discord);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
import mentions from "../../../utils/mentions.js";
|
||||
import { getAVI } from "../../commands/utility/pfp.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `pfp`,
|
||||
aliases: [`avi`, `avatar`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
{ // If no user is mentioned, use the author.
|
||||
const self = await client.users.fetch(message.author.id, true);
|
||||
return getAVI(message, false, self);
|
||||
}
|
||||
|
||||
var id = ourArguments[0];
|
||||
if (id[0] === `<`)
|
||||
id = mentions.getUserFromMention(ourArguments[0]);
|
||||
|
||||
const member = await client.users.fetch(id, true);
|
||||
return getAVI(message, false, member);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `remindme`,
|
||||
aliases: [`remind`],
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
const Time = ourArguments[0];
|
||||
const messageToSend = ourArguments.slice(1).join(` `);
|
||||
if (messageToSend.length > 2000)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].messageTooLong }`);
|
||||
|
||||
const time = await common.getEpoch(Time, true);
|
||||
if (time === -1337)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].badTimeUnit }`);
|
||||
|
||||
// insert into db
|
||||
sql.prepare(`INSERT INTO scheduledmessages (guildId, channelId, time, content) VALUES (?, ?, ?, ?)`).run(message.guild.id, message.channel.id, time, `<@!${ message.author.id }>, ${ messageToSend }`);
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setColor(`#00ff00`)
|
||||
.setTimestamp()
|
||||
.setAuthor({ name: `${ global.locale[global.findLocale(message.guild.id)].reminderScheduled }` })
|
||||
.setDescription(`${ global.locale[global.findLocale(message.guild.id)].reminderDescription.replaceAll(`%messageAuthorUsername%`, `${ message.author.username }`) } <t:${ Math.round(time / 1000) }:R> ${ global.locale[global.findLocale(message.guild.id)].reminderDescription2.replaceAll(`%messageToSend%`, `${ messageToSend }`) }`);
|
||||
message.channel.send({ embeds: [embed] });
|
||||
}
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `restart`,
|
||||
async execute(message)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
await message.delete();
|
||||
process.exit(); // requires pm2 to be installed, and the bot to be running in pm2.
|
||||
}
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import sale from "../../commands/utility/sale.js";
|
||||
|
||||
export default {
|
||||
name: `sale`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
sale.checkSteamMW2Sale(message.channel.id, client, false);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
import { createRequire } from "node:module";
|
||||
import { say } from "../../commands/utility/say.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `say`,
|
||||
aliases: [`s`],
|
||||
async execute(message, ourArguments)
|
||||
{
|
||||
if (!common.canRunCommand(message, `Administrator`)
|
||||
&& !botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (ourArguments.length === 0)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].sayError }`);
|
||||
|
||||
const messageToSay = ourArguments.join(` `);
|
||||
if (message.type === `REPLY`) // reply w image + caption
|
||||
say(message, false, messageToSay, message.reference.messageId);
|
||||
else
|
||||
say(message, false, messageToSay);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID, webfrontURL } = require(`../../../config.json`);
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
name: `schedule`,
|
||||
async execute(message, ourArguments, Discord)
|
||||
{
|
||||
if (!common.canRunCommand(message, `Administrator`)
|
||||
&& !botOwnerID.includes(message.author.id))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[2]) return message.channel.send(`${ global.locale[global.findLocale(message.guild.id)].seeWebfrontEpoch.replaceAll(`%webfrontURL%`, `${ webfrontURL }`) }`);
|
||||
|
||||
const time = ourArguments[0];
|
||||
let channel = ourArguments[1];
|
||||
const messageToSend = ourArguments.slice(2).join(` `);
|
||||
if (channel.includes(`<#`))
|
||||
channel = channel.replace(/<#/g, ``).replace(/>/g, ``);
|
||||
if (messageToSend.length > 2000)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].messageTooLong }`);
|
||||
|
||||
// if time is not just numbers
|
||||
if (!/^\d+$/.test(time))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].epochFormat.replaceAll(`%webfrontURL%`, `${ webfrontURL }`) }`);
|
||||
|
||||
// insert into db
|
||||
sql.prepare(`INSERT INTO scheduledmessages (guildId, channelId, time, content) VALUES (?, ?, ?, ?)`).run(message.guild.id, channel, time, messageToSend);
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setColor(`#00ff00`)
|
||||
.setTimestamp()
|
||||
.setAuthor({ name: `${ global.locale[global.findLocale(message.guild.id)].messageScheduled }` })
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(message.guild.id)].channel }`, value: `<#${ channel }>`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(message.guild.id)].time }`, value: `<t:${ time / 1000 }> (<t:${ time / 1000 }:R>)`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(message.guild.id)].message }`, value: messageToSend, inline: true }]);
|
||||
message.channel.send({ embeds: [embed] });
|
||||
}
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
import { sendDm } from "../../commands/utility/send-dm.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { botOwnerID } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
name: `dm`,
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
if (!botOwnerID.includes(message.author.id)) // dev only cuz we're cool
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (!ourArguments[0])
|
||||
return;
|
||||
|
||||
let messageToDm = ourArguments.slice(1).join(` `);
|
||||
messageToDm = common.truncateString(messageToDm, 1024);
|
||||
const user = await client.users.fetch(ourArguments[0]);
|
||||
|
||||
await sendDm(message, false, messageToDm, user, Discord, client);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
name: `suggest`,
|
||||
aliases: [`sg`],
|
||||
async execute(message, ourArguments, Discord, client)
|
||||
{
|
||||
const { suggestionChannelID } = common.getGuildConfig(message.guild.id);
|
||||
if (!common.canRunCommand(message, `KickMembers`))
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noPermission }`);
|
||||
|
||||
if (ourArguments.length === 0)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].noSuggestion }`);
|
||||
|
||||
if (!suggestionChannelID
|
||||
|| suggestionChannelID.length < 10)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].suggestionSetup }`);
|
||||
|
||||
const votingChannel = client.channels.cache.get(suggestionChannelID);
|
||||
if (!votingChannel)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].invalidSugChan }`);
|
||||
const suggestion = ourArguments.join(` `);
|
||||
if (suggestion.length > 2000)
|
||||
return message.channel.send(`<@!${ message.author.id }>, ${ global.locale[global.findLocale(message.guild.id)].sugTooLong }`);
|
||||
votingChannel.send(ourArguments.join(` `)).then((message) =>
|
||||
{
|
||||
message.react(`👍`);
|
||||
message.react(`👎`);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
banlist
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
*/
|
||||
export async function banlist(interactionOrMessage, isSlashCommand)
|
||||
{
|
||||
const banArray = await common.getAllGuildBans(interactionOrMessage.guild);
|
||||
const message = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].amountOfBans.replaceAll(`%count%`, `${ banArray.length }`) }`;
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: message }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import st from "string-table";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
guildlist
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {Discord} Discord The Discord client.
|
||||
* @param {Discord.client} client The client.
|
||||
* @param {boolean} onlyCount Should we only return the number of guilds it is in?
|
||||
*/
|
||||
export async function guildlist(interactionOrMessage, isSlashCommand, Discord, client, onlyCount = false)
|
||||
{
|
||||
const guilds = client.guilds.cache.map((guild) => guild.id);
|
||||
if (onlyCount)
|
||||
{
|
||||
const lengthMessage = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].amountOfGuilds.replaceAll(`%count%`, `${ guilds.length }`) }`;
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, { content: lengthMessage }, isSlashCommand);
|
||||
}
|
||||
|
||||
const data = [];
|
||||
for (const guildId of guilds)
|
||||
{
|
||||
data.push({
|
||||
guildName: client.guilds.cache.get(guildId).name,
|
||||
guildId,
|
||||
guildOwner: await client.guilds.cache.get(guildId).fetchOwner().then((owner) => owner.user.tag),
|
||||
memberCount: await client.guilds.cache.get(guildId).memberCount,
|
||||
channelCount: await client.guilds.cache.get(guildId).channels.cache.size,
|
||||
roleCount: await client.guilds.cache.get(guildId).roles.cache.size,
|
||||
});
|
||||
}
|
||||
const testString = `\`\`\`${ st.create(data) }\n\`\`\``;
|
||||
if (testString.length < 2000)
|
||||
{
|
||||
const string = `\`\`\`${ st.create(data) }\n\`\`\``;
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
const string = `${ st.create(data) }`;
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `guildlist.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
membercount
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
*/
|
||||
export async function membercount(interactionOrMessage, isSlashCommand)
|
||||
{
|
||||
const guildId = interactionOrMessage.guild.id;
|
||||
const guild = interactionOrMessage.guild;
|
||||
const memberCount = guild.memberCount;
|
||||
const memberCounts = await sql.prepare(`SELECT * FROM memberCounts WHERE guildId = ?`).get(guildId);
|
||||
const time = Date.now();
|
||||
if (memberCounts)
|
||||
{
|
||||
const oldCount = Math.round(memberCounts.count);
|
||||
const oldTime = memberCounts.time;
|
||||
let string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].memberCount1.replaceAll(`%guildName%`, `${ guild.name }`).replaceAll(`%memberCount%`, `${ memberCount }`) }\n`;
|
||||
if (oldCount > memberCount)
|
||||
string += `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].memberCount2.replaceAll(`%dec%`, `${ oldCount - memberCount }`) }`;
|
||||
else if (oldCount < memberCount)
|
||||
string += `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].memberCount3.replaceAll(`%inc%`, `${ memberCount - oldCount }`) }`;
|
||||
if (oldCount !== memberCount)
|
||||
string += ` from <t:${ Math.round(oldTime / 1000) }:R>`;
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
await sql.prepare(`INSERT OR REPLACE INTO memberCounts (guildId, count, time) VALUES (?, ?, ?);`).run(guildId, memberCount, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
const string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].memberCount1.replaceAll(`%guildName%`, `${ guild.name }`).replaceAll(`%memberCount%`, `${ memberCount }`) }`;
|
||||
await sql.prepare(`INSERT INTO memberCounts (guildId, count, time) VALUES (?, ?, ?);`).run(guildId, memberCount, time);
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
mutelist
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
*/
|
||||
export async function mutelist(interactionOrMessage, isSlashCommand)
|
||||
{
|
||||
const guildId = interactionOrMessage.guild.id;
|
||||
const totalMutes = sql.prepare(`SELECT COUNT(*) count FROM mutes WHERE guildId = ?`).get(guildId);
|
||||
const totalMutesCount = totalMutes.count;
|
||||
|
||||
const temporaryMutes = sql.prepare(`SELECT COUNT(*) count FROM mutes WHERE guildId = ? AND time > 1`).get(guildId);
|
||||
const temporaryMutesCount = temporaryMutes.count;
|
||||
|
||||
const permMutes = sql.prepare(`SELECT COUNT(*) count FROM mutes WHERE guildId = ? AND time < 0`).get(guildId);
|
||||
const permMutesCount = permMutes.count;
|
||||
|
||||
const message = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].amountOfMutes.replaceAll(`%totalMutesCount%`, `${ totalMutesCount }`).replaceAll(`%temporaryMutesCount%`, `${ temporaryMutesCount }`).replaceAll(`%permMutesCount%`, `${ permMutesCount }`) }`;
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: message }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
ping
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {*} client The client.
|
||||
*/
|
||||
export async function ping(interactionOrMessage, isSlashCommand, client)
|
||||
{
|
||||
const ping = `${ Date.now() - interactionOrMessage.createdTimestamp }ms.`;
|
||||
const apiPing = `${ Math.round(client.ws.ping) }ms.`;
|
||||
const message = `🏓 ${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].latencyIs } ${ ping } ${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].api } ${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].latencyIs } ${ apiPing }`;
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: message }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
serverinfo
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {Discord.Guild} guild The guild.
|
||||
* @param {Discord} Discord The Discord object.
|
||||
*/
|
||||
export async function serverinfo(interactionOrMessage, isSlashCommand, guild, Discord)
|
||||
{
|
||||
var owner = await guild.fetchOwner();
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setColor(`#0e9af9`)
|
||||
.setTimestamp()
|
||||
.setAuthor({ name: `🔎 (${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].serverInfo })` })
|
||||
.setThumbnail(guild.iconURL())
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].serverName }`, value: `${ guild.name } (${ guild.id })`, inline: false }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].owner }`, value: `${ owner.user.tag } (${ owner.user.id })`, inline: false }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].memberCount }`, value: `${ guild.memberCount }`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].channelCount }`, value: `${ guild.channels.cache.size }`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].roleCount }`, value: `${ guild.roles.cache.size }`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].emojiCount }`, value: `${ guild.emojis.cache.size }`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].createdOn }`, value: `<t:${ Math.round(guild.createdTimestamp / 1000) }>`, inline: true }]);
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { embeds: [embed] }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import { execSync } from "node:child_process";
|
||||
import { createRequire } from "node:module";
|
||||
import common from "../../../utils/common.js";
|
||||
import logging from "../../../utils/logging.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { clientSecret, debugMode } = require(`../../../config.json`);
|
||||
|
||||
export default {
|
||||
/**
|
||||
* @name getCommitInfo
|
||||
* @description Gets the commit info for boot messages / version command.
|
||||
* @param {*} interactionOrMessage The interaction or message that called this function.
|
||||
* @param {*} auditChannel The audit channel to send the message to.
|
||||
* @param {boolean} isSlashCommand Whether or not this function was called from a slash command.
|
||||
* @param {boolean} botOnline Was this function called on the bot's startup?
|
||||
*/
|
||||
async getCommitInfo(interactionOrMessage, auditChannel, isSlashCommand, botOnline = false)
|
||||
{
|
||||
const guildId = botOnline ? auditChannel.guild.id : interactionOrMessage.guild.id;
|
||||
|
||||
const { banAppealsChannelID, banAppealsLink } = common.getGuildConfig(guildId);
|
||||
|
||||
var gitMessage = execSync(`git show -s --format="*%s* (**%an**)"`).toString();
|
||||
|
||||
// Don't @everyone/@here
|
||||
if (gitMessage.includes(`@everyone`) || gitMessage.includes(`@here`))
|
||||
gitMessage = gitMessage.replace(/@/g, `@${ String.fromCodePoint(8203) }`);
|
||||
if (gitMessage.length > 1024)
|
||||
gitMessage = common.truncateString(gitMessage, 1024);
|
||||
|
||||
// bot online message
|
||||
if (botOnline)
|
||||
{
|
||||
// don't send anything if the bot is in debug mode
|
||||
if (debugMode)
|
||||
return;
|
||||
|
||||
auditChannel.send(`${ global.locale[global.findLocale(guildId)].botIsOnline } ${ gitMessage }`);
|
||||
return;
|
||||
}
|
||||
|
||||
const versionString = `**BOT:** ${ gitMessage }`;
|
||||
|
||||
if (!banAppealsChannelID || !clientSecret)
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, { content: versionString }, isSlashCommand);
|
||||
|
||||
let banAppealsInfo = await common.fetchJsonResponse(
|
||||
`${ banAppealsLink }/commit-info?authKey=${ clientSecret }`,
|
||||
{
|
||||
methods: `GET`
|
||||
}
|
||||
).catch(() => { logging.warn(`Ban Appeals API: Failed to get commit info.`); });
|
||||
if (!banAppealsInfo)
|
||||
{
|
||||
banAppealsInfo = {
|
||||
message: `Failed to reach ban appeals API.`
|
||||
};
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: `${ versionString }\n**APPEALS:** ${ banAppealsInfo.message }` }, isSlashCommand);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,141 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import st from "string-table";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
list,
|
||||
add,
|
||||
remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The guild ID.
|
||||
* @param {*} Discord The Discord object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, guildId, Discord)
|
||||
{
|
||||
const allowedDiscords = sql.prepare(`SELECT * FROM allowedDiscords WHERE guildId = ${ guildId }`).raw().all();
|
||||
if (allowedDiscords.length === 0)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noDiscordsInList
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
const servers = [];
|
||||
for (const allowedDiscord of allowedDiscords)
|
||||
{
|
||||
servers.push({
|
||||
id: allowedDiscord[1]
|
||||
});
|
||||
}
|
||||
|
||||
let string = `\`\`\`${ st.create(servers) }\`\`\``;
|
||||
if (string.length < 2000)
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
|
||||
string = `${ st.create(servers) }`;
|
||||
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `allowed-discords.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The guild ID.
|
||||
* @param {string} inviteString The invite string.
|
||||
* @param {Discord} Discord The Discord object.
|
||||
* @param {Discord.client} client The client.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, guildId, inviteString, Discord, client)
|
||||
{
|
||||
const discordInvite = await client.fetchInvite(inviteString);
|
||||
|
||||
if (!discordInvite)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].invalidDiscordInvite
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
// If discord invite is already in db, return
|
||||
const allowedDiscords = sql.prepare(`SELECT * FROM allowedDiscords WHERE guildId = ${ guildId }`).raw().all();
|
||||
for (const allowedDiscord of allowedDiscords)
|
||||
{
|
||||
if (guildId === allowedDiscord[1])
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].serverAlreadyInList
|
||||
}, isSlashCommand);
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
guildId,
|
||||
id: discordInvite.guild.id
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`INSERT INTO allowedDiscords (guildId, id) VALUES (@guildId, @id)`).run(data);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].addedToList.replaceAll(`%item%`, `${ discordInvite.guild.name }`) }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The guild ID.
|
||||
* @param {string} inviteString The invite string.
|
||||
* @param {Discord} Discord The Discord object.
|
||||
* @param {Discord.client} client The client.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, guildId, inviteString, Discord, client)
|
||||
{
|
||||
const regex = /^\d*$/;
|
||||
|
||||
let discordInvite = {
|
||||
guild: {
|
||||
guildId,
|
||||
id: undefined
|
||||
}
|
||||
};
|
||||
|
||||
if (inviteString.includes(`.`))
|
||||
{ // Is a discord invite link
|
||||
discordInvite = await client.fetchInvite(inviteString);
|
||||
if (!discordInvite)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].invalidDiscordInvite
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
var guildIdToRm = discordInvite.guild.id;
|
||||
}
|
||||
else if (regex.test(inviteString))
|
||||
{ // Is a guildId
|
||||
var guildIdToRm = inviteString;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`DELETE FROM allowedDiscords WHERE id = ? AND guildId = ?`).run(guildIdToRm, guildId);
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].removedFromList.replaceAll(`%item%`, `${ guildIdToRm }`) }, isSlashCommand);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error(error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
list, add, remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {Discord} Discord The Discord object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, Discord)
|
||||
{
|
||||
const approvedLinksH = sql.prepare(`SELECT link FROM allowedLinks WHERE guildId = ${ interactionOrMessage.guild.id }`).raw().all();
|
||||
const approvedLinks = approvedLinksH.flat();
|
||||
|
||||
if (approvedLinks.length === 0)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noLinksInList
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
let string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].allowedLinks } \`${ approvedLinks.join(`\`, \``) }\``;
|
||||
if (string.length < 2000)
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
else
|
||||
{
|
||||
string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].allowedLinks } \n${ approvedLinks.join(`\n`) }`;
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `allowed-links.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The guild ID.
|
||||
* @param {string} link The link to add.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, guildId, link)
|
||||
{
|
||||
if (link.length > 1900)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].itemTooLong
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`INSERT INTO allowedLinks (link, guildId) VALUES (?, ?)`).run(link, guildId);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].addedToList.replaceAll(`%item%`, `${ link }`) }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The guild ID.
|
||||
* @param {string} link The link to remove.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, guildId, link)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql.prepare(`DELETE FROM allowedLinks WHERE link = ? AND guildId = ?`).run(link, guildId);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].removedFromList.replaceAll(`%item%`, `${ link }`) }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
list, add, remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {*} Discord The Discord Object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, Discord)
|
||||
{
|
||||
const autoBanWordsH = sql.prepare(`SELECT phrase FROM autoBannedPhrases WHERE guildId = ${ interactionOrMessage.guild.id }`).raw().all();
|
||||
const autoBanWords = autoBanWordsH.flat();
|
||||
|
||||
if (autoBanWords.length === 0)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noAutoBannedPhrases
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
let string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoBannedPhrases } \`${ autoBanWords.join(`\`, \``) }\``;
|
||||
if (string.length < 2000)
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
else
|
||||
{
|
||||
string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoBannedPhrases } \n${ autoBanWords.join(`\n`) }`;
|
||||
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `auto-banned-phrases.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} phrase The auto banned phrase to add.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, phrase)
|
||||
{
|
||||
if (phrase.length > 1900)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].itemTooLong
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`INSERT INTO autoBannedPhrases (guildId, phrase) VALUES (?, ?)`).run(interactionOrMessage.guild.id, phrase);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].addedToList.replaceAll(`%item%`, `${ phrase }`) }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} phrase The phrase to remove.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, guildId, phrase)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql.prepare(`DELETE FROM autoBannedPhrases WHERE guildId = ? AND phrase = ?`).run(guildId, phrase);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].removedFromList.replaceAll(`%item%`, `${ phrase }`) }, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import st from "string-table";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
clear, list, add, remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
*/
|
||||
export async function clear(interactionOrMessage, isSlashCommand, guildId)
|
||||
{
|
||||
sql.prepare(`DELETE FROM keywords WHERE guildId = ${ guildId }`).run();
|
||||
sql.prepare(`DELETE FROM keywordsRegional WHERE guildId = ${ guildId }`).run();
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].clearedKeywords }`
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {*} Discord The Discord Object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, guildId, Discord)
|
||||
{
|
||||
const responseObject = sql.prepare(`SELECT * FROM keywords WHERE guildId = ${ guildId }`).raw().all();
|
||||
const responseObjectRegional = sql.prepare(`SELECT * FROM keywordsRegional WHERE guildId = ${ guildId }`).raw().all();
|
||||
|
||||
const data = [];
|
||||
for (const element of responseObject)
|
||||
{
|
||||
data.push({
|
||||
trigger: element[1],
|
||||
response: element[2]
|
||||
});
|
||||
}
|
||||
|
||||
const dataRegional = [];
|
||||
for (const element of responseObjectRegional)
|
||||
{
|
||||
dataRegional.push({
|
||||
trigger: element[1],
|
||||
response: element[2]
|
||||
});
|
||||
}
|
||||
|
||||
let string = ``;
|
||||
if (data.length > 0)
|
||||
string += `**${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].keywords }**\n\`\`\`${ st.create(data) }\n\`\`\``;
|
||||
|
||||
if (dataRegional.length > 0)
|
||||
string += `\n**${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].keywordsRegional }**\n\`\`\`${ st.create(dataRegional) }\n\`\`\``;
|
||||
|
||||
if (string === ``)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noKeywords
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
if (string.length < 2000)
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
|
||||
string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].keywords }\n${ st.create(data) }\n\n${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].keywordsRegional }\n${ st.create(dataRegional) }`;
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `auto-replies.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} trigger The trigger to add.
|
||||
* @param {string} response The response to add.
|
||||
* @param {boolean} isRegional Whether or not the keyword is regional.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, guildId, trigger, response, isRegional)
|
||||
{
|
||||
const responseObject = sql.prepare(`SELECT * FROM keywords WHERE guildId = ${ guildId }`).raw().all();
|
||||
const responseObjectRegional = sql.prepare(`SELECT * FROM keywordsRegional WHERE guildId = ${ guildId }`).raw().all();
|
||||
if (isRegional)
|
||||
{
|
||||
if (responseObjectRegional.some((x) => x[1] === trigger))
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].triggerAlreadyExists
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
sql.prepare(`INSERT INTO keywordsRegional (guildId, phrase, response) VALUES (?, ?, ?)`).run(guildId, trigger, response);
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoReplyAdded
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
if (responseObject.some((x) => x[1] === trigger))
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].triggerAlreadyExists
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
sql.prepare(`INSERT INTO keywords (guildId, phrase, response) VALUES (?, ?, ?)`).run(guildId, trigger, response);
|
||||
common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoReplyAdded
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} trigger The trigger to remove.
|
||||
* @param {boolean} isRegional Whether or not the keyword is regional.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, guildId, trigger, isRegional)
|
||||
{
|
||||
if (isRegional)
|
||||
{
|
||||
const responseObject = sql.prepare(`SELECT * FROM keywordsRegional WHERE guildId = ${ guildId }`).raw().all();
|
||||
if (!responseObject.some((x) => x[1] === trigger))
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].triggerDoesNotExist
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
sql.prepare(`DELETE FROM keywordsRegional WHERE guildId = ${ guildId } AND phrase = ?`).run(trigger);
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoReplyRemoved
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
const responseObject = sql.prepare(`SELECT * FROM keywords WHERE guildId = ${ guildId }`).raw().all();
|
||||
if (!responseObject.some((x) => x[1] === trigger))
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].triggerDoesNotExist
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
sql.prepare(`DELETE FROM keywords WHERE guildId = ${ guildId } AND phrase = ?`).run(trigger);
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].autoReplyRemoved
|
||||
}, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
list, add, remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {*} Discord The Discord Object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, Discord)
|
||||
{
|
||||
const badWordsH = sql.prepare(`SELECT word FROM badWords WHERE guildId = ${ interactionOrMessage.guild.id }`).raw().all();
|
||||
const badWords = badWordsH.flat();
|
||||
|
||||
if (badWords.length === 0)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noBadWords
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
let string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].badWords } \`${ badWords.join(`\`, \``) }\``;
|
||||
if (string.length < 2000)
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
else
|
||||
{
|
||||
string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].badWords } \n${ badWords.join(`\n`) }`;
|
||||
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `bad-words.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} phrase The phrase to add.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, guildId, phrase)
|
||||
{
|
||||
if (phrase.length > 1900)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].itemTooLong
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`INSERT INTO badWords (guildId, word) VALUES (?, ?)`).run(guildId, phrase);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].badWordAdded } \`${ phrase }\`` }, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} phrase The phrase to remove.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, guildId, phrase)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql.prepare(`DELETE FROM badWords WHERE guildId = ? AND word = ?`).run(guildId, phrase);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].badWordRemoved } \`${ phrase }\``
|
||||
}, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
list, add, remove
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {*} Discord The Discord Object.
|
||||
*/
|
||||
export async function list(interactionOrMessage, isSlashCommand, Discord)
|
||||
{
|
||||
const dmListH = sql.prepare(`SELECT userId FROM doNotForwardDMsFrom`).raw().all();
|
||||
const dmList = dmListH.flat();
|
||||
|
||||
if (dmList.length === 0)
|
||||
{
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].noIgnoredDMs
|
||||
}, isSlashCommand);
|
||||
}
|
||||
let string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].ignoredDMs } \`${ dmList.join(`\`, \``) }\``;
|
||||
if (string.length < 2000)
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { content: string }, isSlashCommand);
|
||||
else
|
||||
{
|
||||
string = `${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].ignoredDMs } \n${ dmList.join(`\n`) }`;
|
||||
|
||||
// send message as attachment
|
||||
const attachment = new Discord.AttachmentBuilder(Buffer.from(string), { name: `ignore-dms.txt` });
|
||||
common.sendInteractionOrMessage(interactionOrMessage, { files: [attachment] }, isSlashCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {number} uid The user ID.
|
||||
*/
|
||||
export async function add(interactionOrMessage, isSlashCommand, uid)
|
||||
{
|
||||
const dmListH = sql.prepare(`SELECT userId FROM doNotForwardDMsFrom`).raw().all();
|
||||
const dmList = dmListH.flat();
|
||||
|
||||
if (dmList.includes(uid))
|
||||
return common.sendInteractionOrMessage(interactionOrMessage, { content: `<@!${ uid }> ${ global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].isAlreadyIgnored }` }, isSlashCommand);
|
||||
|
||||
try
|
||||
{
|
||||
sql.prepare(`INSERT INTO doNotForwardDMsFrom (userId) VALUES (?)`).run(uid);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].userIgnored
|
||||
}, isSlashCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} interactionOrMessage The interaction or message object.
|
||||
* @param {boolean} isSlashCommand Whether or not the interaction is a slash command.
|
||||
* @param {number} uid The user ID.
|
||||
*/
|
||||
export async function remove(interactionOrMessage, isSlashCommand, uid)
|
||||
{
|
||||
try
|
||||
{
|
||||
sql.prepare(`DELETE FROM doNotForwardDMsFrom WHERE userId = ?`).run(uid);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
common.sendInteractionOrMessage(interactionOrMessage, {
|
||||
content: global.locale[global.findLocale(interactionOrMessage.guild.id, interactionOrMessage.locale)].userUnignored
|
||||
}, isSlashCommand);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
import { AuditLogEvent } from "discord.js";
|
||||
import sqlite from "../../../utils/sqlite.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
export default {
|
||||
guildBanAddEvent,
|
||||
sendBanEmbed,
|
||||
banAndSendEmbed,
|
||||
};
|
||||
|
||||
/**
|
||||
* @name guildBanAddEvent
|
||||
* @description Event that fires when a user is banned from a guild.
|
||||
* @param {*} Discord The Discord Object.
|
||||
* @param {*} client The Discord Client Object.
|
||||
* @param {*} data The data object.
|
||||
*/
|
||||
async function guildBanAddEvent(Discord, client, data)
|
||||
{
|
||||
const guildId = data.guild.id;
|
||||
const guild = client.guilds.cache.get(guildId);
|
||||
|
||||
const user = data.user;
|
||||
const fetchedLogs = await guild.fetchAuditLogs({
|
||||
limit: 1,
|
||||
type: AuditLogEvent.MemberBanAdd
|
||||
});
|
||||
const banLog = fetchedLogs.entries.first();
|
||||
|
||||
if (!banLog)
|
||||
return; // no ban log, something went wrong?
|
||||
|
||||
const { executor, target, action } = banLog;
|
||||
|
||||
if (executor.id === client.user.id)
|
||||
return; // dont send embed if bot banned
|
||||
if (target.id !== user.id)
|
||||
return; // dont send embed if user wasn't banned
|
||||
if (action !== AuditLogEvent.MemberBanAdd)
|
||||
return; // dont send embed if user wasn't banned
|
||||
|
||||
var reason = banLog.reason;
|
||||
if (!reason)
|
||||
reason = `${ global.locale[global.findLocale(guildId)].noReasonSpecified }`;
|
||||
|
||||
var newReason = `🔨 ${ reason }`;
|
||||
await sqlite.modifyPunishmentsProfile(client, target.id, executor.id, guild.id, `bans`, 1, newReason, `permanently`);
|
||||
|
||||
sendBanEmbed(Discord, client, target.id, target.username, executor.id, reason, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} Discord The Discord Object.
|
||||
* @param {*} client The Discord Client Object.
|
||||
* @param {string} userId The user ID.
|
||||
* @param {string} displayName The user display name.
|
||||
* @param {string} moderatorId The moderator ID.
|
||||
* @param {string} reason The reason for the ban.
|
||||
* @param {Discord.GuildMember} member The guild member object.
|
||||
* @name banAndSendEmbed
|
||||
* @description Ban the user and send an embed.
|
||||
*/
|
||||
function banAndSendEmbed(Discord, client, userId, displayName, moderatorId, reason, member)
|
||||
{
|
||||
const authorTag = client.users.cache.get(moderatorId).tag;
|
||||
member.ban({ deleteMessageSeconds: 7 * 24 * 60 * 60, reason: `${ authorTag } | ${ reason }` });
|
||||
sendBanEmbed(Discord, client, userId, displayName, moderatorId, reason, member.guild.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name sendBanEmbed
|
||||
* @description Send an embed to the audit channel when a user is banned.
|
||||
* @param {*} Discord The Discord Object.
|
||||
* @param {*} client The Discord Client Object.
|
||||
* @param {string} userId The user's id.
|
||||
* @param {string} displayName The user's display name.
|
||||
* @param {string} moderatorId The moderator's id.
|
||||
* @param {string} reason The reason for the ban.
|
||||
* @param {string} guildId The guild's id.
|
||||
* @param {number} time Time in Epoch format.
|
||||
*/
|
||||
function sendBanEmbed(Discord, client, userId, displayName, moderatorId, reason, guildId, time)
|
||||
{
|
||||
const { auditChannelID } = common.getGuildConfig(guildId);
|
||||
if (!auditChannelID || auditChannelID.length < 10) return; // no audit channel set, dont try and send embed
|
||||
const auditChannel = client.channels.cache.get(auditChannelID);
|
||||
if (!auditChannel) // auditChannelID is invalid.
|
||||
return;
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setColor(`#ff1e00`)
|
||||
.setTimestamp()
|
||||
.setAuthor({ name: `🔨 (${ global.locale[global.findLocale(guildId)].ban })` })
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(guildId)].user }`, value: `<@!${ userId }> (${ displayName })`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(guildId)].moderator }`, value: `<@!${ moderatorId }>`, inline: true }]);
|
||||
if (time && time > 0)
|
||||
embed.addFields([{ name: `${ global.locale[global.findLocale(guildId)].expires }`, value: `<t:${ Math.round(time / 1000) }:R>`, inline: true }]);
|
||||
embed.addFields([{ name: `${ global.locale[global.findLocale(guildId)].reason }`, value: (reason || `${ global.locale[global.findLocale(guildId)].noReasonSpecified }`), inline: true }]);
|
||||
|
||||
auditChannel.send({ embeds: [embed] });
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import SQLite from "better-sqlite3";
|
||||
import sqlite from "../../../utils/sqlite.js";
|
||||
import common from "../../../utils/common.js";
|
||||
|
||||
const sql = new SQLite(`./src/db.sqlite`);
|
||||
|
||||
export default {
|
||||
clearWarns,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} client The Discord Client Object.
|
||||
* @param {*} Discord The Discord Object.
|
||||
* @param {string} guildId The Guild ID.
|
||||
* @param {string} id The ID of the user to clear warns for.
|
||||
* @param {Discord.GuildMember} member The GuildMember object.
|
||||
* @param {string} authorId The ID of the user who issued the command.
|
||||
* @param {string} reason The reason for the clear.
|
||||
*/
|
||||
export async function clearWarns(client, Discord, guildId, id, member, authorId, reason)
|
||||
{
|
||||
var warnings = sqlite.getPunishmentData(guildId, id, `warns`);
|
||||
if (warnings >= 1)
|
||||
{
|
||||
const data = global.getInfoById.get(guildId, id);
|
||||
var punishmentinfo = JSON.parse(data.punishmentinfo);
|
||||
var punishmentreason = JSON.parse(data.punishmentreason);
|
||||
|
||||
for (let index = 0; index < punishmentreason.length;)
|
||||
{
|
||||
if (punishmentreason[index].includes(`⚠`))
|
||||
{
|
||||
punishmentreason.splice(index, 1);
|
||||
punishmentinfo.splice(index, 1);
|
||||
|
||||
// apply data
|
||||
data.punishmentinfo = JSON.stringify(punishmentinfo);
|
||||
data.punishmentreason = JSON.stringify(punishmentreason);
|
||||
data.warns -= 1;
|
||||
global.setInfo.run(data);
|
||||
}
|
||||
else
|
||||
index += 1; // only up 1 index if no warning reason was found. this solves the issue of back-to-back warnings and we skip over 1
|
||||
}
|
||||
}
|
||||
|
||||
// If the user has 0 history now, delete their record.
|
||||
if (!sqlite.hasRecord(guildId, id))
|
||||
sql.prepare(`DELETE FROM punishments WHERE guildId = ? AND id = ?`).run(guildId, id);
|
||||
|
||||
const { auditChannelID } = common.getGuildConfig(guildId);
|
||||
if (!auditChannelID || auditChannelID.length < 10) return; // no audit channel ID, dont try and send an embed
|
||||
const auditChannel = client.channels.cache.get(auditChannelID);
|
||||
if (!auditChannel) // auditChannelID is invalid.
|
||||
return;
|
||||
const embed = new Discord.EmbedBuilder()
|
||||
.setColor(`#00FF00`)
|
||||
.setTimestamp()
|
||||
.setAuthor({ name: `⚠️ (${ global.locale[global.findLocale(guildId)].clearWarns })` })
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(guildId)].user }`, value: `<@!${ member.id }> (${ member.username })`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(guildId)].moderator }`, value: `<@!${ authorId }>`, inline: true }])
|
||||
.addFields([{ name: `${ global.locale[global.findLocale(guildId)].reason }`, value: reason, inline: true }]);
|
||||
|
||||
auditChannel.send({ embeds: [embed] });
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue