Merge pull request #384 from ZynerOrg/dev

Release 2022.10.01
This commit is contained in:
Axel Olausson Holtenäs 2022-10-21 20:46:14 +02:00 committed by GitHub
commit 4a833eccdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
232 changed files with 6845 additions and 5319 deletions

6
.dockerignore Normal file
View file

@ -0,0 +1,6 @@
.vscode
.husky
.github
.cspell
.env
node_modules

30
.env.example Normal file
View file

@ -0,0 +1,30 @@
# THIS FILE SHOULD BE INSIDE OF build/
# Discord
DISCORD_TOKEN=""
DISCORD_CLIENT_ID=""
DISCORD_GUILD_ID=""
# Database
DATABASE_URL="file:./production.db"
# Encryption
ENCRYPTION_ALGORITHM="aes-256-ctr"
ENCRYPTION_SECRET="A RANDOM STRING WITH LENGTH OF 32"
#Embed
EMBED_COLOR_SUCCESS="#22bb33"
EMBED_COLOR_WAIT="#f0ad4e"
EMBED_COLOR_ERROR="#bb2124"
EMBED_FOOTER_TEXT="https://github.com/ZynerOrg/xyter"
EMBED_FOOTER_ICON="https://github.com/ZynerOrg.png"
# Log
LOG_LEVEL="silly"
# Reputation
REPUTATION_TIMEOUT="86400"
# Bot Hoster
BOT_HOSTER_NAME="Zyner"
BOT_HOSTER_URL="https://xyter.zyner.org/customization/change-hoster"

View file

@ -1,2 +0,0 @@
node_modules
dist

View file

@ -1,15 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "no-loops", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-console": 1,
"no-loops/no-loops": 2
}
}

View file

@ -42,7 +42,7 @@ body:
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/ZynerOrg/xyter/blob/main/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow this project's Code of Conduct
required: true

1
.husky/.gitignore vendored
View file

@ -1 +0,0 @@
_

View file

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged

View file

@ -45,7 +45,8 @@
"sonarsource.sonarlint-vscode",
"nicoespeon.hocus-pocus",
"aaron-bond.better-comments",
"oouo-diogo-perdigao.docthis"
"oouo-diogo-perdigao.docthis",
"Vtrois.gitmoji-vscode"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []

10
.vscode/settings.json vendored
View file

@ -4,7 +4,6 @@
"editor.cursorBlinking": "phase",
"editor.cursorSmoothCaretAnimation": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.fontFamily": "Cascadia Code",
"editor.fontLigatures": true,
"editor.formatOnSave": true,
"editor.guides.bracketPairs": "active",
@ -15,6 +14,9 @@
"editor.wordWrapColumn": 100,
"files.eol": "\n",
"files.trimTrailingWhitespace": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"cSpell.customDictionaries": {
"custom-dictionary-workspace": {
"name": "custom-dictionary-workspace",
@ -22,5 +24,11 @@
"addWords": true,
"scope": "workspace"
}
},
"[dotenv]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[prisma]": {
"editor.defaultFormatter": "Prisma.prisma"
}
}

19
Dockerfile Normal file
View file

@ -0,0 +1,19 @@
FROM node:19
LABEL maintainer="xyter@zyner.org"
WORKDIR /build
COPY package* .
RUN npm install
COPY . .
RUN npx -y tsc
WORKDIR /app
RUN cp -r /build/build/* .
RUN cp -r /build/node_modules .
CMD [ "node", "." ]

View file

@ -1,57 +0,0 @@
> Please note that this is our first privacy policy, so some stuff may be off or not in it!
> We are trying our best to follow the privacy policy law.
# Privacy Policy
This document entails the privacy policy and agreement that you accept when adding Xyter bot to a server, or as a member of such a server. This document does not supersede the [Developer Terms of Service](https://discordapp.com/developers/docs/legal).
This privacy policy applies to **Xyter**#7721 (949998000401436673)
### Terminology
- **Server Manager** - Anyone who has the ability to add a bot to a server or configure the bot for the server. This is usually an administrator or moderator
- **Server Member** - Anyone who is a member of server to which one of the bots has been added
- **Service User** - Anyone who authorizes an application (logs in) for a scope that provides additional information
### Data Collected By Command
The following items may be collected and stored when intentionally provided by a user (usually by means of a command). This data will not be collected automatically. When providing data in this way, you forego any rights to the content of the data provided.
- Server configurations (/settings guild)
- Data and content for automated tasks (/shop roles)
- Locale (/settings user language)
- Reputation (/reputation give)
### Data Collected When Enabled
These items will be automatically collected if a bot is configured to perform certain actions by a server manager. These features are always opt-in, and thus this data will not be collected unless the corresponding feature is enabled.
- API Token & URL (/settings guild pterodactyl)
- Counters (/admin counter)
### Data Collected Automatically
This data may be collected automatically. This data is used to provide statistics or history data. For any bots that collect this data, it is necessary for features of said bot.
- Username ID (Unique identifier)
- Guild ID (Unique identifier)
- Any data needed for standard operation of Discord bots, such as server permissions
- Credits (/profile view)
- Points (/profile view)
- Levels (/profile view)
- Timestamps (Audit logs and all your data that we store)
### Data Storage
All stored data is kept on protected servers. While storage methods vary, most data is kept within password-protected databases such as [MongoDB Atlas](https://atlas.mongodb.com/). Please keep in mind that even with these protections, no data can ever be 100% secure. All efforts are taken to keep your data secure and private, but its absolute security cannot be guaranteed.
### Feedback
Feedback on Xyter bot and service is appreciated. When you submit comments, suggestions, bug reports, and any other forms of feedback, you forego any rights to the content, title, or intent of the provided feedback. Additionally, the feedback may be utilized in any way.
### Agreement
By adding Xyter bot to your server or using this bot or service in any way, you are consenting to the policies outlined in this document. In addition, you (the server manager) are agreeing to inform your members of the [Developer Terms of Service](https://discordapp.com/developers/docs/legal) and the contents of this document. If you, the server manager, do not agree to this document, you may remove the bot(s) from the server. If you, the server member, do not agree to this document, you may leave the server that contains the bot(s). If you, the service user, do not agree to this document, you may revoke authorization of the application(s) in your 'Authorized Apps' menu.
Changes to This Privacy Policy
We may update our Privacy Policy from time to time. Thus, we advise you to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately, after they are posted on this page.

View file

@ -1,14 +0,0 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ---------- | ------------------ |
| 2022.4.x | :white_check_mark: |
| < 2022.4.x | :x: |
## Reporting a Vulnerability
Report a security issue to Vermium#9649 on discord or vermium@zyner.org
I will try to fix the vulnerability within a month, often in some days only. If vulnerability is declined then still don't abuse it in any way you can.

39
docker-compose.yml Normal file
View file

@ -0,0 +1,39 @@
version: "3"
services:
app:
image: zyner/xyter:latest
restart: unless-stopped
# build: .
stdin_open: true
tty: true
volumes:
- ./logs:/app/logs
environment:
- DISCORD_TOKEN=DISCORD_TOKEN
- DISCORD_CLIENT_ID=DISCORD_CLIENT_ID
- DISCORD_GUILD_ID=DISCORD_GUILD_ID
- MONGO_URL=mongodb://MONGO_USER:MONGO_PASS@mongodb:27017/admin?retryWrites=true&w=majority
- ENCRYPTION_ALGORITHM=ENCRYPTION_ALGORITHM
- ENCRYPTION_SECRET=ENCRYPTION_SECRET
- EMEBD_COLOR_SUCCESS=EMEBD_COLOR_SUCCESS
- EMBED_COLOR_WAIT=EMBED_COLOR_WAIT
- EMBED_COLOR_ERROR=EMBED_COLOR_ERROR
- EMBED_FOOTER_TEXT=EMBED_FOOTER_TEXT
- EMBED_FOOTER_ICON=EMBED_FOOTER_ICON
- LOG_LEVEL=LOG_LEVEL
- REPUTATION_TIMEOUT=REPUTATION_TIMEOUT
- BOT_HOSTER_NAME=BOT_HOSTER_NAME
- BOT_HOSTER_URL=BOT_HOSTER_URL
- NODE_ENV=production
depends_on:
- mongodb
mongodb:
image: mongo:latest
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: MONGO_USER
MONGO_INITDB_ROOT_PASSWORD: MONGO_PASS
volumes:
- ./database:/data/db

View file

@ -21,23 +21,27 @@
"url": "https://github.com/ZynerOrg/xyter.git"
},
"author": "Vermium Sifell <vermium@zyner.org> (https://zyner.org)",
"contributors": [
"Joshua Schmitt <me@jqshuv.xyz> (https://jqshuv.xyz)"
],
"license": "GPL-3.0-only",
"bugs": {
"url": "https://github.com/ZynerOrg/xyter/issues",
"email": "vermium@zyner.org"
},
"dependencies": {
"@discordjs/builders": "^0.15.0",
"@discordjs/rest": "^0.5.0",
"@discordjs/rest": "^1.0.0",
"@prisma/client": "^4.5.0",
"@types/i18next-fs-backend": "^1.1.2",
"axios": "^0.27.2",
"axios": "^1.0.0",
"chance": "^1.1.8",
"common": "^0.2.5",
"crypto": "^1.0.1",
"discord-api-types": "^0.34.0",
"discord.js": "^13.6.0",
"discord-api-types": "^0.37.0",
"discord.js": "^14.0.0",
"dotenv": "^16.0.1",
"i18n": "^0.15.0",
"i18next": "^21.6.13",
"i18next": "^22.0.0",
"i18next-async-backend": "^2.0.0",
"i18next-fs-backend": "^1.1.4",
"i18next-http-backend": "^1.4.0",
@ -46,27 +50,28 @@
"node-schedule": "^2.1.0",
"ts-node": "^10.7.0",
"tsconfig-paths": "^4.0.0",
"typescript": "^4.6.3",
"uuid": "^8.3.2",
"typescript": "^4.8.4",
"uuid": "^9.0.0",
"winston-daily-rotate-file": "^4.6.1"
},
"devDependencies": {
"@types/chance": "^1.1.3",
"@types/chance": "1.1.3",
"@types/node-schedule": "2.1.0",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"eslint": "8.18.0",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.40.1",
"@typescript-eslint/parser": "5.40.1",
"eslint": "8.25.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-no-loops": "^0.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-no-loops": "0.3.0",
"eslint-plugin-prettier": "4.2.1",
"husky": "8.0.1",
"jest": "28.1.1",
"lint-staged": "13.0.1",
"nodemon": "^2.0.16",
"prettier": "^2.6.0"
"jest": "29.2.1",
"lint-staged": "13.0.3",
"nodemon": "2.0.20",
"prettier": "2.7.1",
"prisma": "4.5.0"
},
"lint-staged": {
"*.ts": "eslint --cache --fix"

2
prisma/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.db
*.db-journal

View file

@ -0,0 +1,29 @@
-- CreateTable
CREATE TABLE "Guild" (
"id" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
-- CreateIndex
CREATE UNIQUE INDEX "User_id_key" ON "User" ("id");
-- CreateIndex
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");

View file

@ -0,0 +1,26 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL,
CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildMember" ("guildId", "userId")
SELECT
"guildId",
"userId"
FROM
"GuildMember";
DROP TABLE "GuildMember";
ALTER TABLE "new_GuildMember" RENAME TO "GuildMember";
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,71 @@
-- AlterTable
ALTER TABLE "GuildMember"
ADD COLUMN "creditsEarned" INTEGER;
ALTER TABLE "GuildMember"
ADD COLUMN "pointsEarned" INTEGER;
-- CreateTable
CREATE TABLE "GuildCounter" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"word" TEXT NOT NULL,
"counter" INTEGER NOT NULL DEFAULT 0,
CONSTRAINT "GuildCounter_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE
);
INSERT INTO "new_Guild" ("id")
SELECT
"id"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
CREATE TABLE "new_User" (
"id" TEXT NOT NULL,
"reputationsEarned" INTEGER NOT NULL DEFAULT 0
);
INSERT INTO "new_User" ("id")
SELECT
"id"
FROM
"User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_id_key" ON "User" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;
-- CreateIndex
CREATE UNIQUE INDEX "GuildCounter_guildId_channelId_key" ON "GuildCounter" ("guildId", "channelId");

View file

@ -0,0 +1,35 @@
/*
Warnings:
- You are about to drop the column `counter` on the `GuildCounter` table. All the data in the column will be lost.
- You are about to drop the column `word` on the `GuildCounter` table. All the data in the column will be lost.
- Added the required column `triggerWord` to the `GuildCounter` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildCounter" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"triggerWord" TEXT NOT NULL,
"count" INTEGER NOT NULL DEFAULT 0,
CONSTRAINT "GuildCounter_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildCounter" ("channelId", "guildId")
SELECT
"channelId",
"guildId"
FROM
"GuildCounter";
DROP TABLE "GuildCounter";
ALTER TABLE "new_GuildCounter" RENAME TO "GuildCounter";
CREATE UNIQUE INDEX "GuildCounter_guildId_channelId_key" ON "GuildCounter" ("guildId", "channelId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,43 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE
);
INSERT INTO "new_Guild" ("countersEnabled", "creditsEnabled", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "id", "pointsEnabled", "pointsRate", "pointsTimeout", "reputationsEnabled")
SELECT
"countersEnabled",
"creditsEnabled",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"id",
"pointsEnabled",
"pointsRate",
"pointsTimeout",
"reputationsEnabled"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,45 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE
);
INSERT INTO "new_Guild" ("countersEnabled", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "id", "pointsEnabled", "pointsRate", "pointsTimeout", "reputationsEnabled")
SELECT
"countersEnabled",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"id",
"pointsEnabled",
"pointsRate",
"pointsTimeout",
"reputationsEnabled"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,30 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL,
"creditsEarned" INTEGER NOT NULL DEFAULT 0,
"pointsEarned" INTEGER NOT NULL DEFAULT 0,
CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildMember" ("creditsEarned", "guildId", "pointsEarned", "userId")
SELECT
coalesce("creditsEarned", 0) AS "creditsEarned",
"guildId",
coalesce("pointsEarned", 0) AS "pointsEarned",
"userId"
FROM
"GuildMember";
DROP TABLE "GuildMember";
ALTER TABLE "new_GuildMember" RENAME TO "GuildMember";
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,13 @@
-- CreateTable
CREATE TABLE "Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" INTEGER NOT NULL,
"timeoutId" TEXT NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");

View file

@ -0,0 +1,155 @@
/*
Warnings:
- Added the required column `updatedAt` to the `Guild` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `Cooldown` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `GuildCounter` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `User` table without a default value. This is not possible if the table is not empty.
- Added the required column `updatedAt` to the `GuildMember` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("countersEnabled", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled")
SELECT
"countersEnabled",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
CREATE TABLE "new_Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" INTEGER NOT NULL,
"timeoutId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Cooldown" ("cooldown", "guildId", "timeoutId", "userId")
SELECT
"cooldown",
"guildId",
"timeoutId",
"userId"
FROM
"Cooldown";
DROP TABLE "Cooldown";
ALTER TABLE "new_Cooldown" RENAME TO "Cooldown";
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");
CREATE TABLE "new_GuildCounter" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"triggerWord" TEXT NOT NULL,
"count" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildCounter_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildCounter" ("channelId", "count", "guildId", "triggerWord")
SELECT
"channelId",
"count",
"guildId",
"triggerWord"
FROM
"GuildCounter";
DROP TABLE "GuildCounter";
ALTER TABLE "new_GuildCounter" RENAME TO "GuildCounter";
CREATE UNIQUE INDEX "GuildCounter_guildId_channelId_key" ON "GuildCounter" ("guildId", "channelId");
CREATE TABLE "new_User" (
"id" TEXT NOT NULL,
"reputationsEarned" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_User" ("id", "reputationsEarned")
SELECT
"id",
"reputationsEarned"
FROM
"User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_id_key" ON "User" ("id");
CREATE TABLE "new_GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL,
"creditsEarned" INTEGER NOT NULL DEFAULT 0,
"pointsEarned" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildMember" ("creditsEarned", "guildId", "pointsEarned", "userId")
SELECT
"creditsEarned",
"guildId",
"pointsEarned",
"userId"
FROM
"GuildMember";
DROP TABLE "GuildMember";
ALTER TABLE "new_GuildMember" RENAME TO "GuildMember";
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,55 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "updatedAt")
SELECT
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"updatedAt"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,12 @@
-- AlterTable
ALTER TABLE "Guild"
ADD COLUMN "apiCpggTokenContent" TEXT;
ALTER TABLE "Guild"
ADD COLUMN "apiCpggTokenIv" TEXT;
ALTER TABLE "Guild"
ADD COLUMN "apiCpggUrlContent" TEXT;
ALTER TABLE "Guild"
ADD COLUMN "apiCpggUrlIv" TEXT;

View file

@ -0,0 +1,34 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" TEXT NOT NULL,
"timeoutId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Cooldown" ("cooldown", "createdAt", "guildId", "timeoutId", "updatedAt", "userId")
SELECT
"cooldown",
"createdAt",
"guildId",
"timeoutId",
"updatedAt",
"userId"
FROM
"Cooldown";
DROP TABLE "Cooldown";
ALTER TABLE "new_Cooldown" RENAME TO "Cooldown";
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,40 @@
/*
Warnings:
- You are about to alter the column `cooldown` on the `Cooldown` table. The data in that column could be lost. The data in that column will be cast from `String` to `Int`.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" INTEGER NOT NULL,
"timeoutId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Cooldown" ("cooldown", "createdAt", "guildId", "timeoutId", "updatedAt", "userId")
SELECT
"cooldown",
"createdAt",
"guildId",
"timeoutId",
"updatedAt",
"userId"
FROM
"Cooldown";
DROP TABLE "Cooldown";
ALTER TABLE "new_Cooldown" RENAME TO "Cooldown";
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,70 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "updatedAt")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"updatedAt"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,74 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" INTEGER NOT NULL DEFAULT 5,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "updatedAt")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"updatedAt"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,79 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" INTEGER NOT NULL DEFAULT 5,
"welcomeEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"welcomeJoinChannelId" TEXT,
"welcomejoinChannelMessahe" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "shopRolesEnabled", "shopRolesPricePerHour", "updatedAt")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"shopRolesEnabled",
"shopRolesPricePerHour",
"updatedAt"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,89 @@
/*
Warnings:
- You are about to drop the column `welcomejoinChannelMessahe` on the `Guild` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" INTEGER NOT NULL DEFAULT 5,
"welcomeEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"welcomeJoinChannelId" TEXT,
"welcomeJoinChannelMessahe" TEXT,
"welcomeLeaveChannelId" TEXT,
"welcomeLeaveChannelMessage" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "shopRolesEnabled", "shopRolesPricePerHour", "updatedAt", "welcomeEnabled", "welcomeJoinChannelId")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"shopRolesEnabled",
"shopRolesPricePerHour",
"updatedAt",
"welcomeEnabled",
"welcomeJoinChannelId"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,91 @@
/*
Warnings:
- You are about to drop the column `welcomeJoinChannelMessahe` on the `Guild` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" INTEGER NOT NULL DEFAULT 5,
"welcomeEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"welcomeJoinChannelId" TEXT,
"welcomeJoinChannelMessage" TEXT,
"welcomeLeaveChannelId" TEXT,
"welcomeLeaveChannelMessage" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "shopRolesEnabled", "shopRolesPricePerHour", "updatedAt", "welcomeEnabled", "welcomeJoinChannelId", "welcomeLeaveChannelId", "welcomeLeaveChannelMessage")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"shopRolesEnabled",
"shopRolesPricePerHour",
"updatedAt",
"welcomeEnabled",
"welcomeJoinChannelId",
"welcomeLeaveChannelId",
"welcomeLeaveChannelMessage"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "GuildShopRoles" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" INTEGER NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "GuildShopRoles_guildId_channelId_key" ON "GuildShopRoles" ("guildId", "channelId");

View file

@ -0,0 +1,42 @@
/*
Warnings:
- You are about to drop the column `channelId` on the `GuildShopRoles` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildShopRoles" (
"guildId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" INTEGER NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildShopRoles" ("createdAt", "guildId", "lastPayed", "pricePerHour", "roleId", "updatedAt", "userId")
SELECT
"createdAt",
"guildId",
"lastPayed",
"pricePerHour",
"roleId",
"updatedAt",
"userId"
FROM
"GuildShopRoles";
DROP TABLE "GuildShopRoles";
ALTER TABLE "new_GuildShopRoles" RENAME TO "GuildShopRoles";
CREATE UNIQUE INDEX "GuildShopRoles_guildId_userId_roleId_key" ON "GuildShopRoles" ("guildId", "userId", "roleId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,39 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildShopRoles" (
"guildId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" INTEGER NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_guildId_userId_fkey" FOREIGN KEY ("guildId",
"userId") REFERENCES "GuildMember" ("guildId",
"userId") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildShopRoles" ("createdAt", "guildId", "lastPayed", "pricePerHour", "roleId", "updatedAt", "userId")
SELECT
"createdAt",
"guildId",
"lastPayed",
"pricePerHour",
"roleId",
"updatedAt",
"userId"
FROM
"GuildShopRoles";
DROP TABLE "GuildShopRoles";
ALTER TABLE "new_GuildShopRoles" RENAME TO "GuildShopRoles";
CREATE UNIQUE INDEX "GuildShopRoles_guildId_userId_roleId_key" ON "GuildShopRoles" ("guildId", "userId", "roleId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,39 @@
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildShopRoles" (
"guildId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" INTEGER NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_guildId_fkey" FOREIGN KEY ("userId",
"guildId") REFERENCES "GuildMember" ("userId",
"guildId") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildShopRoles" ("createdAt", "guildId", "lastPayed", "pricePerHour", "roleId", "updatedAt", "userId")
SELECT
"createdAt",
"guildId",
"lastPayed",
"pricePerHour",
"roleId",
"updatedAt",
"userId"
FROM
"GuildShopRoles";
DROP TABLE "GuildShopRoles";
ALTER TABLE "new_GuildShopRoles" RENAME TO "GuildShopRoles";
CREATE UNIQUE INDEX "GuildShopRoles_guildId_userId_roleId_key" ON "GuildShopRoles" ("guildId", "userId", "roleId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,244 @@
/*
Warnings:
- You are about to alter the column `count` on the `GuildCounter` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsEarned` on the `GuildMember` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `pointsEarned` on the `GuildMember` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `pricePerHour` on the `GuildShopRoles` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `cooldown` on the `Cooldown` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsMinimumLength` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsWorkRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `creditsWorkTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `pointsMinimumLength` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `pointsRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `pointsTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `shopRolesPricePerHour` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
- You are about to alter the column `reputationsEarned` on the `User` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_GuildCounter" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"triggerWord" TEXT NOT NULL,
"count" BIGINT NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildCounter_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildCounter" ("channelId", "count", "createdAt", "guildId", "triggerWord", "updatedAt")
SELECT
"channelId",
"count",
"createdAt",
"guildId",
"triggerWord",
"updatedAt"
FROM
"GuildCounter";
DROP TABLE "GuildCounter";
ALTER TABLE "new_GuildCounter" RENAME TO "GuildCounter";
CREATE UNIQUE INDEX "GuildCounter_guildId_channelId_key" ON "GuildCounter" ("guildId", "channelId");
CREATE TABLE "new_GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL,
"creditsEarned" BIGINT NOT NULL DEFAULT 0,
"pointsEarned" BIGINT NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildMember" ("createdAt", "creditsEarned", "guildId", "pointsEarned", "updatedAt", "userId")
SELECT
"createdAt",
"creditsEarned",
"guildId",
"pointsEarned",
"updatedAt",
"userId"
FROM
"GuildMember";
DROP TABLE "GuildMember";
ALTER TABLE "new_GuildMember" RENAME TO "GuildMember";
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");
CREATE TABLE "new_GuildShopRoles" (
"guildId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" BIGINT NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_guildId_fkey" FOREIGN KEY ("userId",
"guildId") REFERENCES "GuildMember" ("userId",
"guildId") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildShopRoles" ("createdAt", "guildId", "lastPayed", "pricePerHour", "roleId", "updatedAt", "userId")
SELECT
"createdAt",
"guildId",
"lastPayed",
"pricePerHour",
"roleId",
"updatedAt",
"userId"
FROM
"GuildShopRoles";
DROP TABLE "GuildShopRoles";
ALTER TABLE "new_GuildShopRoles" RENAME TO "GuildShopRoles";
CREATE UNIQUE INDEX "GuildShopRoles_guildId_userId_roleId_key" ON "GuildShopRoles" ("guildId", "userId", "roleId");
CREATE TABLE "new_Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" BIGINT NOT NULL,
"timeoutId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Cooldown" ("cooldown", "createdAt", "guildId", "timeoutId", "updatedAt", "userId")
SELECT
"cooldown",
"createdAt",
"guildId",
"timeoutId",
"updatedAt",
"userId"
FROM
"Cooldown";
DROP TABLE "Cooldown";
ALTER TABLE "new_Cooldown" RENAME TO "Cooldown";
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" BIGINT NOT NULL DEFAULT 1,
"creditsTimeout" BIGINT NOT NULL DEFAULT 5,
"creditsWorkRate" BIGINT NOT NULL DEFAULT 25,
"creditsWorkTimeout" BIGINT NOT NULL DEFAULT 86400,
"creditsMinimumLength" BIGINT NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" BIGINT NOT NULL DEFAULT 1,
"pointsTimeout" BIGINT NOT NULL DEFAULT 5,
"pointsMinimumLength" BIGINT NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" BIGINT NOT NULL DEFAULT 5,
"welcomeEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"welcomeJoinChannelId" TEXT,
"welcomeJoinChannelMessage" TEXT,
"welcomeLeaveChannelId" TEXT,
"welcomeLeaveChannelMessage" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "shopRolesEnabled", "shopRolesPricePerHour", "updatedAt", "welcomeEnabled", "welcomeJoinChannelId", "welcomeJoinChannelMessage", "welcomeLeaveChannelId", "welcomeLeaveChannelMessage")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"shopRolesEnabled",
"shopRolesPricePerHour",
"updatedAt",
"welcomeEnabled",
"welcomeJoinChannelId",
"welcomeJoinChannelMessage",
"welcomeLeaveChannelId",
"welcomeLeaveChannelMessage"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
CREATE TABLE "new_User" (
"id" TEXT NOT NULL,
"reputationsEarned" BIGINT NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_User" ("createdAt", "id", "reputationsEarned", "updatedAt")
SELECT
"createdAt",
"id",
"reputationsEarned",
"updatedAt"
FROM
"User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_id_key" ON "User" ("id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,244 @@
/*
Warnings:
- You are about to alter the column `reputationsEarned` on the `User` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `count` on the `GuildCounter` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsEarned` on the `GuildMember` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `pointsEarned` on the `GuildMember` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `pricePerHour` on the `GuildShopRoles` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsMinimumLength` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsWorkRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `creditsWorkTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `pointsMinimumLength` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `pointsRate` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `pointsTimeout` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `shopRolesPricePerHour` on the `Guild` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `cooldown` on the `Cooldown` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
*/
-- RedefineTables
PRAGMA foreign_keys = OFF;
CREATE TABLE "new_User" (
"id" TEXT NOT NULL,
"reputationsEarned" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_User" ("createdAt", "id", "reputationsEarned", "updatedAt")
SELECT
"createdAt",
"id",
"reputationsEarned",
"updatedAt"
FROM
"User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_id_key" ON "User" ("id");
CREATE TABLE "new_GuildCounter" (
"guildId" TEXT NOT NULL,
"channelId" TEXT NOT NULL,
"triggerWord" TEXT NOT NULL,
"count" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildCounter_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildCounter" ("channelId", "count", "createdAt", "guildId", "triggerWord", "updatedAt")
SELECT
"channelId",
"count",
"createdAt",
"guildId",
"triggerWord",
"updatedAt"
FROM
"GuildCounter";
DROP TABLE "GuildCounter";
ALTER TABLE "new_GuildCounter" RENAME TO "GuildCounter";
CREATE UNIQUE INDEX "GuildCounter_guildId_channelId_key" ON "GuildCounter" ("guildId", "channelId");
CREATE TABLE "new_GuildMember" (
"userId" TEXT NOT NULL,
"guildId" TEXT NOT NULL,
"creditsEarned" INTEGER NOT NULL DEFAULT 0,
"pointsEarned" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildMember_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildMember" ("createdAt", "creditsEarned", "guildId", "pointsEarned", "updatedAt", "userId")
SELECT
"createdAt",
"creditsEarned",
"guildId",
"pointsEarned",
"updatedAt",
"userId"
FROM
"GuildMember";
DROP TABLE "GuildMember";
ALTER TABLE "new_GuildMember" RENAME TO "GuildMember";
CREATE UNIQUE INDEX "GuildMember_userId_guildId_key" ON "GuildMember" ("userId", "guildId");
CREATE TABLE "new_GuildShopRoles" (
"guildId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"pricePerHour" INTEGER NOT NULL DEFAULT 5,
"lastPayed" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "GuildShopRoles_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "GuildShopRoles_userId_guildId_fkey" FOREIGN KEY ("userId",
"guildId") REFERENCES "GuildMember" ("userId",
"guildId") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_GuildShopRoles" ("createdAt", "guildId", "lastPayed", "pricePerHour", "roleId", "updatedAt", "userId")
SELECT
"createdAt",
"guildId",
"lastPayed",
"pricePerHour",
"roleId",
"updatedAt",
"userId"
FROM
"GuildShopRoles";
DROP TABLE "GuildShopRoles";
ALTER TABLE "new_GuildShopRoles" RENAME TO "GuildShopRoles";
CREATE UNIQUE INDEX "GuildShopRoles_guildId_userId_roleId_key" ON "GuildShopRoles" ("guildId", "userId", "roleId");
CREATE TABLE "new_Guild" (
"id" TEXT NOT NULL,
"embedColorSuccess" TEXT NOT NULL DEFAULT '#22bb33',
"embedColorWait" TEXT NOT NULL DEFAULT '#f0ad4e',
"embedColorError" TEXT NOT NULL DEFAULT '#bb2124',
"embedFooterText" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg/xyter',
"embedFooterIcon" TEXT NOT NULL DEFAULT 'https://github.com/ZynerOrg.png',
"creditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"creditsRate" INTEGER NOT NULL DEFAULT 1,
"creditsTimeout" INTEGER NOT NULL DEFAULT 5,
"creditsWorkRate" INTEGER NOT NULL DEFAULT 25,
"creditsWorkTimeout" INTEGER NOT NULL DEFAULT 86400,
"creditsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"pointsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"pointsRate" INTEGER NOT NULL DEFAULT 1,
"pointsTimeout" INTEGER NOT NULL DEFAULT 5,
"pointsMinimumLength" INTEGER NOT NULL DEFAULT 5,
"reputationsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"countersEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"apiCpggUrlIv" TEXT,
"apiCpggUrlContent" TEXT,
"apiCpggTokenIv" TEXT,
"apiCpggTokenContent" TEXT,
"auditsEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"auditsChannelId" TEXT,
"shopRolesEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"shopRolesPricePerHour" INTEGER NOT NULL DEFAULT 5,
"welcomeEnabled" BOOLEAN NOT NULL DEFAULT FALSE,
"welcomeJoinChannelId" TEXT,
"welcomeJoinChannelMessage" TEXT,
"welcomeLeaveChannelId" TEXT,
"welcomeLeaveChannelMessage" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_Guild" ("apiCpggTokenContent", "apiCpggTokenIv", "apiCpggUrlContent", "apiCpggUrlIv", "auditsChannelId", "auditsEnabled", "countersEnabled", "createdAt", "creditsEnabled", "creditsMinimumLength", "creditsRate", "creditsTimeout", "creditsWorkRate", "creditsWorkTimeout", "embedColorError", "embedColorSuccess", "embedColorWait", "embedFooterIcon", "embedFooterText", "id", "pointsEnabled", "pointsMinimumLength", "pointsRate", "pointsTimeout", "reputationsEnabled", "shopRolesEnabled", "shopRolesPricePerHour", "updatedAt", "welcomeEnabled", "welcomeJoinChannelId", "welcomeJoinChannelMessage", "welcomeLeaveChannelId", "welcomeLeaveChannelMessage")
SELECT
"apiCpggTokenContent",
"apiCpggTokenIv",
"apiCpggUrlContent",
"apiCpggUrlIv",
"auditsChannelId",
"auditsEnabled",
"countersEnabled",
"createdAt",
"creditsEnabled",
"creditsMinimumLength",
"creditsRate",
"creditsTimeout",
"creditsWorkRate",
"creditsWorkTimeout",
"embedColorError",
"embedColorSuccess",
"embedColorWait",
"embedFooterIcon",
"embedFooterText",
"id",
"pointsEnabled",
"pointsMinimumLength",
"pointsRate",
"pointsTimeout",
"reputationsEnabled",
"shopRolesEnabled",
"shopRolesPricePerHour",
"updatedAt",
"welcomeEnabled",
"welcomeJoinChannelId",
"welcomeJoinChannelMessage",
"welcomeLeaveChannelId",
"welcomeLeaveChannelMessage"
FROM
"Guild";
DROP TABLE "Guild";
ALTER TABLE "new_Guild" RENAME TO "Guild";
CREATE UNIQUE INDEX "Guild_id_key" ON "Guild" ("id");
CREATE TABLE "new_Cooldown" (
"guildId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"cooldown" INTEGER NOT NULL,
"timeoutId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Cooldown_guildId_fkey" FOREIGN KEY ("guildId") REFERENCES "Guild" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Cooldown_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Cooldown" ("cooldown", "createdAt", "guildId", "timeoutId", "updatedAt", "userId")
SELECT
"cooldown",
"createdAt",
"guildId",
"timeoutId",
"updatedAt",
"userId"
FROM
"Cooldown";
DROP TABLE "Cooldown";
ALTER TABLE "new_Cooldown" RENAME TO "Cooldown";
CREATE UNIQUE INDEX "Cooldown_guildId_userId_timeoutId_key" ON "Cooldown" ("guildId", "userId", "timeoutId");
PRAGMA foreign_key_check;
PRAGMA foreign_keys = ON;

View file

@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"

144
prisma/schema.prisma Normal file
View file

@ -0,0 +1,144 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
previewFeatures = ["interactiveTransactions"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model Guild {
id String @unique
guildMembers GuildMember[]
cooldowns Cooldown[]
// Settings
embedColorSuccess String @default("#22bb33")
embedColorWait String @default("#f0ad4e")
embedColorError String @default("#bb2124")
embedFooterText String @default("https://github.com/ZynerOrg/xyter")
embedFooterIcon String @default("https://github.com/ZynerOrg.png")
// Modules
creditsEnabled Boolean @default(false)
creditsRate Int @default(1)
creditsTimeout Int @default(5)
creditsWorkRate Int @default(25)
creditsWorkTimeout Int @default(86400)
creditsMinimumLength Int @default(5)
pointsEnabled Boolean @default(false)
pointsRate Int @default(1)
pointsTimeout Int @default(5)
pointsMinimumLength Int @default(5)
reputationsEnabled Boolean @default(false)
countersEnabled Boolean @default(false)
counters GuildCounter[]
apiCpggUrlIv String?
apiCpggUrlContent String?
apiCpggTokenIv String?
apiCpggTokenContent String?
auditsEnabled Boolean @default(false)
auditsChannelId String?
shopRolesEnabled Boolean @default(false)
shopRolesPricePerHour Int @default(5)
welcomeEnabled Boolean @default(false)
welcomeJoinChannelId String?
welcomeJoinChannelMessage String?
welcomeLeaveChannelId String?
welcomeLeaveChannelMessage String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
}
model User {
id String @unique
GuildMember GuildMember[]
// Settings
// Modules
reputationsEarned Int @default(0)
Cooldown Cooldown[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
}
model GuildMember {
userId String
guildId String
user User @relation(fields: [userId], references: [id])
guild Guild @relation(fields: [guildId], references: [id])
// Settings
// Modules
creditsEarned Int @default(0)
pointsEarned Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
// Unique Identifier
@@unique([userId, guildId])
}
model GuildCounter {
guildId String
channelId String
triggerWord String
count Int @default(0)
guild Guild @relation(fields: [guildId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([guildId, channelId])
}
model Cooldown {
guild Guild @relation(fields: [guildId], references: [id])
user User @relation(fields: [userId], references: [id])
guildId String
userId String
cooldown Int
timeoutId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([guildId, userId, timeoutId])
}
model GuildShopRoles {
guildId String
roleId String
userId String
pricePerHour Int @default(5)
lastPayed DateTime
guild Guild @relation(fields: [guildId], references: [id])
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
member GuildMember? @relation(fields: [userId, guildId], references: [userId, guildId])
@@unique([guildId, userId, roleId])
}

View file

@ -1,8 +1,9 @@
import { ButtonInteraction } from "discord.js";
import logger from "../../../logger";
import logger from "../../middlewares/logger";
export const metadata = { guildOnly: false, ephemeral: false };
export const execute = async (interaction: ButtonInteraction) => {
// Execute the function
export const execute = (interaction: ButtonInteraction) => {
logger.debug(interaction.customId, "primary button clicked!");
};

View file

@ -0,0 +1,54 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleAudits from "./modules/audits";
import moduleCpgg from "./modules/cpgg";
import moduleCredits from "./modules/credits";
import moduleEmbeds from "./modules/embeds";
import modulePoints from "./modules/points";
import moduleShop from "./modules/shop";
import moduleWelcome from "./modules/welcome";
export const builder = new SlashCommandBuilder()
.setName("config")
.setDescription("Manage guild configurations.")
.setDMPermission(false)
// Modules
.addSubcommand(moduleAudits.builder)
.addSubcommand(moduleCpgg.builder)
.addSubcommand(moduleCredits.builder)
.addSubcommand(moduleEmbeds.builder)
.addSubcommand(modulePoints.builder)
.addSubcommand(moduleShop.builder)
.addSubcommand(moduleWelcome.builder);
// Execute function
export const execute = async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "audits":
await moduleAudits.execute(interaction);
break;
case "cpgg":
await moduleCpgg.execute(interaction);
break;
case "credits":
await moduleCredits.execute(interaction);
break;
case "embeds":
await moduleEmbeds.execute(interaction);
break;
case "points":
await modulePoints.execute(interaction);
break;
case "shop":
await moduleShop.execute(interaction);
break;
case "welcome":
await moduleWelcome.execute(interaction);
break;
default:
throw new Error("No module found for that specific command.");
}
};

View file

@ -0,0 +1,97 @@
import { ChannelType } from "discord-api-types/v10";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
SlashCommandSubcommandBuilder,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("audits")
.setDescription("Audits")
.addBooleanOption((option) =>
option
.setName("status")
.setDescription("Should audits be enabled?")
.setRequired(true)
)
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("Channel for audit messages.")
.addChannelTypes(ChannelType.GuildText)
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { guild, options } = interaction;
const { successColor, footerText, footerIcon } = await getEmbedConfig(
guild
);
const status = options.getBoolean("status");
const channel = options.getChannel("channel");
if (!guild) throw new Error("Guild not found.");
if (!channel) throw new Error("Channel not found.");
if (status === null) throw new Error("Status not found.");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
auditsEnabled: status,
auditsChannelId: channel.id,
},
create: {
id: guild.id,
auditsEnabled: status,
auditsChannelId: channel.id,
},
});
logger.silly(createGuild);
const embedSuccess = new EmbedBuilder()
.setTitle("[:hammer:] Audits")
.setDescription("Guild configuration updated successfully.")
.setColor(successColor)
.addFields(
{
name: "🤖 Status",
value: `${
createGuild.auditsEnabled
? ":white_check_mark: Enabled"
: ":x: Disabled"
}`,
inline: true,
},
{
name: "🌊 Channel",
value: `<#${createGuild.auditsChannelId}>`,
inline: true,
}
)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction.editReply({
embeds: [embedSuccess],
});
return;
},
};

View file

@ -0,0 +1,106 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import encryption from "../../../../helpers/encryption";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("cpgg")
.setDescription("Controlpanel.gg")
.addStringOption((option) =>
option
.setName("scheme")
.setDescription(`Controlpanel.gg Scheme`)
.setRequired(true)
.setChoices(
{ name: "HTTPS (secure)", value: "https" },
{ name: "HTTP (insecure)", value: "http" }
)
)
.addStringOption((option) =>
option
.setName("domain")
.setDescription(`Controlpanel.gg Domain`)
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("token")
.setDescription(`Controlpanel.gg Application API`)
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const tokenData = options.getString("token");
const scheme = options.getString("scheme");
const domain = options.getString("domain");
const token = tokenData && encryption.encrypt(tokenData);
const url = scheme && domain && encryption.encrypt(`${scheme}://${domain}`);
if (!guild) throw new Error("No guild found");
if (!token) throw new Error("Token not found");
if (!url) throw new Error("URL not found");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
apiCpggTokenIv: token.iv,
apiCpggTokenContent: token.content,
apiCpggUrlIv: url.iv,
apiCpggUrlContent: url.content,
},
create: {
id: guild.id,
apiCpggTokenIv: token.iv,
apiCpggTokenContent: token.content,
apiCpggUrlIv: url.iv,
apiCpggUrlContent: url.content,
},
});
logger.silly(createGuild);
logger?.silly(`Updated API credentials.`);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] CPGG")
.setDescription(
`The following configuration will be used.
**Scheme**: ${scheme}
**Domain**: ${domain}
**Token**: ends with ${tokenData?.slice(-4)}`
)
.setColor(successColor)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction?.editReply({
embeds: [interactionEmbed],
});
return;
},
};

View file

@ -0,0 +1,165 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("credits")
.setDescription(`Configure this guild's credits module.`)
.addBooleanOption((option) =>
option
.setName("enabled")
.setDescription("Do you want to activate the credit module?")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("rate")
.setDescription("Credit rate per message.")
.setRequired(true)
.setMinValue(1)
)
.addNumberOption((option) =>
option
.setName("minimum-length")
.setDescription("Minimum message length to receive credit.")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("work-rate")
.setDescription(
"The maximum amount of credit that can be obtained within a working day."
)
.setRequired(true)
.setMinValue(1)
)
.addNumberOption((option) =>
option
.setName("work-timeout")
.setDescription(
"How long you need to wait before you can work again provided in seconds."
)
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("timeout")
.setDescription(
"How long you need to wait before you can earn more credits."
)
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { guild, options } = interaction;
const enabled = options.getBoolean("enabled");
const rate = options.getNumber("rate");
const timeout = options.getNumber("timeout");
const minimumLength = options.getNumber("minimum-length");
const workRate = options.getNumber("work-rate");
const workTimeout = options.getNumber("work-timeout");
if (!guild) throw new Error("Guild not found.");
if (typeof enabled !== "boolean")
throw new Error("Enabled option is not a boolean.");
if (typeof rate !== "number") throw new Error("Rate is not a number.");
if (typeof workRate !== "number")
throw new Error("Work rate is not a number.");
if (typeof workTimeout !== "number")
throw new Error("Work timeout is not a number.");
if (typeof timeout !== "number")
throw new Error("Timeout is not a number.");
if (typeof minimumLength !== "number")
throw new Error("Minimum length is not a number.");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
creditsEnabled: enabled,
creditsRate: rate,
creditsTimeout: timeout,
creditsWorkRate: workRate,
creditsWorkTimeout: workTimeout,
creditsMinimumLength: minimumLength,
},
create: {
id: guild.id,
creditsEnabled: enabled,
creditsRate: rate,
creditsTimeout: timeout,
creditsWorkRate: workRate,
creditsWorkTimeout: workTimeout,
creditsMinimumLength: minimumLength,
},
});
logger.silly(createGuild);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] Credits")
.setDescription("Credits settings updated")
.setColor(successColor)
.addFields(
{
name: "🤖 Enabled?",
value: `${createGuild.creditsEnabled}`,
inline: true,
},
{
name: "📈 Rate",
value: `${createGuild.creditsRate}`,
inline: true,
},
{
name: "📈 Work Rate",
value: `${createGuild.creditsWorkRate}`,
inline: true,
},
{
name: "🔨 Minimum Length",
value: `${createGuild.creditsMinimumLength}`,
inline: true,
},
{
name: "⏰ Timeout",
value: `${createGuild.creditsTimeout}`,
inline: true,
},
{
name: "⏰ Work Timeout",
value: `${createGuild.creditsWorkTimeout}`,
inline: true,
}
)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction.editReply({
embeds: [interactionEmbed],
});
return;
},
};

View file

@ -0,0 +1,56 @@
import { ChatInputCommandInteraction, ColorResolvable } from "discord.js";
import prisma from "../../../../../../handlers/database";
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
import logger from "../../../../../../middlewares/logger";
export default async (interaction: ChatInputCommandInteraction) => {
const { options, guild } = interaction;
if (!guild) throw new Error("Guild not found");
const embedConfig = await getEmbedConfig(guild);
if (!embedConfig) throw new Error("Embed config not found");
const newSuccessColor = <ColorResolvable>options.getString("success-color");
const newWaitColor = <ColorResolvable>options.getString("wait-color");
const newErrorColor = <ColorResolvable>options.getString("error-color");
const newFooterIcon = options.getString("footer-icon");
const newFooterText = options.getString("footer-text");
if (!newSuccessColor) throw new Error("Success color not found");
if (!newWaitColor) throw new Error("Wait color not found");
if (!newErrorColor) throw new Error("Error color not found");
if (!newFooterIcon) throw new Error("Footer icon not found");
if (!newFooterText) throw new Error("Footer text not found");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
embedColorSuccess: <string>newSuccessColor,
embedColorWait: <string>newWaitColor,
embedColorError: <string>newErrorColor,
embedFooterIcon: newFooterIcon,
embedFooterText: newFooterText,
},
create: {
id: guild.id,
embedColorSuccess: <string>newSuccessColor,
embedColorWait: <string>newWaitColor,
embedColorError: <string>newErrorColor,
embedFooterIcon: newFooterIcon,
embedFooterText: newFooterText,
},
});
logger.silly(createGuild);
const successColor = <ColorResolvable>createGuild.embedColorSuccess;
const waitColor = <ColorResolvable>createGuild.embedColorWait;
const errorColor = <ColorResolvable>createGuild.embedColorError;
const footerText = createGuild.embedFooterText;
const footerIcon = createGuild.embedFooterIcon;
return { successColor, waitColor, errorColor, footerText, footerIcon };
};

View file

@ -0,0 +1,100 @@
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getValues from "./components/getValues";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("embeds")
.setDescription(`Embeds`)
.addStringOption((option) =>
option
.setName("success-color")
.setDescription("No provided description")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("wait-color")
.setDescription("No provided description")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("error-color")
.setDescription("No provided description")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("footer-icon")
.setDescription("No provided description")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("footer-text")
.setDescription("No provided description")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { guild } = interaction;
if (!guild) throw new Error("Guild not found");
const { successColor, waitColor, errorColor, footerText, footerIcon } =
await getValues(interaction);
const embed = new EmbedBuilder()
.setTitle("[:tools:] Embeds")
.setFooter({ text: footerText, iconURL: footerIcon })
.setTimestamp(new Date());
embed
.setDescription("Following embed configuration will be used.")
.setColor(successColor)
.addFields([
{
name: "🟢 Success Color",
value: `${successColor}`,
inline: true,
},
{
name: "🟡 Wait Color",
value: `${waitColor}`,
inline: true,
},
{
name: "🔴 Error Color",
value: `${errorColor}`,
inline: true,
},
{
name: "🖼️ Footer Icon",
value: `${footerIcon}`,
inline: true,
},
{
name: "📄 Footer Text",
value: `${footerText}`,
inline: true,
},
]);
await interaction.editReply({
embeds: [embed],
});
return;
},
};

View file

@ -0,0 +1,123 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("points")
.setDescription("Points")
.addBooleanOption((option) =>
option
.setName("status")
.setDescription("Should credits be enabled?")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("rate")
.setDescription("Amount of credits per message.")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("minimum-length")
.setDescription("Minimum length of message to earn credits.")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("timeout")
.setDescription("Timeout between earning credits (milliseconds).")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const status = options?.getBoolean("status");
const rate = options?.getNumber("rate");
const timeout = options?.getNumber("timeout");
const minimumLength = options?.getNumber("minimum-length");
if (!guild) throw new Error("Guild is required");
if (status === null) throw new Error("Status must be specified");
if (!rate) throw new Error("Rate must be specified");
if (!timeout) throw new Error("Timeout must be specified");
if (!minimumLength) throw new Error("Minimum length must be specified");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
pointsEnabled: status,
pointsRate: rate,
pointsTimeout: timeout,
pointsMinimumLength: minimumLength,
},
create: {
id: guild.id,
pointsEnabled: status,
pointsRate: rate,
pointsTimeout: timeout,
pointsMinimumLength: minimumLength,
},
});
logger.silly(createGuild);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] Points")
.setDescription("Points settings updated")
.setColor(successColor)
.addFields(
{
name: "🤖 Status",
value: `${createGuild.pointsEnabled}`,
inline: true,
},
{
name: "📈 Rate",
value: `${createGuild.pointsRate}`,
inline: true,
},
{
name: "🔨 Minimum Length",
value: `${createGuild.pointsMinimumLength}`,
inline: true,
},
{
name: "⏰ Timeout",
value: `${createGuild.pointsTimeout}`,
inline: true,
}
)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction?.editReply({
embeds: [interactionEmbed],
});
return;
},
};

View file

@ -0,0 +1,93 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("shop")
.setDescription("Shop")
.addBooleanOption((option) =>
option
.setName("roles-status")
.setDescription("Should roles be enabled?")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("roles-price-per-hour")
.setDescription("Price per hour for roles.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const rolesStatus = options?.getBoolean("roles-status");
const rolesPricePerHour = options?.getNumber("roles-price-per-hour");
if (!guild) throw new Error("Guild not found");
if (rolesStatus === null) throw new Error("Status must be provided");
if (!rolesPricePerHour)
throw new Error("Roles price per hour must be provided");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
shopRolesEnabled: rolesStatus,
shopRolesPricePerHour: rolesPricePerHour,
},
create: {
id: guild.id,
shopRolesEnabled: rolesStatus,
shopRolesPricePerHour: rolesPricePerHour,
},
});
logger.silly(createGuild);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] Shop")
.setDescription("Shop settings updated")
.setColor(successColor)
.addFields(
{
name: "🤖 Roles Status",
value: `${createGuild.shopRolesEnabled}`,
inline: true,
},
{
name: "🌊 Roles Price Per Hour",
value: `${createGuild.shopRolesPricePerHour}`,
inline: true,
}
)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction?.editReply({
embeds: [interactionEmbed],
});
return;
},
};

View file

@ -0,0 +1,147 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChannelType } from "discord-api-types/v10";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("welcome")
.setDescription("Welcome")
.addBooleanOption((option) =>
option
.setName("status")
.setDescription("Should welcome be enabled?")
.setRequired(true)
)
.addChannelOption((option) =>
option
.setName("join-channel")
.setDescription("Channel for join messages.")
.addChannelTypes(ChannelType.GuildText)
.setRequired(true)
)
.addChannelOption((option) =>
option
.setName("leave-channel")
.setDescription("Channel for leave messages.")
.addChannelTypes(ChannelType.GuildText)
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("leave-message")
.setDescription("Message for leave messages.")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("join-message")
.setDescription("Message for join messages.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const status = options?.getBoolean("status");
const joinChannel = options?.getChannel("join-channel");
const leaveChannel = options?.getChannel("leave-channel");
const joinChannelMessage = options?.getString("join-message");
const leaveChannelMessage = options?.getString("leave-message");
if (!guild) throw new Error("Guild not found");
if (status === null) throw new Error("Status not specified");
if (!joinChannel) throw new Error("Join channel not specified");
if (!joinChannelMessage)
throw new Error("Join channel message not specified");
if (!leaveChannel) throw new Error("Leave channel not specified");
if (!leaveChannelMessage)
throw new Error("Leave channel message not specified");
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {
welcomeEnabled: status,
welcomeJoinChannelId: joinChannel.id,
welcomeJoinChannelMessage: joinChannelMessage,
welcomeLeaveChannelId: leaveChannel.id,
welcomeLeaveChannelMessage: leaveChannelMessage,
},
create: {
id: guild.id,
welcomeEnabled: status,
welcomeJoinChannelId: joinChannel.id,
welcomeJoinChannelMessage: joinChannelMessage,
welcomeLeaveChannelId: leaveChannel.id,
welcomeLeaveChannelMessage: leaveChannelMessage,
},
});
logger.silly(createGuild);
const interactionEmbedDisabled = new EmbedBuilder()
.setTitle("[:tools:] Welcome")
.setDescription(
"This module is currently disabled, please enable it to continue."
)
.setColor(successColor)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
if (!createGuild.welcomeEnabled) {
return interaction?.editReply({
embeds: [interactionEmbedDisabled],
});
}
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] Welcome")
.setDescription(
`The following configuration will be used.
[👋] **Welcome**
**Channel**: <#${createGuild.welcomeJoinChannelId}>
**Message**: ${createGuild.welcomeJoinChannelMessage}
[🚪] **Leave**
**Channel**: <#${createGuild.welcomeLeaveChannelId}>
**Message**: ${createGuild.welcomeLeaveChannelMessage}`
)
.setColor(successColor)
.setTimestamp()
.setFooter({
iconURL: footerIcon,
text: footerText,
});
await interaction?.editReply({
embeds: [interactionEmbed],
});
return;
},
};

View file

@ -0,0 +1,24 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleView from "./modules/view";
export const builder = new SlashCommandBuilder()
.setName("counters")
.setDescription("View guild counters")
.setDMPermission(false)
// Modules
.addSubcommand(moduleView.builder);
// Execute function
export const execute = async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "view":
await moduleView.execute(interaction);
break;
default:
throw new Error("No module found for that command.");
}
};

View file

@ -0,0 +1,67 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChannelType } from "discord-api-types/v10";
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("view")
.setDescription(`View a guild counter`)
.addChannelOption((option) =>
option
.setName("channel")
.setDescription(
`The channel that contains the counter you want to view`
)
.setRequired(true)
.addChannelTypes(ChannelType.GuildText)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, false);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const discordChannel = options.getChannel("channel");
if (!guild) throw new Error(`Guild not found`);
if (!discordChannel) throw new Error(`Channel not found`);
const embed = new EmbedBuilder()
.setTitle("[:1234:] Counters (View)")
.setTimestamp(new Date())
.setFooter({
text: footerText,
iconURL: footerIcon,
});
const channelCounter = await prisma.guildCounter.findUnique({
where: {
guildId_channelId: {
guildId: guild.id,
channelId: discordChannel.id,
},
},
});
if (!channelCounter) throw new Error("No counter found for channel");
await interaction.editReply({
embeds: [
embed
.setDescription(
`Viewing counter for channel ${discordChannel}: ${channelCounter.count}!`
)
.setColor(successColor),
],
});
return;
},
};

View file

@ -0,0 +1,42 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
import logger from "../../middlewares/logger";
// Modules
import moduleBalance from "./modules/balance";
import moduleGift from "./modules/gift";
import moduleTop from "./modules/top";
import moduleWork from "./modules/work";
export const builder = new SlashCommandBuilder()
.setName("credits")
.setDescription("Manage your credits.")
.setDMPermission(false)
// Modules
.addSubcommand(moduleBalance.builder)
.addSubcommand(moduleGift.builder)
.addSubcommand(moduleTop.builder)
.addSubcommand(moduleWork.builder);
// Execute function
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { options } = interaction;
switch (options.getSubcommand()) {
case "balance":
await moduleBalance.execute(interaction);
break;
case "gift":
await moduleGift.execute(interaction);
break;
case "top":
await moduleTop.execute(interaction);
break;
case "work":
await moduleWork.execute(interaction);
break;
default:
logger.silly(`Unknown subcommand ${options.getSubcommand()}`);
}
};

View file

@ -0,0 +1,95 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { CommandInteraction, EmbedBuilder } from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("balance")
.setDescription(`View a user's balance`)
.addUserOption((option) =>
option
.setName("user")
.setDescription(`The user whose balance you want to view`)
);
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, true);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild);
const { options, user, guild } = interaction;
const discordUser = options.getUser("user");
const embed = new EmbedBuilder()
.setTitle("[:dollar:] Balance")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });
if (guild === null) {
logger.silly(`Guild is null`);
return interaction.editReply({
embeds: [
embed.setDescription("Guild is not found").setColor(errorColor),
],
});
}
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: (discordUser || user).id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: (discordUser || user).id,
},
where: {
id: (discordUser || user).id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
if (!createGuildMember) throw new Error("No guild member exists.");
return interaction.editReply({
embeds: [
embed
.setDescription(
`${discordUser || user} currently has ${
createGuildMember.creditsEarned
} credits.`
)
.setColor(successColor),
],
});
},
};

View file

@ -0,0 +1,89 @@
// Dependencies
// Models
import {
ChatInputCommandInteraction,
EmbedBuilder,
SlashCommandSubcommandBuilder,
} from "discord.js";
import transferCredits from "../../../../helpers/transferCredits";
// Configurations
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
// Handlers
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("gift")
.setDescription(`Gift a user credits`)
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user you want to gift credits to.")
.setRequired(true)
)
.addIntegerOption((option) =>
option
.setName("amount")
.setDescription("The amount of credits you want to gift.")
.setRequired(true)
)
.addStringOption((option) =>
option.setName("reason").setDescription("Your reason.")
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, user, guild, client } = interaction;
const optionUser = options.getUser("user");
const optionAmount = options.getInteger("amount");
const optionReason = options.getString("reason");
const embed = new EmbedBuilder()
.setTitle("[:dollar:] Gift")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });
if (!guild) throw new Error("Guild not found");
if (!optionUser) throw new Error("No receiver found");
if (optionAmount === null) throw new Error("Amount not found");
await transferCredits(guild, user, optionUser, optionAmount);
// Get DM user object
const dmUser = client.users.cache.get(optionUser.id);
if (!dmUser) throw new Error("User not found");
// Send DM to user
await dmUser.send({
embeds: [
embed
.setDescription(
`${user.tag} has gifted you ${optionAmount} credits with reason: ${
optionReason || "unspecified"
}`
)
.setColor(successColor),
],
});
return interaction.editReply({
embeds: [
embed
.setDescription(
`Successfully gifted ${optionAmount} credits to ${optionUser} with reason: ${
optionReason || "unspecified"
}`
)
.setColor(successColor),
],
});
},
};

View file

@ -1,10 +1,10 @@
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { CommandInteraction, MessageEmbed } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import logger from "../../../../../logger";
import userSchema, { IUser } from "../../../../../models/user";
import { GuildMember } from "@prisma/client";
import { CommandInteraction, EmbedBuilder } from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
metadata: { guildOnly: true, ephemeral: false },
@ -13,11 +13,13 @@ export default {
return command.setName("top").setDescription(`View the top users`);
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild);
const { guild } = interaction;
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTitle("[:dollar:] Top")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });
@ -36,19 +38,25 @@ export default {
});
}
const usersDB = await userSchema.find({ guildId: guild.id });
// const usersDB = await userSchema.find({ guildId: guild.id });
const topTen = usersDB
const topTen = await prisma.guildMember.findMany({
where: {
guildId: guild.id,
},
orderBy: {
creditsEarned: "desc",
},
take: 10,
});
// Sort them after credits amount (ascending)
.sort((a, b) => (a.credits > b.credits ? -1 : 1))
// Return the top 10
.slice(0, 10);
logger.silly(topTen);
// Create entry object
const entry = (x: IUser, index: number) =>
`${index + 1}. <@${x.userId}> - ${x.credits} credits`;
const entry = (guildMember: GuildMember, index: number) =>
`${index + 1}. <@${guildMember.userId}> - ${
guildMember.creditsEarned
} credits`;
return interaction.editReply({
embeds: [
@ -56,8 +64,7 @@ export default {
.setDescription(
`Below are the top ten members in this guild.
${topTen.map(entry).join("\n")}
`
${topTen.map(entry).join("\n")}`
)
.setColor(successColor),
],

View file

@ -0,0 +1,108 @@
// Dependencies
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import Chance from "chance";
import { CommandInteraction, EmbedBuilder } from "discord.js";
// Models
import { command as CooldownCommand } from "../../../../handlers/cooldown";
// Configurations
import getEmbedConfig from "../../../../helpers/getEmbedData";
// Helpers
// Handlers
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command.setName("work").setDescription(`Work to earn credits`);
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, true);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
); // Destructure member
const { guild, user } = interaction;
const embed = new EmbedBuilder()
.setTitle("[:dollar:] Work")
.setTimestamp(new Date())
.setFooter({
text: footerText,
iconURL: footerIcon,
});
// Chance module
const chance = new Chance();
if (guild === null) {
return logger?.silly(`Guild is null`);
}
const createGuild = await prisma.guild.upsert({
where: {
id: guild.id,
},
update: {},
create: {
id: guild.id,
},
});
logger.silly(createGuild);
await CooldownCommand(interaction, createGuild.creditsWorkTimeout);
const creditsEarned = chance.integer({
min: 0,
max: createGuild.creditsWorkRate,
});
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: { creditsEarned: { increment: creditsEarned } },
create: {
creditsEarned,
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
return interaction.editReply({
embeds: [
embed
.setDescription(`You worked and earned ${creditsEarned} credits.`)
.setColor(successColor),
],
});
},
};

View file

@ -1,19 +1,22 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { CommandInteraction } from "discord.js";
import { ChatInputCommandInteraction } from "discord.js";
import modules from "./modules";
export const moduleData = modules;
// Modules
import moduleLookup from "./modules/lookup";
export const builder = new SlashCommandBuilder()
.setName("dns")
.setDescription("DNS commands.")
.addSubcommand(modules.lookup.builder);
// Modules
.addSubcommand(moduleLookup.builder);
export const execute = async (interaction: CommandInteraction) => {
// Execute the command
export const execute = async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "lookup":
return modules.lookup.execute(interaction);
await moduleLookup.execute(interaction);
break;
default:
throw new Error(
`Unknown subcommand: ${interaction.options.getSubcommand()}`

View file

@ -1,13 +1,10 @@
import axios from "axios";
import { CommandInteraction, MessageEmbed } from "discord.js";
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import axios from "axios";
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
export default {
metadata: { guildOnly: false, ephemeral: false },
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("lookup")
@ -21,7 +18,9 @@ export default {
.setRequired(true)
);
},
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, false);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild);
const embedTitle = "[:hammer:] Utility (Lookup)";
@ -35,7 +34,7 @@ export default {
if (response.data.status !== "success") {
await interaction.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle(embedTitle)
.setFooter({
text: footerText,
@ -54,7 +53,7 @@ export default {
await interaction.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle(embedTitle)
.setFooter({
text: footerText,

23
src/commands/fun/index.ts Normal file
View file

@ -0,0 +1,23 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
import logger from "../../middlewares/logger";
// Modules
import moduleMeme from "./modules/meme";
export const builder = new SlashCommandBuilder()
.setName("fun")
.setDescription("Fun commands.")
.addSubcommand(moduleMeme.builder);
// Execute function
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { options } = interaction;
if (options.getSubcommand() === "meme") {
await moduleMeme.execute(interaction);
} else {
logger.silly(`Unknown subcommand ${options.getSubcommand()}`);
}
};

View file

@ -1,17 +1,20 @@
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import axios from "axios";
import { CommandInteraction, MessageEmbed } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import axios from "axios";
import { CommandInteraction, EmbedBuilder } from "discord.js";
import { command as CooldownCommand } from "../../../../handlers/cooldown";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
export default {
metadata: { guildOnly: false, ephemeral: false, cooldown: 15 },
builder: (command: SlashCommandSubcommandBuilder) => {
return command.setName("meme").setDescription("Get a meme from r/memes)");
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
await CooldownCommand(interaction, 15);
const { guild } = interaction;
const embedConfig = await getEmbedConfig(guild);
@ -22,7 +25,7 @@ export default {
const response = res.data[0].data.children;
const content = response[0].data;
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setAuthor({
name: content.title,
iconURL:
@ -50,7 +53,8 @@ export default {
})
.setColor(embedConfig.successColor);
return interaction.editReply({ embeds: [embed] });
await interaction.editReply({ embeds: [embed] });
return;
})
.catch((error) => {
throw new Error(error.message);

View file

@ -0,0 +1,36 @@
//Dependencies
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleCounters from "./modules/counters";
import moduleCredits from "./modules/credits";
// Function
export const builder = new SlashCommandBuilder()
.setName("manage")
.setDescription("Manage the bot.")
.setDMPermission(false)
// Modules
.addSubcommandGroup(moduleCounters.builder)
.addSubcommandGroup(moduleCredits.builder);
export const execute = async (interaction: ChatInputCommandInteraction) => {
// Destructure
const { options } = interaction;
switch (options.getSubcommandGroup()) {
case "credits": {
await moduleCredits.execute(interaction);
break;
}
case "counters": {
await moduleCounters.execute(interaction);
break;
}
default: {
throw new Error("Could not find an module for the command.");
}
}
};

View file

@ -0,0 +1,34 @@
// Dependencies
import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleAdd from "./modules/add";
import moduleRemove from "./modules/remove";
export default {
builder: (group: SlashCommandSubcommandGroupBuilder) => {
return group
.setName("counters")
.setDescription("Manage guild counters.")
.addSubcommand(moduleAdd.builder)
.addSubcommand(moduleRemove.builder);
},
execute: async (interaction: ChatInputCommandInteraction) => {
const { options } = interaction;
switch (options.getSubcommand()) {
case "add": {
await moduleAdd.execute(interaction);
break;
}
case "remove": {
await moduleRemove.execute(interaction);
break;
}
default: {
throw new Error("Could not found a module for that command.");
}
}
},
};

View file

@ -0,0 +1,113 @@
// Dependencies
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChannelType } from "discord-api-types/v10";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
// Configurations
import prisma from "../../../../../../handlers/database";
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
import logger from "../../../../../../middlewares/logger";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("add")
.setDescription("Add a counter to your guild.")
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to send the counter to.")
.setRequired(true)
.addChannelTypes(ChannelType.GuildText)
)
.addStringOption((option) =>
option
.setName("word")
.setDescription("The word to use for the counter.")
.setRequired(true)
)
.addNumberOption((option) =>
option
.setName("start")
.setDescription("The starting value of the counter.")
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const discordChannel = options?.getChannel("channel");
const triggerWord = options?.getString("word");
const startValue = options?.getNumber("start");
if (!guild) throw new Error("We could not find a guild");
if (!discordChannel) throw new Error("We could not find a channel");
if (!triggerWord) throw new Error("We could not find a word");
const channelCounter = await prisma.guildCounter.findUnique({
where: {
guildId_channelId: {
guildId: guild.id,
channelId: discordChannel.id,
},
},
});
if (channelCounter)
throw new Error("A counter already exists for this channel.");
const createGuildCounter = await prisma.guildCounter.upsert({
where: {
guildId_channelId: {
guildId: guild.id,
channelId: discordChannel.id,
},
},
update: {},
create: {
channelId: discordChannel.id,
triggerWord,
count: startValue || 0,
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildCounter);
if (createGuildCounter) {
const embed = new EmbedBuilder()
.setTitle("[:toolbox:] Counters - Add")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction?.editReply({
embeds: [
embed
.setDescription(":white_check_mark: Counter created successfully.")
.setColor(successColor),
],
});
}
},
};

View file

@ -0,0 +1,82 @@
// Dependencies
// Models
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChannelType } from "discord-api-types/v10";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
// Configurations
import prisma from "../../../../../../handlers/database";
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("remove")
.setDescription(`Delete a counter from your guild.`)
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to delete the counter from.")
.setRequired(true)
.addChannelTypes(ChannelType.GuildText)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { options, guild } = interaction;
const discordChannel = options?.getChannel("channel");
if (!guild) throw new Error("We could not find a guild");
if (!discordChannel) throw new Error("We could not find a channel");
const embed = new EmbedBuilder()
.setTitle("[:toolbox:] Counters - Remove")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });
const channelCounter = await prisma.guildCounter.findUnique({
where: {
guildId_channelId: {
guildId: guild.id,
channelId: discordChannel.id,
},
},
});
if (!channelCounter)
throw new Error(
"There is no counter sin this channel, please add one first."
);
const deleteGuildCounter = await prisma.guildCounter.deleteMany({
where: {
guildId: guild.id,
channelId: discordChannel.id,
},
});
if (!deleteGuildCounter)
throw new Error("We could not find a counter for this guild");
await interaction?.editReply({
embeds: [
embed
.setDescription(":white_check_mark: Counter deleted successfully.")
.setColor(successColor),
],
});
},
};

View file

@ -0,0 +1,43 @@
import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleGive from "./modules/give";
import moduleGiveaway from "./modules/giveaway";
import moduleSet from "./modules/set";
import moduleTake from "./modules/take";
import moduleTransfer from "./modules/transfer";
export default {
builder: (group: SlashCommandSubcommandGroupBuilder) => {
return group
.setName("credits")
.setDescription("Manage the credits of a user.")
.addSubcommand(moduleGive.builder)
.addSubcommand(moduleSet.builder)
.addSubcommand(moduleTake.builder)
.addSubcommand(moduleTransfer.builder)
.addSubcommand(moduleGiveaway.builder);
},
execute: async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "give":
await moduleGive.execute(interaction);
break;
case "set":
await moduleSet.execute(interaction);
break;
case "take":
await moduleTake.execute(interaction);
break;
case "transfer":
await moduleTransfer.execute(interaction);
break;
case "giveaway":
await moduleGiveaway.execute(interaction);
break;
default:
throw new Error("No module found for that specific command");
}
},
};

View file

@ -0,0 +1,114 @@
// Dependencies
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import logger from "../../../../../../middlewares/logger";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Helpers../../../../../../../helpers/userData
import pluralize from "../../../../../../helpers/pluralize";
// Models
// Handlers
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("give")
.setDescription("Give credits to a user.")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to give credits to.")
.setRequired(true)
)
.addIntegerOption((option) =>
option
.setName("amount")
.setDescription(`The amount of credits to give.`)
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
); // Destructure
const { guild, options } = interaction;
const discordReceiver = options?.getUser("user");
const creditAmount = options?.getInteger("amount");
// If amount option is null
if (creditAmount === null)
throw new Error("You need to provide a credit amount.");
// If amount is zero or below
if (creditAmount <= 0)
throw new Error("You must provide a credit amount greater than zero");
if (discordReceiver === null)
throw new Error("We could not get the receiving user from Discord");
if (guild === null)
throw new Error("We could not get the current guild from discord.");
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordReceiver.id,
guildId: guild.id,
},
},
update: { creditsEarned: { increment: creditAmount } },
create: {
creditsEarned: creditAmount,
user: {
connectOrCreate: {
create: {
id: discordReceiver.id,
},
where: {
id: discordReceiver.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
// Save toUser
await interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Give)")
.setDescription(
`Successfully gave ${pluralize(creditAmount, "credit")}`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
return;
},
};

View file

@ -1,30 +1,25 @@
// Dependencies
import {
CommandInteraction,
MessageActionRow,
MessageButton,
MessageEmbed,
Permissions,
} from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { v4 as uuidv4 } from "uuid";
import axios from "axios";
import apiSchema from "../../../../../../../models/api";
import encryption from "../../../../../../../handlers/encryption";
import { ButtonStyle, ChannelType } from "discord-api-types/v10";
import {
ActionRowBuilder,
ButtonBuilder,
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import { v4 as uuidv4 } from "uuid";
import encryption from "../../../../../../helpers/encryption";
// Configurations
import getEmbedConfig from "../../../../../../../helpers/getEmbedConfig";
import { ChannelType } from "discord-api-types/v10";
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
import logger from "../../../../../../middlewares/logger";
// Function
export default {
metadata: {
guildOnly: true,
ephemeral: true,
permissions: [Permissions.FLAGS.MANAGE_GUILD],
},
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("giveaway")
@ -49,11 +44,15 @@ export default {
.addChannelTypes(ChannelType.GuildText)
);
},
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
); // Destructure
const { guild, options } = interaction;
const { guild, user, options } = interaction;
const uses = options?.getInteger("uses");
const creditAmount = options?.getInteger("credit");
@ -62,25 +61,75 @@ export default {
if (!uses) throw new Error("Amount of uses is required.");
if (!creditAmount) throw new Error("Amount of credits is required.");
if (!channel) throw new Error("Channel is required.");
if (!guild) throw new Error("Guild is required.");
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTitle("[:toolbox:] Giveaway")
.setFooter({ text: footerText, iconURL: footerIcon });
const code = uuidv4();
const apiCredentials = await apiSchema?.findOne({
guildId: guild?.id,
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
if (!apiCredentials) return;
logger.silly(createGuildMember);
const url = encryption.decrypt(apiCredentials?.url);
if (
!createGuildMember.guild.apiCpggUrlIv ||
!createGuildMember.guild.apiCpggUrlContent
)
throw new Error("No API url available");
if (
!createGuildMember.guild.apiCpggTokenIv ||
!createGuildMember.guild.apiCpggTokenContent
)
throw new Error("No API token available");
const url = encryption.decrypt({
iv: createGuildMember.guild.apiCpggUrlIv,
content: createGuildMember.guild.apiCpggUrlContent,
});
const api = axios?.create({
baseURL: `${url}/api/`,
headers: {
Authorization: `Bearer ${encryption.decrypt(apiCredentials.token)}`,
Authorization: `Bearer ${encryption.decrypt({
iv: createGuildMember.guild.apiCpggTokenIv,
content: createGuildMember.guild.apiCpggTokenContent,
})}`,
},
});
@ -102,10 +151,10 @@ export default {
],
});
const buttons = new MessageActionRow().addComponents(
new MessageButton()
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setLabel("Redeem it here")
.setStyle("LINK")
.setStyle(ButtonStyle.Link)
.setEmoji("🏦")
.setURL(`${shopUrl}?voucher=${code}`)
);
@ -114,11 +163,11 @@ export default {
if (!discordChannel) return;
if (discordChannel.type !== "GUILD_TEXT") return;
if (discordChannel.type !== ChannelType.GuildText) return;
discordChannel.send({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:parachute:] Credits!")
.addFields([
{

View file

@ -1,26 +1,22 @@
// Dependencies
import { CommandInteraction, MessageEmbed, Permissions } from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../../helpers/getEmbedConfig";
// Handlers
import logger from "../../../../../../../logger";
// Helpers
// Models
import fetchUser from "../../../../../../../helpers/fetchUser";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Handlers
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import logger from "../../../../../../middlewares/logger";
// Function
export default {
metadata: {
guildOnly: true,
ephemeral: true,
permissions: [Permissions.FLAGS.MANAGE_GUILD],
},
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("set")
@ -38,7 +34,11 @@ export default {
.setRequired(true)
);
},
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild);
const { options, guild } = interaction;
@ -52,7 +52,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide an amount.`)
.setTimestamp(new Date())
@ -67,7 +67,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide a user.`)
.setTimestamp(new Date())
@ -81,7 +81,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide a guild.`)
.setTimestamp(new Date())
@ -91,60 +91,52 @@ export default {
});
}
// toUser Information
const toUser = await fetchUser(discordUser, guild);
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordUser.id,
guildId: guild.id,
},
},
update: { creditsEarned: creditAmount },
create: {
creditsEarned: creditAmount,
user: {
connectOrCreate: {
create: {
id: discordUser.id,
},
where: {
id: discordUser.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
// If toUser does not exist
if (toUser === null) {
logger?.silly(`User does not exist`);
logger.silly(createGuildMember);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`The user you provided does not exist.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// If toUser.credits does not exist
if (toUser?.credits === null) {
logger?.silly(`User does not have any credits`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`The user you provided does not have any credits.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// Set toUser with amount
toUser.credits = creditAmount;
// Save toUser
await toUser?.save()?.then(async () => {
logger?.silly(`Saved user`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(
`Set **${discordUser}**'s credits to **${creditAmount}**.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(
`Set **${discordUser}**'s credits to **${creditAmount}**.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
},
};

View file

@ -1,27 +1,23 @@
// Dependencies
import { CommandInteraction, MessageEmbed, Permissions } from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../../helpers/getEmbedConfig";
// Handlers
import logger from "../../../../../../../logger";
// Helpers
import pluralize from "../../../../../../../helpers/pluralize";
// Models
import fetchUser from "../../../../../../../helpers/fetchUser";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Helpers../../../../../../../helpers/userData
import pluralize from "../../../../../../helpers/pluralize";
// Handlers
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import logger from "../../../../../../middlewares/logger";
// Function
export default {
metadata: {
guildOnly: true,
ephemeral: true,
permissions: [Permissions.FLAGS.MANAGE_GUILD],
},
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("take")
@ -39,13 +35,17 @@ export default {
.setRequired(true)
);
},
execute: async (interaction: CommandInteraction) => {
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild); // Destructure
const { guild, options } = interaction;
// User option
const optionUser = options?.getUser("user");
const discordReceiver = options?.getUser("user");
// Amount option
const optionAmount = options?.getInteger("amount");
@ -56,7 +56,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide an amount.`)
.setTimestamp(new Date())
@ -72,7 +72,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide an amount greater than zero.`)
.setTimestamp(new Date())
@ -82,12 +82,12 @@ export default {
});
}
if (optionUser === null) {
if (discordReceiver === null) {
logger?.silly(`Discord receiver is null`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide a user.`)
.setTimestamp(new Date())
@ -101,7 +101,7 @@ export default {
return interaction?.editReply({
embeds: [
new MessageEmbed()
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must be in a guild.`)
.setTimestamp(new Date())
@ -111,60 +111,52 @@ export default {
});
}
// toUser Information
const toUser = await fetchUser(optionUser, guild);
// If toUser does not exist
if (toUser === null) {
logger?.silly(`ToUser is null`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`The user you provided does not exist.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// If toUser.credits does not exist
if (toUser?.credits === null) {
logger?.silly(`ToUser.credits is null`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`The user you provided does not have credits.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// Withdraw amount from toUser
toUser.credits -= optionAmount;
// Save toUser
await toUser?.save()?.then(async () => {
logger?.silly(`Saved toUser`);
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(
`Took ${pluralize(optionAmount, "credit")} from ${optionUser}.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordReceiver.id,
guildId: guild.id,
},
},
update: { creditsEarned: { decrement: optionAmount } },
create: {
creditsEarned: -optionAmount,
user: {
connectOrCreate: {
create: {
id: discordReceiver.id,
},
where: {
id: discordReceiver.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
await interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(
`Took ${pluralize(optionAmount, "credit")} from ${discordReceiver}.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
return;
},
};

View file

@ -0,0 +1,81 @@
// Dependencies
// Models
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import transferCredits from "../../../../../../helpers/transferCredits";
// Configurations
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("transfer")
.setDescription("Transfer credits from one user to another.")
.addUserOption((option) =>
option
.setName("from")
.setDescription("The user to transfer credits from.")
.setRequired(true)
)
.addUserOption((option) =>
option
.setName("to")
.setDescription("The user to transfer credits to.")
.setRequired(true)
)
.addIntegerOption((option) =>
option
.setName("amount")
.setDescription(`The amount of credits to transfer.`)
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
); // Destructure member
const { guild, options } = interaction;
// Get options
const optionFromUser = options?.getUser("from");
const optionToUser = options?.getUser("to");
const optionAmount = options?.getInteger("amount");
if (optionAmount === null) throw new Error("Amount is not specified");
if (optionAmount <= 0)
throw new Error("You need to set amount above zero to transfer.");
if (!guild) throw new Error(`We could not find this guild.`);
if (!optionFromUser)
throw new Error("You must provide a user to transfer from.");
if (!optionToUser)
throw new Error("You must provide a user to transfer to.");
await transferCredits(guild, optionFromUser, optionToUser, optionAmount);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Transfer)")
.setDescription(`Transferred ${optionAmount} credits.`)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
},
};

View file

@ -0,0 +1,27 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import modulePrune from "./modules/prune";
export const builder = new SlashCommandBuilder()
.setName("moderation")
.setDescription("Moderation.")
.setDMPermission(false)
.addSubcommand(modulePrune.builder);
// Execute the command
export const execute = async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "prune": {
await modulePrune.execute(interaction);
break;
}
default: {
throw new Error(
`Unknown subcommand: ${interaction.options.getSubcommand()}`
);
}
}
};

View file

@ -1,22 +1,18 @@
// Dependencies
import {
CommandInteraction,
Permissions,
} from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChannelType,
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import deferReply from "../../../../handlers/deferReply";
import checkPermission from "../../../../helpers/checkPermission";
// Configurations
import getEmbedConfig from "../../../../helpers/getEmbedData";
// Function
export default {
metadata: {
guildOnly: true,
ephemeral: false,
permissions: [Permissions.FLAGS.MANAGE_MESSAGES],
},
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("prune")
@ -31,33 +27,34 @@ export default {
option.setName("bots").setDescription("Include bots.")
);
},
execute: async (interaction: CommandInteraction) => {
const { successColor, footerText, footerIcon } = await getEmbedConfig(
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, false);
checkPermission(interaction, PermissionsBitField.Flags.ManageMessages);
const { errorColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const count = interaction.options.getInteger("count");
if (count == null) return;
if (count === null) return;
const bots = interaction.options.getBoolean("bots");
if (count < 1 || count > 100) {
const interactionEmbed = {
title: "[:police_car:] Prune",
description: `You can only prune between 1 and 100 messages.`,
color: successColor,
timestamp: new Date(),
footer: {
iconURL: footerIcon,
text: footerText,
},
};
const interactionEmbed = new EmbedBuilder()
.setTitle("[:police_car:] Prune")
.setDescription(`You can only prune between 1 and 100 messages.`)
.setTimestamp()
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
});
return;
}
if (interaction?.channel?.type !== "GUILD_TEXT") return;
if (interaction?.channel?.type !== ChannelType.GuildText) return;
await interaction.channel.messages.fetch().then(async (messages) => {
const messagesToDelete = (
bots
@ -68,20 +65,17 @@ export default {
)
).first(count);
if (interaction?.channel?.type !== "GUILD_TEXT") return;
if (interaction?.channel?.type !== ChannelType.GuildText) return;
await interaction.channel
.bulkDelete(messagesToDelete, true)
.then(async () => {
const interactionEmbed = {
title: "[:police_car:] Prune",
description: `Successfully pruned \`${count}\` messages.`,
color: successColor,
timestamp: new Date(),
footer: {
iconURL: footerIcon,
text: footerText,
},
};
const interactionEmbed = new EmbedBuilder()
.setTitle("[:police_car:] Prune")
.setDescription(`Successfully pruned \`${count}\` messages.`)
.setTimestamp()
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
});

View file

@ -0,0 +1,29 @@
// Dependencies
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleGive from "./modules/give";
import moduleView from "./modules/view";
// Function
export const builder = new SlashCommandBuilder()
.setName("reputation")
.setDescription("Manage reputation.")
.setDMPermission(false)
// Modules
.addSubcommand(moduleGive.builder)
.addSubcommand(moduleView.builder);
// Execute function
export const execute = async (interaction: ChatInputCommandInteraction) => {
if (interaction.options.getSubcommand() === "give") {
await moduleGive.execute(interaction);
return;
}
if (interaction.options.getSubcommand() === "view") {
await moduleView.execute(interaction);
return;
}
};

View file

@ -1,5 +1,6 @@
import { User } from "discord.js";
export default async (to: User | null, from: User | null) => {
export default (to: User | null, from: User | null) => {
if (from?.id === to?.id) {
throw new Error("You cannot give reputation to yourself.");
}

View file

@ -0,0 +1,117 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
import { command as CooldownCommand } from "../../../../handlers/cooldown";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
import noSelfReputation from "./components/noSelfReputation";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("give")
.setDescription("Give reputation to a user")
.addUserOption((option) =>
option
.setName("target")
.setDescription("The user you want to repute.")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("type")
.setDescription("What type of reputation you want to repute")
.setRequired(true)
.addChoices(
{ name: "Positive", value: "positive" },
{
name: "Negative",
value: "negative",
}
)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { options, user, guild } = interaction;
const { successColor, footerText, footerIcon } = await getEmbedConfig(
guild
);
const optionTarget = options?.getUser("target");
const optionType = options?.getString("type");
if (!guild) throw new Error("Guild is undefined");
if (!optionTarget) throw new Error("Target is not defined");
// Pre-checks
noSelfReputation(optionTarget, user);
// Check if user is on cooldown otherwise create one
await CooldownCommand(
interaction,
parseInt(process.env.REPUTATION_TIMEOUT)
);
switch (optionType) {
case "positive": {
const createUser = await prisma.user.upsert({
where: {
id: optionTarget.id,
},
update: {
reputationsEarned: {
increment: 1,
},
},
create: {
id: optionTarget.id,
reputationsEarned: 1,
},
});
logger.silly(createUser);
break;
}
case "negative": {
const createUser = await prisma.user.upsert({
where: {
id: optionTarget.id,
},
update: {
reputationsEarned: {
decrement: 1,
},
},
create: {
id: optionTarget.id,
reputationsEarned: -1,
},
});
logger.silly(createUser);
break;
}
default: {
throw new Error("Invalid reputation type");
}
}
const interactionEmbed = new EmbedBuilder()
.setTitle("[:loudspeaker:] Give")
.setDescription(
`You have given a ${optionType} repute to ${optionTarget}`
)
.setTimestamp()
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
});
},
};

View file

@ -0,0 +1,85 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("view")
.setDescription("View a user's reputation value")
.addUserOption((option) =>
option
.setName("target")
.setDescription("The user you want to check.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { options, guild } = interaction;
const { successColor, footerText, footerIcon } = await getEmbedConfig(
guild
);
const optionTarget = options?.getUser("target");
if (!guild) throw new Error("Guild is undefined");
if (!optionTarget) throw new Error("Target is not defined");
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: optionTarget.id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: optionTarget.id,
},
where: {
id: optionTarget.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:loudspeaker:] View")
.setDescription(
`${optionTarget} has ${createGuildMember.user.reputationsEarned}.`
)
.setTimestamp()
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
});
},
};

View file

@ -0,0 +1,42 @@
// Dependencies
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleCpgg from "./modules/cpgg";
import moduleRoles from "./modules/roles";
// Function
export const builder = new SlashCommandBuilder()
.setName("shop")
.setDescription("Shop for credits and custom roles.")
.setDMPermission(false)
// Modules
.addSubcommand(moduleCpgg.builder)
.addSubcommandGroup(moduleRoles.builder);
// Execute the command
export const execute = async (interaction: ChatInputCommandInteraction) => {
const { options } = interaction;
switch (options.getSubcommand()) {
case "cpgg": {
await moduleCpgg.execute(interaction);
break;
}
default: {
throw new Error("Could not find module for that command.");
}
}
switch (options.getSubcommandGroup()) {
case "roles": {
await moduleRoles.execute(interaction);
break;
}
default: {
throw new Error("Could not find module for that command.");
}
}
};

View file

@ -0,0 +1,195 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import axios from "axios";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ChatInputCommandInteraction,
EmbedBuilder,
Message,
} from "discord.js";
import { v4 as uuidv4 } from "uuid";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import encryption from "../../../../helpers/encryption";
import getEmbedData from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("cpgg")
.setDescription("Buy cpgg power.")
.addIntegerOption((option) =>
option
.setName("amount")
.setDescription("How much credits you want to withdraw.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedData(interaction.guild);
const { options, guild, user, client } = interaction;
const optionAmount = options?.getInteger("amount");
if (optionAmount === null) {
logger?.silly(`Amount is null.`);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:dollar:] Gift")
.setDescription("We could not read your requested amount.")
.setTimestamp()
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon });
return interaction?.editReply({
embeds: [interactionEmbed],
});
}
if (!guild) throw new Error("Guild not found");
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
const dmUser = client?.users?.cache?.get(user?.id);
if ((optionAmount || createGuildMember.creditsEarned) < 100)
throw new Error("You can't withdraw to CPGG below 100 credits.");
if ((optionAmount || createGuildMember.creditsEarned) > 1000000)
throw new Error("Amount or user credits is above 1.000.000.");
if (createGuildMember.creditsEarned < optionAmount)
throw new Error("You can't withdraw more than you have on your account.");
if (
!createGuildMember.guild.apiCpggUrlIv ||
!createGuildMember.guild.apiCpggUrlContent
)
throw new Error("No API url available");
if (
!createGuildMember.guild.apiCpggTokenIv ||
!createGuildMember.guild.apiCpggTokenContent
)
throw new Error("No API token available");
const code = uuidv4();
const url = encryption.decrypt({
iv: createGuildMember.guild.apiCpggUrlIv,
content: createGuildMember.guild.apiCpggUrlContent,
});
const api = axios?.create({
baseURL: `${url}/api/`,
headers: {
Authorization: `Bearer ${encryption.decrypt({
iv: createGuildMember.guild.apiCpggTokenIv,
content: createGuildMember.guild.apiCpggTokenContent,
})}`,
},
});
const shopUrl = `${url}/store`;
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setLabel("Redeem it here")
.setStyle(ButtonStyle.Link)
.setEmoji("🏦")
.setURL(`${shopUrl}?voucher=${code}`)
);
await api
?.post("vouchers", {
uses: 1,
code,
credits: optionAmount || createGuildMember.creditsEarned,
memo: `${interaction?.createdTimestamp} - ${interaction?.user?.id}`,
})
?.then(async () => {
logger?.silly(`Successfully created voucher.`);
createGuildMember.creditsEarned -=
optionAmount || createGuildMember.creditsEarned;
const updateGuildMember = await prisma.guildMember.update({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
data: {
creditsEarned: {
decrement: optionAmount || createGuildMember.creditsEarned,
},
},
});
logger.silly(updateGuildMember);
if (!interaction.guild) throw new Error("Guild is undefined");
const dmEmbed = new EmbedBuilder()
.setTitle("[:shopping_cart:] CPGG")
.setDescription(
`This voucher comes from **${interaction.guild.name}**.`
)
.setTimestamp()
.addFields({
name: "💶 Credits",
value: `${optionAmount || createGuildMember.creditsEarned}`,
inline: true,
})
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await dmUser
?.send({
embeds: [dmEmbed],
components: [buttons],
})
.then(async (msg: Message) => {
const interactionEmbed = new EmbedBuilder()
.setTitle("[:shopping_cart:] CPGG")
.setDescription(`I have sent you the code in [DM](${msg.url})!`)
.setTimestamp()
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction?.editReply({
embeds: [interactionEmbed],
});
return;
});
});
},
};

View file

@ -0,0 +1,45 @@
// Dependencies
import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Handlers
// Modules
import moduleBuy from "./modules/buy";
import moduleCancel from "./modules/cancel";
import prisma from "../../../../handlers/database";
export default {
builder: (group: SlashCommandSubcommandGroupBuilder) => {
return (
group
.setName("roles")
.setDescription("Shop for custom roles.")
// Modules
.addSubcommand(moduleBuy.builder)
.addSubcommand(moduleCancel.builder)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
if (!interaction.guild) return;
const { options, guild } = interaction;
const getGuild = await prisma.guild.findUnique({
where: { id: guild.id },
});
if (!getGuild) throw new Error("Guild not found");
if (!getGuild.shopRolesEnabled)
throw new Error("This server has disabled shop roles.");
if (options?.getSubcommand() === "buy") {
await moduleBuy.execute(interaction);
}
if (options?.getSubcommand() === "cancel") {
await moduleCancel.execute(interaction);
}
},
};

View file

@ -0,0 +1,178 @@
// Dependencies
// Helpers
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
ColorResolvable,
EmbedBuilder,
GuildMemberRoleManager,
} from "discord.js";
import deferReply from "../../../../../../handlers/deferReply";
import getEmbedData from "../../../../../../helpers/getEmbedData";
import logger from "../../../../../../middlewares/logger";
// Configurations
// import fetchUser from "../../../../../../helpers/userData";
// Models
import prisma from "../../../../../../handlers/database";
import pluralize from "../../../../../../helpers/pluralize";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("buy")
.setDescription("Buy a custom role.")
.addStringOption((option) =>
option
.setName("name")
.setDescription("Name of the role you wish to buy.")
.setRequired(true)
)
.addStringOption((option) =>
option
.setName("color")
.setDescription("Color of the role you wish to buy.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { successColor, footerText, footerIcon } = await getEmbedData(
interaction.guild
);
const { options, guild, user, member } = interaction;
const optionName = options?.getString("name");
const optionColor = options?.getString("color");
// If amount is null
if (optionName === null)
throw new Error("We could not read your requested name");
await guild?.roles
.create({
name: optionName,
color: optionColor as ColorResolvable,
reason: `${user?.id} bought from shop`,
})
.then(async (role) => {
const userId = "SNOWFLKAE";
const guildId = "SNOWFLAKE";
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId,
guildId,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: userId,
},
where: {
id: userId,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guildId,
},
where: {
id: guildId,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
// Get guild object
const pricePerHour = createGuildMember.guild.shopRolesPricePerHour;
const updateGuildMember = await prisma.guildMember.update({
where: {
userId_guildId: {
userId,
guildId,
},
},
data: {
creditsEarned: { decrement: pricePerHour },
},
});
logger.silly(updateGuildMember);
const createShopRole = await prisma.guildShopRoles.upsert({
where: {
guildId_userId_roleId: {
guildId: guild.id,
userId: user.id,
roleId: role.id,
},
},
update: {},
create: {
roleId: role.id,
lastPayed: new Date(),
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createShopRole);
await (member?.roles as GuildMemberRoleManager)?.add(role?.id);
logger?.silly(`Role ${role?.name} was bought by ${user?.tag}`);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:shopping_cart:] Buy")
.setDescription(
`You bought **${optionName}** for **${pluralize(
pricePerHour,
"credit"
)}**.`
)
.setTimestamp()
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
return interaction?.editReply({
embeds: [interactionEmbed],
});
})
.catch(() => {
throw new Error("Failed creating role.");
});
},
};

View file

@ -0,0 +1,127 @@
// Dependencies
// Helpers
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
GuildMemberRoleManager,
} from "discord.js";
// Configurations
// Models
import deferReply from "../../../../../../handlers/deferReply";
import logger from "../../../../../../middlewares/logger";
// Configurations
// Models
import prisma from "../../../../../../handlers/database";
import getEmbedData from "../../../../../../helpers/getEmbedData";
import pluralize from "../../../../../../helpers/pluralize";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("cancel")
.setDescription("Cancel a purchase.")
.addRoleOption((option) =>
option
.setName("role")
.setDescription("Role you wish to cancel.")
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { successColor, footerText, footerIcon } = await getEmbedData(
interaction.guild
);
const { options, guild, user, member } = interaction;
const optionRole = options.getRole("role");
if (optionRole === null)
throw new Error("We could not read your requested role.");
if (!guild) throw new Error("No guild specified");
if (!user) throw new Error("No user specified");
const roleExist = await prisma.guildShopRoles.findUnique({
where: {
guildId_userId_roleId: {
guildId: guild.id,
userId: user.id,
roleId: optionRole.id,
},
},
});
if (roleExist === null) return;
await (member?.roles as GuildMemberRoleManager)?.remove(optionRole?.id);
await guild?.roles
.delete(optionRole?.id, `${user?.id} canceled from shop`)
.then(async () => {
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
if (!createGuildMember) throw new Error("Guild member not created");
const deleteShopRole = await prisma.guildShopRoles.delete({
where: {
guildId_userId_roleId: {
guildId: guild?.id,
userId: user?.id,
roleId: optionRole?.id,
},
},
});
logger.silly(deleteShopRole);
const interactionEmbed = new EmbedBuilder()
.setTitle("[:shopping_cart:] Cancel")
.setDescription(`You have canceled ${optionRole.name}.`)
.setTimestamp()
.setColor(successColor)
.addFields({
name: "Your balance",
value: `${pluralize(createGuildMember.creditsEarned, "credit")}`,
})
.setFooter({ text: footerText, iconURL: footerIcon });
return interaction?.editReply({
embeds: [interactionEmbed],
});
});
},
};

View file

@ -0,0 +1,40 @@
import { SlashCommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js";
// Modules
import moduleAbout from "./modules/about";
import moduleAvatar from "./modules/avatar";
import modulePing from "./modules/ping";
import moduleStats from "./modules/stats";
export const builder = new SlashCommandBuilder()
.setName("utility")
.setDescription("Common utility.")
// Modules
.addSubcommand(moduleAbout.builder)
.addSubcommand(moduleStats.builder)
.addSubcommand(moduleAvatar.builder)
.addSubcommand(modulePing.builder);
// Execute the command
export const execute = async (interaction: ChatInputCommandInteraction) => {
switch (interaction.options.getSubcommand()) {
case "about":
await moduleAbout.execute(interaction);
break;
case "stats":
await moduleStats.execute(interaction);
break;
case "avatar":
await moduleAvatar.execute(interaction);
break;
case "ping":
await modulePing.execute(interaction);
break;
default:
throw new Error(
`Unknown subcommand: ${interaction.options.getSubcommand()}`
);
}
};

View file

@ -0,0 +1,75 @@
// Dependencies
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
CommandInteraction,
EmbedBuilder,
} from "discord.js";
import deferReply from "../../../../handlers/deferReply";
// Configurations
import getEmbedConfig from "../../../../helpers/getEmbedData";
// Function
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command.setName("about").setDescription("About this bot!)");
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setLabel("Source Code")
.setStyle(ButtonStyle.Link)
.setEmoji("📄")
.setURL("https://github.com/ZynerOrg/xyter"),
new ButtonBuilder()
.setLabel("Documentation")
.setStyle(ButtonStyle.Link)
.setEmoji("📚")
.setURL("https://xyter.zyner.org"),
new ButtonBuilder()
.setLabel("Website")
.setStyle(ButtonStyle.Link)
.setEmoji("🌐")
.setURL("https://zyner.org"),
new ButtonBuilder()
.setLabel("Get Help")
.setStyle(ButtonStyle.Link)
.setEmoji("💬")
.setURL("https://discord.zyner.org"),
new ButtonBuilder()
.setLabel(`Hosted by ${process.env.BOT_HOSTER_NAME}`)
.setStyle(ButtonStyle.Link)
.setEmoji("⚒️")
.setURL(`${process.env.BOT_HOSTER_URL}`)
);
const interactionEmbed = new EmbedBuilder()
.setColor(successColor)
.setTitle("[:tools:] About")
.setDescription(
`
**Xyter**'s goal is to provide a __privacy-friendly__ discord bot.
We created **Xyter** to **replace the mess** of having a dozen or so bots in __your__ community.
On top of this, you can also see our **source code** for **security** and **privacy** issues.
As well as making your own **fork** of the bot, you can also get **help** from our community.
Developed with by **Zyner**, a non-profit project by teens.
`
)
.setTimestamp()
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
components: [buttons],
});
},
};

View file

@ -1,11 +1,9 @@
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { CommandInteraction, MessageEmbed } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { CommandInteraction, EmbedBuilder } from "discord.js";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
export default {
metadata: { guildOnly: false, ephemeral: false },
builder: (command: SlashCommandSubcommandBuilder) => {
return command
.setName("avatar")
@ -17,6 +15,8 @@ export default {
);
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
@ -24,7 +24,7 @@ export default {
const targetUser = userOption || interaction.user;
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTitle("[:tools:] Avatar")
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon });

View file

@ -1,26 +1,25 @@
// Dependencies
import { CommandInteraction } from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { CommandInteraction, EmbedBuilder } from "discord.js";
// Configurations
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
// Function
export default {
metadata: { guildOnly: false, ephemeral: false },
builder: (command: SlashCommandSubcommandBuilder) => {
return command.setName("ping").setDescription("Ping this bot");
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const interactionEmbed = {
title: "[:tools:] Ping",
fields: [
const interactionEmbed = new EmbedBuilder()
.setTitle("[:tools:] Ping")
.addFields(
{
name: "📦 Deliver Latency",
value: `${Math.abs(Date.now() - interaction.createdTimestamp)} ms`,
@ -30,15 +29,12 @@ export default {
name: "🤖 API Latency",
value: `${Math.round(interaction.client.ws.ping)} ms`,
inline: true,
},
],
color: successColor,
timestamp: new Date(),
footer: {
iconURL: footerIcon,
text: footerText,
},
};
}
)
.setTimestamp()
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon });
await interaction.editReply({
embeds: [interactionEmbed],
});

View file

@ -1,17 +1,19 @@
import getEmbedConfig from "../../../../../helpers/getEmbedConfig";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { CommandInteraction } from "discord.js";
export default {
metadata: { guildOnly: false, ephemeral: false },
import { CommandInteraction, EmbedBuilder } from "discord.js";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command.setName("stats").setDescription("Check bot statistics!)");
},
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { client } = interaction;
if (client?.uptime === null) return;
let totalSeconds = client?.uptime / 1000;
@ -24,10 +26,12 @@ export default {
const uptime = `${days} days, ${hours} hours, ${minutes} minutes and ${seconds} seconds`;
const interactionEmbed = {
title: ":hammer: Utilities - Stats",
description: "Below you can see a list of statistics about the bot.",
fields: [
const interactionEmbed = new EmbedBuilder()
.setColor(successColor)
.setTitle("[:hammer:] Stats")
.setDescription("Below you can see a list of statistics about the bot.")
.setTimestamp()
.addFields(
{
name: "⏰ Latency",
value: `${Date?.now() - interaction?.createdTimestamp} ms`,
@ -55,15 +59,10 @@ export default {
0
)}`,
inline: true,
},
],
color: successColor,
timestamp: new Date(),
footer: {
iconURL: footerIcon,
text: footerText,
},
};
}
)
.setFooter({ text: footerText, iconURL: footerIcon });
interaction?.editReply({ embeds: [interactionEmbed] });
},
};

View file

@ -1,3 +0,0 @@
// MongoDB connection string
export const url =
"mongodb+srv://username:password@server/database?retryWrites=true&w=majority";

View file

@ -1,14 +0,0 @@
import { Intents } from "discord.js"; // discord.js
// Discord API token
export const token = "";
// Discord API id
export const clientId = "";
// Discord API intents
export const intents = [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MEMBERS,
];

View file

@ -1,17 +0,0 @@
// Dependencies
import { ColorResolvable } from "discord.js";
// Color for successfully actions
export const successColor: ColorResolvable = "#22bb33";
// Color for waiting actions
export const waitColor: ColorResolvable = "#f0ad4e";
// Color for error actions
export const errorColor: ColorResolvable = "#bb2124";
// Footer text
export const footerText = "https://github.com/ZynerOrg/xyter";
// Footer icon
export const footerIcon = "https://github.com/ZynerOrg.png";

View file

@ -1,5 +0,0 @@
// Encryption algorithm
export const algorithm = "aes-256-ctr";
// Encryption secret (strictly 32 length)
export const secretKey = "";

View file

@ -1,14 +0,0 @@
// Development features
export const devMode = false;
// Development guild
export const guildId = "";
// Hoster name
export const hosterName = "someone";
// Hoster Url
export const hosterUrl = "https://xyter.zyner.org/customization/change-hoster";
// Winston log level
export const logLevel = "info";

View file

@ -1,2 +0,0 @@
// Timeout between repute someone (seconds)
export const timeout = 86400; // One day

View file

@ -0,0 +1,51 @@
import { Guild } from "discord.js";
import prisma from "../../handlers/database";
import updatePresence from "../../handlers/updatePresence";
import { IEventOptions } from "../../interfaces/EventOptions";
import logger from "../../middlewares/logger";
export const options: IEventOptions = {
type: "on",
};
// Execute the function
export const execute = async (guild: Guild) => {
const { client } = guild;
updatePresence(client);
// Create guildMember object
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: guild.ownerId,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: guild.ownerId,
},
where: {
id: guild.ownerId,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
};

View file

@ -0,0 +1,37 @@
// 3rd party dependencies
import { Guild } from "discord.js";
import prisma from "../../handlers/database";
import updatePresence from "../../handlers/updatePresence";
import { IEventOptions } from "../../interfaces/EventOptions";
import logger from "../../middlewares/logger";
export const options: IEventOptions = {
type: "on",
};
// Execute the function
export const execute = async (guild: Guild) => {
const { client } = guild;
updatePresence(client);
// Delete guildMember objects
const deleteGuildMembers = prisma.guildMember.deleteMany({
where: {
guildId: guild.id,
},
});
// Delete guild object
const deleteGuild = prisma.guild.deleteMany({
where: {
id: guild.id,
},
});
// The transaction runs synchronously so deleteUsers must run last.
await prisma.$transaction([deleteGuildMembers, deleteGuild]);
logger.silly(deleteGuildMembers);
logger.silly(deleteGuild);
};

View file

@ -1,31 +1,32 @@
import logger from "../../../logger";
import { GuildMember, MessageEmbed } from "discord.js";
import guildSchema from "../../../models/guild";
import getEmbedConfig from "../../../helpers/getEmbedConfig";
import { ChannelType, EmbedBuilder, GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger";
export default {
execute: async (member: GuildMember) => {
const { client, guild } = member;
const guildData = await guildSchema.findOne({ guildId: member.guild.id });
if (!guildData) {
throw new Error("Could not find guild");
}
if (guildData.audits.status !== true) return;
if (!guildData.audits.channelId) {
const getGuild = await prisma.guild.findUnique({
where: { id: member.guild.id },
});
if (!getGuild) throw new Error("Guild not found");
if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) {
throw new Error("Channel not found");
}
const embedConfig = await getEmbedConfig(guild);
const channel = client.channels.cache.get(guildData.audits.channelId);
if (channel?.type !== "GUILD_TEXT") {
const channel = client.channels.cache.get(getGuild.auditsChannelId);
if (!channel) throw new Error("Channel not found");
if (channel.type !== ChannelType.GuildText) {
throw new Error("Channel must be a text channel");
}
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTimestamp(new Date())
.setAuthor({
name: "Member Joined",
@ -50,12 +51,10 @@ export default {
]),
],
})
.then(async () => {
logger.debug(
`Audit log sent for event guildMemberAdd in guild ${member.guild.name} (${member.guild.id})`
);
.then(() => {
logger.debug(`Audit log sent for event guildMemberAdd`);
})
.catch(async () => {
.catch(() => {
throw new Error("Audit log failed to send");
});
},

View file

@ -0,0 +1,60 @@
// 3rd party dependencies
import { GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import updatePresence from "../../handlers/updatePresence";
import { IEventOptions } from "../../interfaces/EventOptions";
import logger from "../../middlewares/logger";
import audits from "./audits";
import joinMessage from "./joinMessage";
export const options: IEventOptions = {
type: "on",
};
// Execute the function
export const execute = async (member: GuildMember) => {
const { client, user, guild } = member;
logger.silly(
`New member: ${user.tag} (${user.id}) added to guild: ${guild.name} (${guild.id})`
);
await audits.execute(member);
await joinMessage.execute(member);
updatePresence(client);
// Create guildMember object
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: {},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
};

View file

@ -0,0 +1,48 @@
import { ChannelType, EmbedBuilder, GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData";
export default {
execute: async (member: GuildMember) => {
const { footerText, footerIcon, successColor } = await getEmbedConfig(
member.guild
);
const getGuild = await prisma.guild.findUnique({
where: { id: member.guild.id },
});
if (!getGuild) throw new Error("Guild not found");
const { client } = member;
if (getGuild.welcomeEnabled !== true) return;
if (!getGuild.welcomeJoinChannelId) return;
const channel = client.channels.cache.get(
`${getGuild.welcomeJoinChannelId}`
);
if (!channel) throw new Error("Channel not found");
if (channel.type !== ChannelType.GuildText)
throw new Error("Channel is not a text channel");
channel.send({
embeds: [
new EmbedBuilder()
.setColor(successColor)
.setTitle(`${member.user.username} has joined the server!`)
.setThumbnail(member.user.displayAvatarURL())
.setDescription(
getGuild.welcomeJoinChannelMessage ||
"Configure a join message in the `/settings guild welcome`."
)
.setTimestamp()
.setFooter({
text: footerText,
iconURL: footerIcon,
}),
],
});
},
};

View file

@ -1,31 +1,30 @@
import logger from "../../../logger";
import { GuildMember, MessageEmbed } from "discord.js";
import guildSchema from "../../../models/guild";
import getEmbedConfig from "../../../helpers/getEmbedConfig";
import { ChannelType, EmbedBuilder, GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger";
export default {
execute: async (member: GuildMember) => {
const { client, guild } = member;
const guildData = await guildSchema.findOne({ guildId: member.guild.id });
if (!guildData) {
throw new Error("Could not find guild");
}
if (guildData.audits.status !== true) return;
if (!guildData.audits.channelId) {
const getGuild = await prisma.guild.findUnique({
where: { id: member.guild.id },
});
if (!getGuild) throw new Error("Guild not found");
if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) {
throw new Error("Channel not found");
}
const embedConfig = await getEmbedConfig(guild);
const channel = client.channels.cache.get(guildData.audits.channelId);
if (channel?.type !== "GUILD_TEXT") {
const channel = client.channels.cache.get(getGuild.auditsChannelId);
if (channel?.type !== ChannelType.GuildText) {
throw new Error("Channel must be a text channel");
}
const embed = new MessageEmbed()
const embed = new EmbedBuilder()
.setTimestamp(new Date())
.setAuthor({
name: "Member Left",
@ -50,12 +49,10 @@ export default {
]),
],
})
.then(async () => {
logger.debug(
`Audit log sent for event guildMemberRemove in guild ${member.guild.name} (${member.guild.id})`
);
.then(() => {
logger.debug(`Audit log sent for event guildMemberRemove.`);
})
.catch(async () => {
.catch(() => {
throw new Error("Audit log failed to send");
});
},

Some files were not shown because too many files have changed in this diff Show more