Compare commits
3 commits
main
...
feat/sqlit
Author | SHA1 | Date | |
---|---|---|---|
4c1698e12f | |||
34118d5e47 | |||
97abd1fcee |
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
.env
|
.env
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
|
||||||
persist/
|
persist/
|
||||||
|
dist/
|
||||||
|
prisma/migrations/
|
||||||
|
prisma/persist/
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"author": "powermaker450",
|
"author": "powermaker450",
|
||||||
"license": "AGPLv3",
|
"license": "AGPLv3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@prisma/client": "^6.2.1",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"discord.js": "^14.16.3",
|
"discord.js": "^14.16.3",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
"prisma": "^6.2.1",
|
||||||
"typescript": "^5.6.3"
|
"typescript": "^5.6.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@prisma/client':
|
||||||
|
specifier: ^6.2.1
|
||||||
|
version: 6.2.1(prisma@6.2.1)
|
||||||
chalk:
|
chalk:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.2
|
version: 4.1.2
|
||||||
|
@ -27,6 +30,9 @@ importers:
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.3.3
|
specifier: ^3.3.3
|
||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
|
prisma:
|
||||||
|
specifier: ^6.2.1
|
||||||
|
version: 6.2.1
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.6.3
|
specifier: ^5.6.3
|
||||||
version: 5.6.3
|
version: 5.6.3
|
||||||
|
@ -61,6 +67,30 @@ packages:
|
||||||
resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==}
|
resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==}
|
||||||
engines: {node: '>=16.11.0'}
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
|
'@prisma/client@6.2.1':
|
||||||
|
resolution: {integrity: sha512-msKY2iRLISN8t5X0Tj7hU0UWet1u0KuxSPHWuf3IRkB4J95mCvGpyQBfQ6ufcmvKNOMQSq90O2iUmJEN2e5fiA==}
|
||||||
|
engines: {node: '>=18.18'}
|
||||||
|
peerDependencies:
|
||||||
|
prisma: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
prisma:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@prisma/debug@6.2.1':
|
||||||
|
resolution: {integrity: sha512-0KItvt39CmQxWkEw6oW+RQMD6RZ43SJWgEUnzxN8VC9ixMysa7MzZCZf22LCK5DSooiLNf8vM3LHZm/I/Ni7bQ==}
|
||||||
|
|
||||||
|
'@prisma/engines-version@6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69':
|
||||||
|
resolution: {integrity: sha512-7tw1qs/9GWSX6qbZs4He09TOTg1ff3gYsB3ubaVNN0Pp1zLm9NC5C5MZShtkz7TyQjx7blhpknB7HwEhlG+PrQ==}
|
||||||
|
|
||||||
|
'@prisma/engines@6.2.1':
|
||||||
|
resolution: {integrity: sha512-lTBNLJBCxVT9iP5I7Mn6GlwqAxTpS5qMERrhebkUhtXpGVkBNd/jHnNJBZQW4kGDCKaQg/r2vlJYkzOHnAb7ZQ==}
|
||||||
|
|
||||||
|
'@prisma/fetch-engine@6.2.1':
|
||||||
|
resolution: {integrity: sha512-OO7O9d6Mrx2F9i+Gu1LW+DGXXyUFkP7OE5aj9iBfA/2jjDXEJjqa9X0ZmM9NZNo8Uo7ql6zKm6yjDcbAcRrw1A==}
|
||||||
|
|
||||||
|
'@prisma/get-platform@6.2.1':
|
||||||
|
resolution: {integrity: sha512-zp53yvroPl5m5/gXYLz7tGCNG33bhG+JYCm74ohxOq1pPnrL47VQYFfF3RbTZ7TzGWCrR3EtoiYMywUBw7UK6Q==}
|
||||||
|
|
||||||
'@sapphire/async-queue@1.5.3':
|
'@sapphire/async-queue@1.5.3':
|
||||||
resolution: {integrity: sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==}
|
resolution: {integrity: sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==}
|
||||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||||
|
@ -118,6 +148,11 @@ packages:
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
has-flag@4.0.0:
|
has-flag@4.0.0:
|
||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -139,6 +174,11 @@ packages:
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
prisma@6.2.1:
|
||||||
|
resolution: {integrity: sha512-hhyM0H13pQleQ+br4CkzGizS5I0oInoeTw3JfLw1BRZduBSQxPILlJLwi+46wZzj9Je7ndyQEMGw/n5cN2fknA==}
|
||||||
|
engines: {node: '>=18.18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -225,6 +265,31 @@ snapshots:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
|
'@prisma/client@6.2.1(prisma@6.2.1)':
|
||||||
|
optionalDependencies:
|
||||||
|
prisma: 6.2.1
|
||||||
|
|
||||||
|
'@prisma/debug@6.2.1': {}
|
||||||
|
|
||||||
|
'@prisma/engines-version@6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69': {}
|
||||||
|
|
||||||
|
'@prisma/engines@6.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 6.2.1
|
||||||
|
'@prisma/engines-version': 6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69
|
||||||
|
'@prisma/fetch-engine': 6.2.1
|
||||||
|
'@prisma/get-platform': 6.2.1
|
||||||
|
|
||||||
|
'@prisma/fetch-engine@6.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 6.2.1
|
||||||
|
'@prisma/engines-version': 6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69
|
||||||
|
'@prisma/get-platform': 6.2.1
|
||||||
|
|
||||||
|
'@prisma/get-platform@6.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 6.2.1
|
||||||
|
|
||||||
'@sapphire/async-queue@1.5.3': {}
|
'@sapphire/async-queue@1.5.3': {}
|
||||||
|
|
||||||
'@sapphire/shapeshift@4.0.0':
|
'@sapphire/shapeshift@4.0.0':
|
||||||
|
@ -287,6 +352,9 @@ snapshots:
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
lodash.snakecase@4.1.1: {}
|
lodash.snakecase@4.1.1: {}
|
||||||
|
@ -299,6 +367,12 @@ snapshots:
|
||||||
|
|
||||||
prettier@3.3.3: {}
|
prettier@3.3.3: {}
|
||||||
|
|
||||||
|
prisma@6.2.1:
|
||||||
|
dependencies:
|
||||||
|
'@prisma/engines': 6.2.1
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
|
|
38
prisma/schema.prisma
Normal file
38
prisma/schema.prisma
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Guild {
|
||||||
|
guildId String @id
|
||||||
|
confessChannel String @unique
|
||||||
|
modChannel String? @unique
|
||||||
|
|
||||||
|
confessions Confession[]
|
||||||
|
bans Ban[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Confession {
|
||||||
|
id String @id
|
||||||
|
messageId String @unique
|
||||||
|
author String
|
||||||
|
authorId String
|
||||||
|
guildId String
|
||||||
|
content String
|
||||||
|
attachment String?
|
||||||
|
|
||||||
|
guild Guild @relation(fields: [guildId], references: [guildId])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Ban {
|
||||||
|
authorId String @id
|
||||||
|
guildId String
|
||||||
|
confessionId String?
|
||||||
|
reason Int
|
||||||
|
|
||||||
|
guild Guild @relation(fields: [guildId], references: [guildId])
|
||||||
|
}
|
|
@ -92,7 +92,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
if (interaction.options.getSubcommand() === "ban") {
|
if (interaction.options.getSubcommand() === "ban") {
|
||||||
const confessionId = interaction.options.getString("id")!;
|
const confessionId = interaction.options.getString("id")!;
|
||||||
|
|
||||||
if (dt.isBannedById(guildId, confessionId)) {
|
if (await dt.isBannedById(guildId, confessionId)) {
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
content: "That user is already banned!",
|
content: "That user is already banned!",
|
||||||
|
@ -101,7 +101,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
.catch(err => logger.error("A ban interaction error occured:", err));
|
.catch(err => logger.error("A ban interaction error occured:", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = dt.addBanById(guildId, confessionId);
|
const result = await dt.addBanById(guildId, confessionId);
|
||||||
|
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
|
@ -116,7 +116,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
} else if (interaction.options.getSubcommand() === "banuser") {
|
} else if (interaction.options.getSubcommand() === "banuser") {
|
||||||
const { id: userId } = interaction.options.getUser("user")!;
|
const { id: userId } = interaction.options.getUser("user")!;
|
||||||
|
|
||||||
const result = dt.addBanByUser(guildId, userId);
|
const result = await dt.addBanByUser(guildId, userId);
|
||||||
|
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
|
@ -127,9 +127,9 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
|
|
||||||
// /confessmod list
|
// /confessmod list
|
||||||
} else if (interaction.options.getSubcommand() === "list") {
|
} else if (interaction.options.getSubcommand() === "list") {
|
||||||
const bannedMembers = dt.getBans(guildId);
|
const bannedMembers = await dt.getBans(guildId);
|
||||||
|
|
||||||
const determineContent = () => {
|
const determineContent = async () => {
|
||||||
if (!bannedMembers.length) {
|
if (!bannedMembers.length) {
|
||||||
return "There are no bans.";
|
return "There are no bans.";
|
||||||
}
|
}
|
||||||
|
@ -140,11 +140,11 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
let idHead = "\n" + heading("Confessions:", HeadingLevel.Two);
|
let idHead = "\n" + heading("Confessions:", HeadingLevel.Two);
|
||||||
let idCount = false;
|
let idCount = false;
|
||||||
for (const member of bannedMembers) {
|
for (const member of bannedMembers) {
|
||||||
if (member.method === BanReason.ByUser) {
|
if (member.reason === BanReason.ByUser) {
|
||||||
userHead += "\n" + `<@${member.user}>`;
|
userHead += "\n" + `<@${member.authorId}>`;
|
||||||
userCount = true;
|
userCount = true;
|
||||||
} else if (member.method === BanReason.ById) {
|
} else if (member.reason === BanReason.ById) {
|
||||||
const confession = dt.getConfession(guildId, member.confessionId!)!;
|
const confession = (await dt.getConfession(guildId, member.confessionId!))!;
|
||||||
idHead += `\nConfession ${inlineCode(member.confessionId!)}: ${italic(confession.content)}`;
|
idHead += `\nConfession ${inlineCode(member.confessionId!)}: ${italic(confession.content)}`;
|
||||||
idCount = true;
|
idCount = true;
|
||||||
}
|
}
|
||||||
|
@ -160,14 +160,14 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
|
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
content: determineContent(),
|
content: await determineContent(),
|
||||||
...messageOpts
|
...messageOpts
|
||||||
})
|
})
|
||||||
.catch(err => logger.error("A banlist interaction error occured:", err));
|
.catch(err => logger.error("A banlist interaction error occured:", err));
|
||||||
|
|
||||||
// /confessmod pardon <id>
|
// /confessmod pardon <id>
|
||||||
} else if (interaction.options.getSubcommand() === "pardon") {
|
} else if (interaction.options.getSubcommand() === "pardon") {
|
||||||
const result = dt.removeBanById(
|
const result = await dt.removeBanById(
|
||||||
guildId,
|
guildId,
|
||||||
interaction.options.getString("id")!
|
interaction.options.getString("id")!
|
||||||
);
|
);
|
||||||
|
@ -185,7 +185,7 @@ export async function execute(interaction: ChatInputCommandInteraction) {
|
||||||
} else if (interaction.options.getSubcommand() === "pardonuser") {
|
} else if (interaction.options.getSubcommand() === "pardonuser") {
|
||||||
const { id: userId } = interaction.options.getUser("user")!;
|
const { id: userId } = interaction.options.getUser("user")!;
|
||||||
|
|
||||||
const result = dt.removeBanByUser(guildId, userId);
|
const result = await dt.removeBanByUser(guildId, userId);
|
||||||
|
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
|
|
|
@ -42,7 +42,7 @@ export async function execute(interaction: CommandInteraction) {
|
||||||
const { id: guildId } = interaction.guild!;
|
const { id: guildId } = interaction.guild!;
|
||||||
const { displayName: username } = interaction.user;
|
const { displayName: username } = interaction.user;
|
||||||
|
|
||||||
if (dt.checkSetup(guildId)) {
|
if (await dt.checkSetup(guildId)) {
|
||||||
return interaction
|
return interaction
|
||||||
.reply({
|
.reply({
|
||||||
content: "This guild has already been set up!",
|
content: "This guild has already been set up!",
|
||||||
|
|
|
@ -38,7 +38,7 @@ export async function deleteConfession(
|
||||||
const { id: guildId } = interaction.guild!;
|
const { id: guildId } = interaction.guild!;
|
||||||
const { id: userId } = interaction.user;
|
const { id: userId } = interaction.user;
|
||||||
|
|
||||||
const result = dt.getConfession(guildId, idVal);
|
const result = await dt.getConfession(guildId, idVal);
|
||||||
// If there is a result, and the user is either an author or has manage messages
|
// If there is a result, and the user is either an author or has manage messages
|
||||||
const allowedByUser = result && result.authorId === userId;
|
const allowedByUser = result && result.authorId === userId;
|
||||||
const allowedByMod =
|
const allowedByMod =
|
||||||
|
@ -48,8 +48,8 @@ export async function deleteConfession(
|
||||||
// If a confession is found with the given ID, check if the user is the one that posted it, and delete it if they are.
|
// If a confession is found with the given ID, check if the user is the one that posted it, and delete it if they are.
|
||||||
// Otherwise, don't let the user delete anything.
|
// Otherwise, don't let the user delete anything.
|
||||||
if (allowedByUser || allowedByMod) {
|
if (allowedByUser || allowedByMod) {
|
||||||
const confession = dt.getConfession(guildId, idVal)!.messageId;
|
const confession = (await dt.getConfession(guildId, idVal))!.messageId;
|
||||||
const channelId = dt.getGuildInfo(guildId)!.settings.confessChannel;
|
const channelId = (await dt.getGuildInfo(guildId))!.confessChannel;
|
||||||
const emptyEmbed = new EmbedBuilder()
|
const emptyEmbed = new EmbedBuilder()
|
||||||
.setColor(getRandomColor())
|
.setColor(getRandomColor())
|
||||||
.setTitle("Confession Deleted")
|
.setTitle("Confession Deleted")
|
||||||
|
|
|
@ -27,7 +27,7 @@ export async function submitConfession(
|
||||||
const { id: userId, displayName: username } = interaction.user;
|
const { id: userId, displayName: username } = interaction.user;
|
||||||
|
|
||||||
// If the user is banned in this guild, don't let them post
|
// If the user is banned in this guild, don't let them post
|
||||||
if (dt.isBannedByUser(guildId, userId)) {
|
if (await dt.isBannedByUser(guildId, userId)) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: "You are banned from confessions in this server!",
|
content: "You are banned from confessions in this server!",
|
||||||
...messageOpts
|
...messageOpts
|
||||||
|
@ -35,7 +35,7 @@ export async function submitConfession(
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no guild info is present for this guild, don't let the user post
|
// If no guild info is present for this guild, don't let the user post
|
||||||
if (!dt.getGuildInfo(guildId)) {
|
if (!(await dt.getGuildInfo(guildId))) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content:
|
content:
|
||||||
"The bot hasn't been set up yet! Ask the server admins to set it up.",
|
"The bot hasn't been set up yet! Ask the server admins to set it up.",
|
||||||
|
@ -43,8 +43,7 @@ export async function submitConfession(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const confessChannel = dt.getGuildInfo(guildId)!.settings.confessChannel;
|
const { confessChannel, modChannel } = (await dt.getGuildInfo(guildId))!;
|
||||||
const adminChannel = dt.getGuildInfo(guildId)?.settings.modChannel;
|
|
||||||
|
|
||||||
const isAttachment = (text: string | null) =>
|
const isAttachment = (text: string | null) =>
|
||||||
text && (text.startsWith("http://") || text.startsWith("https://"));
|
text && (text.startsWith("http://") || text.startsWith("https://"));
|
||||||
|
@ -125,10 +124,10 @@ export async function submitConfession(
|
||||||
components: [actionRow]
|
components: [actionRow]
|
||||||
});
|
});
|
||||||
|
|
||||||
adminChannel &&
|
modChannel &&
|
||||||
(await (BotClient.channels.cache.get(adminChannel!) as TextChannel).send({
|
(BotClient.channels.cache.get(modChannel!) as TextChannel).send({
|
||||||
embeds: [adminConfessionEmbed]
|
embeds: [adminConfessionEmbed]
|
||||||
}));
|
});
|
||||||
|
|
||||||
const fields: readonly [Message, string, string, string, string] = [
|
const fields: readonly [Message, string, string, string, string] = [
|
||||||
message,
|
message,
|
||||||
|
@ -142,23 +141,12 @@ export async function submitConfession(
|
||||||
? dt.addConfession(...fields, attachmentContent)
|
? dt.addConfession(...fields, attachmentContent)
|
||||||
: dt.addConfession(...fields);
|
: dt.addConfession(...fields);
|
||||||
|
|
||||||
const confessionsLength = dt.getGuildInfo(guildId)!.confessions.length;
|
const confessions = await dt.getConfessions(guildId);
|
||||||
|
|
||||||
// If there are 2 or more confessions, remove the previous confession's button components
|
// If there are 2 or more confessions, remove the previous confession's button components
|
||||||
if (confessionsLength >= 2) {
|
if (confessions.length >= 2) {
|
||||||
(BotClient.channels.cache.get(confessChannel) as TextChannel).messages
|
const previousMessage = await (BotClient.channels.cache.get(confessChannel) as TextChannel).messages.fetch(confessions[confessions.length - 2].messageId);
|
||||||
.fetch(
|
previousMessage.edit({ components: [] }).catch(err => logger.error("An error occured removing embeds from the previous message:", err));
|
||||||
dt.getGuildInfo(guildId)!.confessions[confessionsLength - 2].messageId
|
|
||||||
)
|
|
||||||
.then(message => {
|
|
||||||
message.edit({ components: [] });
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
logger.error(
|
|
||||||
"An error occured removing embeds from the previous message:",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
|
|
|
@ -47,7 +47,7 @@ export async function execute(interaction: ContextMenuCommandInteraction) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id: confessionId } = dt.getConfessionById(guildId!, targetId)!;
|
const { id: confessionId } = (await dt.getConfessionById(guildId!, targetId))!;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deleteConfession(interaction, confessionId);
|
deleteConfession(interaction, confessionId);
|
||||||
|
|
24
src/main.ts
24
src/main.ts
|
@ -29,7 +29,7 @@ import { messageOpts } from "./constants";
|
||||||
import { submitConfession } from "./commandutils";
|
import { submitConfession } from "./commandutils";
|
||||||
import { contextCommands } from "./contextcommands";
|
import { contextCommands } from "./contextcommands";
|
||||||
|
|
||||||
export const dt = new StoreMan(StoreMan.checkFile());
|
export const dt = new StoreMan();
|
||||||
const logger = new Logger("Main");
|
const logger = new Logger("Main");
|
||||||
|
|
||||||
BotClient.once("ready", client => {
|
BotClient.once("ready", client => {
|
||||||
|
@ -75,25 +75,7 @@ BotClient.on(Events.InteractionCreate, async interaction => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
BotClient.on(Events.MessageDelete, async message => {
|
// BotClient.on(Events.MessageDelete, async message => {});
|
||||||
const guildId = message.guild?.id!;
|
|
||||||
if (!dt.getGuildInfo(guildId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const messageId = message.id;
|
|
||||||
const confessions = dt.getGuildInfo(guildId)?.confessions!;
|
|
||||||
|
|
||||||
for (const confession of confessions) {
|
|
||||||
if (confession.messageId === messageId) {
|
|
||||||
dt.adminDelConfession(guildId, confession.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
logger.error("An error occured:", err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Submit Confession button
|
// Submit Confession button
|
||||||
BotClient.on(Events.InteractionCreate, async interaction => {
|
BotClient.on(Events.InteractionCreate, async interaction => {
|
||||||
|
@ -108,7 +90,7 @@ BotClient.on(Events.InteractionCreate, async interaction => {
|
||||||
|
|
||||||
if (requestSubmit) {
|
if (requestSubmit) {
|
||||||
// Check if the user is banned from confessions before showing the modal
|
// Check if the user is banned from confessions before showing the modal
|
||||||
dt.isBannedByUser(interaction.guild?.id!, interaction.user.id)
|
await dt.isBannedByUser(interaction.guild?.id!, interaction.user.id)
|
||||||
? interaction
|
? interaction
|
||||||
.reply({
|
.reply({
|
||||||
content: "You are banned from confessions in this server!",
|
content: "You are banned from confessions in this server!",
|
||||||
|
|
|
@ -16,341 +16,179 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from "fs";
|
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import {
|
import {
|
||||||
BanReason,
|
BanReason,
|
||||||
Confession,
|
|
||||||
ConfessionBan,
|
|
||||||
GuildData,
|
|
||||||
GuildSettings
|
GuildSettings
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { DATA_DIR } from "./config";
|
|
||||||
import { CommandInteraction, Message } from "discord.js";
|
import { CommandInteraction, Message } from "discord.js";
|
||||||
|
import { Guild, Confession, PrismaClient, Ban } from "@prisma/client";
|
||||||
import Logger from "../utils/Logger";
|
import Logger from "../utils/Logger";
|
||||||
|
|
||||||
export class StoreMan {
|
export class StoreMan {
|
||||||
public static readonly fullPath: string =
|
|
||||||
(DATA_DIR ?? "./persist/") + "data.json";
|
|
||||||
private static logger = new Logger("StoreMan");
|
private static logger = new Logger("StoreMan");
|
||||||
private data: GuildData[];
|
private static checkResult = (result: any | null) => result ? true : false;
|
||||||
|
|
||||||
constructor(existingData: GuildData[] = []) {
|
private client: PrismaClient;
|
||||||
this.data = existingData;
|
|
||||||
|
constructor() {
|
||||||
|
this.client = new PrismaClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static genId = () => crypto.randomBytes(2).toString("hex");
|
public static genId = () => crypto.randomBytes(2).toString("hex");
|
||||||
|
|
||||||
public static toConfession(
|
|
||||||
message: Message,
|
|
||||||
id: string,
|
|
||||||
author: string,
|
|
||||||
authorId: string,
|
|
||||||
content: string,
|
|
||||||
attachment?: string
|
|
||||||
): Confession {
|
|
||||||
return {
|
|
||||||
id: id,
|
|
||||||
messageId: message.id,
|
|
||||||
author: author,
|
|
||||||
authorId: authorId,
|
|
||||||
content: content,
|
|
||||||
attachment: attachment
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static checkFile(): GuildData[] {
|
|
||||||
let final: GuildData[];
|
|
||||||
|
|
||||||
if (fs.existsSync(StoreMan.fullPath)) {
|
|
||||||
const data = fs.readFileSync(StoreMan.fullPath);
|
|
||||||
|
|
||||||
// Read the file if it isn't empty, else set final to an empty array
|
|
||||||
final = !data.toString().trim() ? [] : JSON.parse(data.toString());
|
|
||||||
} else {
|
|
||||||
// If the directory doesn't exist, make it
|
|
||||||
!fs.existsSync(DATA_DIR ?? "./persist/") &&
|
|
||||||
fs.mkdirSync(DATA_DIR ?? "./persist/");
|
|
||||||
fs.createWriteStream(StoreMan.fullPath);
|
|
||||||
final = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async saveFile(): Promise<void> {
|
|
||||||
fs.writeFile(
|
|
||||||
StoreMan.fullPath,
|
|
||||||
JSON.stringify(this.data, null, 2),
|
|
||||||
"utf8",
|
|
||||||
err => err && StoreMan.logger.error("A write error occured:", err)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if a guild is not set up
|
// Checks if a guild is not set up
|
||||||
public checkSetup(guildId: string): boolean {
|
public async checkSetup(guildId: string): Promise<boolean> {
|
||||||
for (const guild of this.data) {
|
const result = await this.client.guild.findFirst({ where: { guildId } }).then(StoreMan.checkResult);
|
||||||
if (guild.id === guildId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up a guild and stores it in the persistent file
|
// Sets up a guild and stores it in the persistent file
|
||||||
public setup(guildId: string, opts: GuildSettings): void {
|
public async setup(guildId: string, { confessChannel, modChannel }: GuildSettings): Promise<void> {
|
||||||
this.data.push({
|
await this.client.guild.create({ data: { guildId, confessChannel, modChannel } }).then(() => StoreMan.logger.log("Guild created"));
|
||||||
id: guildId,
|
|
||||||
confessions: [],
|
|
||||||
settings: opts
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the settings for a given guild
|
// Clear the settings for a given guild
|
||||||
public clearSettings(guildId: string): void {
|
public async clearSettings(guildId: string): Promise<void> {
|
||||||
this.data = this.data.filter(guild => {
|
await this.client.confession.deleteMany({ where: { guildId } });
|
||||||
return guild.id !== guildId;
|
await this.client.ban.deleteMany({ where: { guildId } });
|
||||||
});
|
await this.client.guild.delete({ where: { guildId } });
|
||||||
this.saveFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getGuildInfo(guildId: string): GuildData | null {
|
public async getGuildInfo(guildId: string): Promise<Guild | null> {
|
||||||
for (const guild of this.data) {
|
return await this.client.guild.findFirst({ where: { guildId } });
|
||||||
if (guild.id === guildId) {
|
|
||||||
return guild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to add a confession. Returns true if the confession is sent, false if otherwise.
|
// Attempts to add a confession. Returns true if the confession is sent, false if otherwise.
|
||||||
public addConfession(
|
public async addConfession(
|
||||||
message: Message,
|
message: Message,
|
||||||
id: string,
|
id: string,
|
||||||
author: string,
|
author: string,
|
||||||
authorId: string,
|
authorId: string,
|
||||||
content: string,
|
content: string,
|
||||||
attachment?: string
|
attachment?: string
|
||||||
): boolean {
|
): Promise<boolean> {
|
||||||
const { id: guildId } = message.guild!;
|
const { id: guildId } = message.guild!;
|
||||||
|
const { id: messageId } = message;
|
||||||
|
|
||||||
for (const guild of this.data) {
|
const ban = await this.client.ban.findFirst({ where: { guildId, authorId } }).then(StoreMan.checkResult);
|
||||||
if (guild.id === guildId) {
|
|
||||||
// If the author's user ID is in the ban list, don't let them post a confession.
|
if (ban) {
|
||||||
if (this.isBannedByUser(guildId, author)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
guild.confessions.push(
|
await this.client.confession.create({ data: { id, messageId, author, authorId, guildId, content, attachment } })
|
||||||
StoreMan.toConfession(
|
|
||||||
message,
|
|
||||||
id,
|
|
||||||
author,
|
|
||||||
authorId,
|
|
||||||
content,
|
|
||||||
attachment
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.saveFile();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(
|
public async getConfession(
|
||||||
`No guild with id ${id} was found. Something's pretty wrong.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConfession(
|
|
||||||
guildId: string,
|
guildId: string,
|
||||||
confessionId: string
|
id: string
|
||||||
): Confession | null {
|
): Promise<Confession | null> {
|
||||||
for (const guild of this.data) {
|
return await this.client.confession.findFirst({ where: { guildId, id } });
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const confession of guild.confessions) {
|
|
||||||
if (confession.id === confessionId) {
|
|
||||||
return confession;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public async getConfessions(guildId: string): Promise<Confession[]> {
|
||||||
|
return await this.client.confession.findMany({ where: { guildId } });
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConfessionById(guildId: string, messageId: string): Confession | null {
|
public async getConfessionById(guildId: string, messageId: string): Promise<Confession | null> {
|
||||||
for (const guild of this.data) {
|
return await this.client.confession.findFirst({ where: { guildId, messageId } });
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const confession of guild.confessions) {
|
|
||||||
if (confession.messageId === messageId) {
|
|
||||||
return confession;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
/**
|
||||||
|
* Delete a confession from the database.
|
||||||
|
*
|
||||||
|
* @param interaction - Used to obtain the guild and authorId
|
||||||
|
* @param id - The confession ID to delete
|
||||||
|
*
|
||||||
|
* @returns true if the confession was sucessfully deleted, false if otherwise.
|
||||||
|
*/
|
||||||
|
public async delConfesssion(
|
||||||
|
{ guild, user: { id: authorId } }: CommandInteraction,
|
||||||
|
id: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
const { id: guildId } = guild!;
|
||||||
|
const result = await this.client.confession.delete({ where: { guildId, authorId, id } }).then(StoreMan.checkResult);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to delete a confession. If it is sucessfully deleted, returns true, else false.
|
/**
|
||||||
public delConfesssion(
|
* Delete a confession from the database as an admin.
|
||||||
{ guild, user }: CommandInteraction,
|
*
|
||||||
confessionId: string
|
* @param guildId - The ID of the guild to delete from
|
||||||
): boolean {
|
* @param id - The ID of the confession to delete
|
||||||
const guildId = guild?.id;
|
*/
|
||||||
const userId = user.id;
|
public async adminDelConfession(guildId: string, id: string): Promise<void> {
|
||||||
|
await this.client.confession.delete({ where: { guildId, id } });
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const confession of guild.confessions) {
|
|
||||||
if (confession.authorId === userId) {
|
|
||||||
guild.confessions = guild.confessions.filter(confession => {
|
|
||||||
return confession.id !== confessionId;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public adminDelConfession(guildId: string, confessionId: string): void {
|
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
guild.confessions = guild.confessions.filter(confession => {
|
|
||||||
return confession.id !== confessionId;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a certain user is banned within a guild.
|
// Check if a certain user is banned within a guild.
|
||||||
public isBannedByUser(guildId: string, userId: string): boolean {
|
public async isBannedByUser(guildId: string, authorId: string): Promise<boolean> {
|
||||||
for (const guild of this.data) {
|
const result = await this.client.ban.findFirst({ where: { guildId, authorId } }).then(StoreMan.checkResult);
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const ban of guild.settings.bans) {
|
return result;
|
||||||
if (ban.user === userId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async isBannedById(guildId: string, confessionId: string): Promise<boolean> {
|
||||||
|
const result = await this.client.ban.findFirst({ where: { guildId, confessionId } }).then(StoreMan.checkResult);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBans(guildId: string): Promise<Ban[]> {
|
||||||
|
return await this.client.ban.findMany({ where: { guildId } });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ban a user by confession id.
|
||||||
|
*
|
||||||
|
* @param guildId - The ID of the guild to ban from
|
||||||
|
* @param confessionId - The ID of the confession to ban for
|
||||||
|
*/
|
||||||
|
public async addBanById(guildId: string, confessionId: string): Promise<boolean> {
|
||||||
|
const alreadyBanned = await this.isBannedById(guildId, confessionId);
|
||||||
|
|
||||||
|
if (alreadyBanned) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isBannedById(guildId: string, confessionId: string): boolean {
|
const { authorId } = await this.client.confession.findFirstOrThrow({ where: { guildId, id: confessionId } });
|
||||||
for (const guild of this.data) {
|
await this.client.ban.create({ data: { guildId, authorId, confessionId, reason: BanReason.ById } });
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const ban of guild.settings.bans) {
|
|
||||||
if (ban.confessionId === confessionId) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public async addBanByUser(guildId: string, authorId: string): Promise<boolean> {
|
||||||
|
const alreadyBanned = await this.isBannedByUser(guildId, authorId);
|
||||||
|
|
||||||
|
if (alreadyBanned) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBans(guildId: string): ConfessionBan[] {
|
await this.client.ban.create({ data: { guildId, authorId, reason: BanReason.ByUser } });
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
return guild.settings.bans;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to ban a user from confessions.
|
|
||||||
public addBanById(guildId: string, confessionId: string): boolean {
|
|
||||||
const confession = this.getConfession(guildId, confessionId);
|
|
||||||
|
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
if (confession) {
|
|
||||||
// Only add the user to the ban list if they aren't banned already
|
|
||||||
!this.isBannedByUser(guildId, confession.authorId) &&
|
|
||||||
guild.settings.bans.push({
|
|
||||||
user: confession.authorId,
|
|
||||||
confessionId: confessionId,
|
|
||||||
method: BanReason.ById
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addBanByUser(guildId: string, userId: string): boolean {
|
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
// Only add the user to the ban list if they aren't banned already
|
|
||||||
!this.isBannedByUser(guildId, userId) &&
|
|
||||||
guild.settings.bans.push({
|
|
||||||
user: userId,
|
|
||||||
method: BanReason.ByUser
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to pardon a user from a ban. If sucessfully completed, returns true, false if otherwise.
|
// Attempts to pardon a user from a ban. If sucessfully completed, returns true, false if otherwise.
|
||||||
public removeBanById(guildId: string, confessionId: string): boolean {
|
public async removeBanById(guildId: string, confessionId: string): Promise<boolean> {
|
||||||
for (const guild of this.data) {
|
if (await this.isBannedById(guildId, confessionId)) {
|
||||||
if (guild.id === guildId) {
|
|
||||||
if (this.getConfession(guildId, confessionId)) {
|
|
||||||
guild.settings.bans = guild.settings.bans.filter(ban => {
|
|
||||||
return (
|
|
||||||
ban.user !== this.getConfession(guildId, confessionId)?.authorId!
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeBanByUser(guildId: string, userId: string): boolean {
|
const { authorId } = await this.client.ban.findFirstOrThrow({ where: { guildId, confessionId } });
|
||||||
for (const guild of this.data) {
|
|
||||||
if (guild.id === guildId) {
|
|
||||||
for (const ban of guild.settings.bans) {
|
|
||||||
if (ban.method === BanReason.ByUser && ban.user === userId) {
|
|
||||||
guild.settings.bans = guild.settings.bans.filter(ban => {
|
|
||||||
return ban.user !== userId;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.saveFile();
|
await this.client.ban.delete({ where: { guildId, confessionId, authorId } });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
public async removeBanByUser(guildId: string, authorId: string): Promise<boolean> {
|
||||||
|
if (await this.isBannedByUser(guildId, authorId)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
await this.client.ban.delete({ where: { guildId, authorId } });
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue