🚀 Bot is fully migrated over to Prisma

This commit is contained in:
Axel Olausson Holtenäs 2022-10-21 17:36:34 +02:00
parent 193b778910
commit 8898959c84
22 changed files with 541 additions and 516 deletions

View file

@ -0,0 +1,16 @@
-- 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,25 @@
/*
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,20 @@
-- 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,20 @@
-- 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

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

View file

@ -58,8 +58,9 @@ model Guild {
welcomeLeaveChannelId String? welcomeLeaveChannelId String?
welcomeLeaveChannelMessage String? welcomeLeaveChannelMessage String?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
} }
model User { model User {
@ -72,8 +73,9 @@ model User {
reputationsEarned Int @default(0) reputationsEarned Int @default(0)
Cooldown Cooldown[] Cooldown Cooldown[]
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
} }
model GuildMember { model GuildMember {
@ -89,8 +91,9 @@ model GuildMember {
creditsEarned Int @default(0) creditsEarned Int @default(0)
pointsEarned Int @default(0) pointsEarned Int @default(0)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
GuildShopRoles GuildShopRoles[]
// Unique Identifier // Unique Identifier
@@unique([userId, guildId]) @@unique([userId, guildId])
@ -122,3 +125,20 @@ model Cooldown {
@@unique([guildId, userId, timeoutId]) @@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

@ -8,7 +8,7 @@ import { ChatInputCommandInteraction } from "discord.js";
import moduleBuy from "./modules/buy"; import moduleBuy from "./modules/buy";
import moduleCancel from "./modules/cancel"; import moduleCancel from "./modules/cancel";
import guildSchema from "../../../../models/guild"; import prisma from "../../../../handlers/database";
export default { export default {
builder: (group: SlashCommandSubcommandGroupBuilder) => { builder: (group: SlashCommandSubcommandGroupBuilder) => {
@ -26,13 +26,12 @@ export default {
if (!interaction.guild) return; if (!interaction.guild) return;
const { options, guild } = interaction; const { options, guild } = interaction;
const guildDB = await guildSchema?.findOne({ const getGuild = await prisma.guild.findUnique({
guildId: guild?.id, where: { id: guild.id },
}); });
if (!getGuild) throw new Error("Guild not found");
if (guildDB === null) return; if (!getGuild.shopRolesEnabled)
if (!guildDB.shop.roles.status)
throw new Error("This server has disabled shop roles."); throw new Error("This server has disabled shop roles.");
if (options?.getSubcommand() === "buy") { if (options?.getSubcommand() === "buy") {

View file

@ -1,12 +1,22 @@
// Dependencies // Dependencies
// Helpers // Helpers
import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js"; import {
ChatInputCommandInteraction,
ColorResolvable,
EmbedBuilder,
GuildMemberRoleManager,
} from "discord.js";
import deferReply from "../../../../../../handlers/deferReply"; import deferReply from "../../../../../../handlers/deferReply";
import getEmbedData from "../../../../../../helpers/getEmbedData";
import logger from "../../../../../../middlewares/logger";
// Configurations // Configurations
// import fetchUser from "../../../../../../helpers/userData"; // import fetchUser from "../../../../../../helpers/userData";
// Models // Models
import prisma from "../../../../../../handlers/database";
import pluralize from "../../../../../../helpers/pluralize";
// Function // Function
export default { export default {
builder: (command: SlashCommandSubcommandBuilder) => { builder: (command: SlashCommandSubcommandBuilder) => {
@ -29,65 +39,140 @@ export default {
execute: async (interaction: ChatInputCommandInteraction) => { execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true); await deferReply(interaction, true);
// const { successColor, footerText, footerIcon } = await getEmbedConfig( const { successColor, footerText, footerIcon } = await getEmbedData(
// interaction.guild interaction.guild
// ); );
// const { options, guild, user, member } = interaction; const { options, guild, user, member } = interaction;
// const optionName = options?.getString("name"); const optionName = options?.getString("name");
// const optionColor = options?.getString("color"); const optionColor = options?.getString("color");
// // If amount is null // If amount is null
// if (optionName === null) if (optionName === null)
// throw new Error("We could not read your requested name"); throw new Error("We could not read your requested name");
// await guild?.roles await guild?.roles
// .create({ .create({
// name: optionName, name: optionName,
// color: optionColor as ColorResolvable, color: optionColor as ColorResolvable,
// reason: `${user?.id} bought from shop`, reason: `${user?.id} bought from shop`,
// }) })
// .then(async (role) => { .then(async (role) => {
// // Get guild object const userId = "SNOWFLKAE";
// const guildDB = await guildSchema?.findOne({ const guildId = "SNOWFLAKE";
// guildId: guild?.id,
// }); const createGuildMember = await prisma.guildMember.upsert({
// const userDB = await fetchUser(user, guild); where: {
// if (userDB === null) { userId_guildId: {
// return logger?.silly(`User is null`); userId,
// } guildId,
// if (guildDB === null) { },
// return logger?.silly(`Guild is null`); },
// } update: {},
// if (guildDB.shop === null) { create: {
// return logger?.silly(`Shop is null`); user: {
// } connectOrCreate: {
// const { pricePerHour } = guildDB.shop.roles; create: {
// userDB.credits -= pricePerHour; id: userId,
// await userDB?.save(); },
// await shopRolesSchema?.create({ where: {
// roleId: role?.id, id: userId,
// userId: user?.id, },
// guildId: guild?.id, },
// pricePerHour, },
// lastPayed: new Date(), guild: {
// }); connectOrCreate: {
// await (member?.roles as GuildMemberRoleManager)?.add(role?.id); create: {
// logger?.silly(`Role ${role?.name} was bought by ${user?.tag}`); id: guildId,
// const interactionEmbed = new EmbedBuilder() },
// .setTitle("[:shopping_cart:] Buy") where: {
// .setDescription( id: guildId,
// `You bought **${optionName}** for **${pluralize( },
// pricePerHour, },
// "credit" },
// )}**.` },
// ) include: {
// .setTimestamp() user: true,
// .setColor(successColor) guild: true,
// .setFooter({ text: footerText, iconURL: footerIcon }); },
// return interaction?.editReply({ });
// embeds: [interactionEmbed],
// }); logger.silly(createGuildMember);
// })
// .catch(() => { // Get guild object
// throw new Error("Failed creating role."); 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

@ -1,11 +1,21 @@
// Dependencies // Dependencies
// Helpers // Helpers
import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction } from "discord.js"; import {
ChatInputCommandInteraction,
EmbedBuilder,
GuildMemberRoleManager,
} from "discord.js";
// Configurations // Configurations
// import fetchUser from "../../../../../../helpers/userData";
// Models // Models
import deferReply from "../../../../../../handlers/deferReply"; 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 // Function
export default { export default {
@ -23,45 +33,95 @@ export default {
execute: async (interaction: ChatInputCommandInteraction) => { execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true); await deferReply(interaction, true);
// const { successColor, footerText, footerIcon } = await getEmbedConfig( const { successColor, footerText, footerIcon } = await getEmbedData(
// interaction.guild interaction.guild
// ); );
// const { options, guild, user, member } = interaction; const { options, guild, user, member } = interaction;
// const optionRole = options.getRole("role"); const optionRole = options.getRole("role");
// if (optionRole === null) if (optionRole === null)
// throw new Error("We could not read your requested role."); throw new Error("We could not read your requested role.");
// const roleExist = await shopRolesSchema?.findOne({ if (!guild) throw new Error("No guild specified");
// guildId: guild?.id, if (!user) throw new Error("No user specified");
// userId: user?.id,
// roleId: optionRole?.id, const roleExist = await prisma.guildShopRoles.findUnique({
// }); where: {
// if (roleExist === null) return; guildId_userId_roleId: {
// await (member?.roles as GuildMemberRoleManager)?.remove(optionRole?.id); guildId: guild.id,
// await guild?.roles userId: user.id,
// .delete(optionRole?.id, `${user?.id} canceled from shop`) roleId: optionRole.id,
// .then(async () => { },
// const userDB = await fetchUser(user, guild); },
// if (userDB === null) { });
// return logger?.silly(`User is null`); if (roleExist === null) return;
// } await (member?.roles as GuildMemberRoleManager)?.remove(optionRole?.id);
// await shopRolesSchema?.deleteOne({ await guild?.roles
// roleId: optionRole?.id, .delete(optionRole?.id, `${user?.id} canceled from shop`)
// userId: user?.id, .then(async () => {
// guildId: guild?.id, const createGuildMember = await prisma.guildMember.upsert({
// }); where: {
// const interactionEmbed = new EmbedBuilder() userId_guildId: {
// .setTitle("[:shopping_cart:] Cancel") userId: user.id,
// .setDescription(`You have canceled ${optionRole.name}.`) guildId: guild.id,
// .setTimestamp() },
// .setColor(successColor) },
// .addFields({ update: {},
// name: "Your balance", create: {
// value: `${pluralize(userDB?.credits, "credit")}`, user: {
// }) connectOrCreate: {
// .setFooter({ text: footerText, iconURL: footerIcon }); create: {
// return interaction?.editReply({ id: user.id,
// embeds: [interactionEmbed], },
// }); 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

@ -1,25 +1,28 @@
import { ChannelType, EmbedBuilder, GuildMember } from "discord.js"; import { ChannelType, EmbedBuilder, GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import guildSchema from "../../models/guild";
export default { export default {
execute: async (member: GuildMember) => { execute: async (member: GuildMember) => {
const { client, guild } = member; const { client, guild } = member;
const guildData = await guildSchema.findOne({ guildId: member.guild.id }); const getGuild = await prisma.guild.findUnique({
if (!guildData) { where: { id: member.guild.id },
throw new Error("Could not find guild"); });
} if (!getGuild) throw new Error("Guild not found");
if (guildData.audits.status !== true) return;
if (!guildData.audits.channelId) { if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) {
throw new Error("Channel not found"); throw new Error("Channel not found");
} }
const embedConfig = await getEmbedConfig(guild); const embedConfig = await getEmbedConfig(guild);
const channel = client.channels.cache.get(guildData.audits.channelId); const channel = client.channels.cache.get(getGuild.auditsChannelId);
if (channel?.type !== ChannelType.GuildText) {
if (!channel) throw new Error("Channel not found");
if (channel.type !== ChannelType.GuildText) {
throw new Error("Channel must be a text channel"); throw new Error("Channel must be a text channel");
} }

View file

@ -1,24 +1,25 @@
import { ChannelType, EmbedBuilder, GuildMember } from "discord.js"; import { ChannelType, EmbedBuilder, GuildMember } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import guildSchema from "../../models/guild";
export default { export default {
execute: async (member: GuildMember) => { execute: async (member: GuildMember) => {
const { client, guild } = member; const { client, guild } = member;
const guildData = await guildSchema.findOne({ guildId: member.guild.id }); const getGuild = await prisma.guild.findUnique({
if (!guildData) { where: { id: member.guild.id },
throw new Error("Could not find guild"); });
} if (!getGuild) throw new Error("Guild not found");
if (guildData.audits.status !== true) return;
if (!guildData.audits.channelId) { if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) {
throw new Error("Channel not found"); throw new Error("Channel not found");
} }
const embedConfig = await getEmbedConfig(guild); const embedConfig = await getEmbedConfig(guild);
const channel = client.channels.cache.get(guildData.audits.channelId); const channel = client.channels.cache.get(getGuild.auditsChannelId);
if (channel?.type !== ChannelType.GuildText) { if (channel?.type !== ChannelType.GuildText) {
throw new Error("Channel must be a text channel"); throw new Error("Channel must be a text channel");
} }

View file

@ -1,7 +1,7 @@
import { BaseInteraction, ChannelType, EmbedBuilder } from "discord.js"; import { BaseInteraction, ChannelType, EmbedBuilder } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import guildSchema from "../../models/guild";
export default { export default {
execute: async (interaction: BaseInteraction) => { execute: async (interaction: BaseInteraction) => {
@ -9,22 +9,21 @@ export default {
if (interaction.guild === null) return; if (interaction.guild === null) return;
const getGuild = await prisma.guild.findUnique({
where: { id: interaction.guild.id },
});
if (!getGuild) throw new Error("Guild not found");
const { footerText, footerIcon, successColor } = await getEmbedConfig( const { footerText, footerIcon, successColor } = await getEmbedConfig(
interaction.guild interaction.guild
); );
const guildData = await guildSchema.findOne({
guildId: interaction.guild.id,
});
const { client } = interaction; const { client } = interaction;
if (guildData === null) return; if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) return;
if (guildData.audits.status !== true) return; const channel = client.channels.cache.get(`${getGuild.auditsChannelId}`);
if (!guildData.audits.channelId) return;
const channel = client.channels.cache.get(`${guildData.audits.channelId}`);
if (!channel) return; if (!channel) return;
if (channel.type !== ChannelType.GuildText) return; if (channel.type !== ChannelType.GuildText) return;

View file

@ -1,7 +1,7 @@
import { ChannelType, EmbedBuilder, Message } from "discord.js"; import { ChannelType, EmbedBuilder, Message } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import guildSchema from "../../models/guild";
export default { export default {
execute: async (message: Message) => { execute: async (message: Message) => {
@ -13,18 +13,19 @@ export default {
message.guild message.guild
); );
const guildData = await guildSchema.findOne({ const getGuild = await prisma.guild.findUnique({
guildId: message.guild.id, where: { id: message.guild.id },
}); });
if (!getGuild) throw new Error("Guild not found");
const { client } = message; const { client } = message;
if (guildData === null) return; if (!getGuild) throw new Error("Guild not found");
if (guildData.audits.status !== true) return; if (getGuild.auditsEnabled !== true) return;
if (!guildData.audits.channelId) return; if (!getGuild.auditsChannelId) return;
const channel = client.channels.cache.get(`${guildData.audits.channelId}`); const channel = client.channels.cache.get(`${getGuild.auditsChannelId}`);
if (!channel) return; if (!channel) return;
if (channel.type !== ChannelType.GuildText) return; if (channel.type !== ChannelType.GuildText) return;

View file

@ -1,8 +1,8 @@
/* eslint-disable no-loops/no-loops */ /* eslint-disable no-loops/no-loops */
import { ChannelType, EmbedBuilder, Message } from "discord.js"; import { ChannelType, EmbedBuilder, Message } from "discord.js";
import prisma from "../../handlers/database";
import getEmbedConfig from "../../helpers/getEmbedData"; import getEmbedConfig from "../../helpers/getEmbedData";
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import guildSchema from "../../models/guild";
export default { export default {
execute: async (oldMessage: Message, newMessage: Message) => { execute: async (oldMessage: Message, newMessage: Message) => {
@ -16,18 +16,17 @@ export default {
newMessage.guild newMessage.guild
); );
const guildData = await guildSchema.findOne({ const getGuild = await prisma.guild.findUnique({
guildId: oldMessage.guild.id, where: { id: oldMessage.guild.id },
}); });
if (!getGuild) throw new Error("Guild not found");
const { client } = oldMessage; const { client } = oldMessage;
if (guildData === null) return; if (getGuild.auditsEnabled !== true) return;
if (!getGuild.auditsChannelId) return;
if (guildData.audits.status !== true) return; const channel = client.channels.cache.get(`${getGuild.auditsChannelId}`);
if (!guildData.audits.channelId) return;
const channel = client.channels.cache.get(`${guildData.audits.channelId}`);
if (!channel) return; if (!channel) return;
if (channel.type !== ChannelType.GuildText) return; if (channel.type !== ChannelType.GuildText) return;

View file

@ -1,142 +0,0 @@
import { ColorResolvable } from "discord.js";
import { model, Schema } from "mongoose";
interface IGuild {
guildId: string;
credits: {
status: boolean;
rate: number;
timeout: number;
workRate: number;
minimumLength: number;
workTimeout: number;
};
embeds: {
successColor: ColorResolvable;
waitColor: ColorResolvable;
errorColor: ColorResolvable;
footerIcon: string;
footerText: string;
};
shop: { roles: { status: boolean; pricePerHour: number } };
points: {
status: boolean;
rate: number;
minimumLength: number;
timeout: number;
};
welcome: {
status: boolean;
joinChannel: string;
leaveChannel: string;
joinChannelMessage: string;
leaveChannelMessage: string;
};
audits: { status: boolean; channelId: string };
}
const guildSchema = new Schema<IGuild>(
{
guildId: {
type: String,
required: true,
unique: true,
index: true,
},
credits: {
status: {
type: Boolean,
default: true,
},
rate: {
type: Number,
default: 1,
},
minimumLength: {
type: Number,
default: 5,
},
timeout: {
type: Number,
default: 5,
},
workRate: {
type: Number,
default: 15,
},
workTimeout: {
type: Number,
default: 900,
},
},
embeds: {
successColor: {
type: String,
default: "#22bb33",
},
waitColor: {
type: String,
default: "#f0ad4e",
},
errorColor: {
type: String,
default: "#bb2124",
},
footerText: {
type: String,
default: "https://github.com/ZynerOrg/xyter",
},
footerIcon: {
type: String,
default: "https://github.com/ZynerOrg.png",
},
},
shop: {
roles: {
status: {
type: Boolean,
default: false,
},
pricePerHour: {
type: Number,
default: 5,
},
},
},
points: {
status: {
type: Boolean,
default: false,
},
rate: {
type: Number,
default: 1,
},
minimumLength: {
type: Number,
default: 5,
},
timeout: {
type: Number,
default: 5,
},
},
welcome: {
status: {
type: Boolean,
default: false,
},
joinChannel: { type: String },
leaveChannel: { type: String },
joinChannelMessage: { type: String },
leaveChannelMessage: { type: String },
},
audits: {
status: { type: Boolean, default: false },
channelId: { type: String },
},
},
{ timestamps: true }
);
export default model<IGuild>("guild", guildSchema);

View file

@ -1,48 +0,0 @@
import { Snowflake } from "discord.js";
import { model, Schema } from "mongoose";
export interface IShopRole {
roleId: Snowflake;
userId: Snowflake;
guildId: Snowflake;
pricePerHour: number;
lastPayed: Date;
}
const shopRoleSchema = new Schema<IShopRole>(
{
roleId: {
type: String,
required: true,
unique: false,
index: true,
},
userId: {
type: String,
required: true,
unique: false,
index: true,
},
guildId: {
type: String,
required: true,
unique: false,
index: true,
},
pricePerHour: {
type: Number,
required: true,
unique: false,
index: true,
default: 5,
},
lastPayed: {
type: Date,
unique: false,
index: true,
},
},
{ timestamps: true }
);
export default model<IShopRole>("shopRole", shopRoleSchema);

View file

@ -1,38 +0,0 @@
import { Snowflake } from "discord.js";
import { model, Schema } from "mongoose";
export interface ITimeout {
userId: Snowflake;
guildId: Snowflake;
cooldown: number;
timeoutId: string;
createdAt: Date;
updatedAt: Date;
}
const timeoutSchema = new Schema<ITimeout>(
{
userId: {
type: String,
required: true,
unique: false,
index: true,
},
guildId: {
type: String,
required: true,
unique: false,
index: true,
},
cooldown: {
type: Number,
required: true,
unique: false,
index: true,
},
timeoutId: { type: String },
},
{ timestamps: true }
);
export default model<ITimeout>("timeout", timeoutSchema);

View file

@ -1,42 +0,0 @@
import { Snowflake } from "discord.js";
import { model, Schema } from "mongoose";
export interface IUser {
guildId: Snowflake;
userId: Snowflake;
language: string;
reputation: number;
credits: number;
level: number;
points: number;
updatedAt: Date;
createdAt: Date;
}
const userSchema = new Schema(
{
guildId: {
type: String,
required: true,
unique: false,
index: true,
},
userId: {
type: String,
required: true,
unique: false,
index: true,
},
language: {
type: String,
default: "en",
},
reputation: { type: Number, default: 0 },
credits: { type: Number, default: 0 },
level: { type: Number, default: 0 },
points: { type: Number, default: 0 },
},
{ timestamps: true }
);
export default model<IUser>("user", userSchema);

View file

@ -1,9 +1,9 @@
import { Client } from "discord.js"; import { Client } from "discord.js";
import logger from "../../../../../middlewares/logger"; import logger from "../../../../../middlewares/logger";
import { IShopRole } from "../../../../../interfaces/ShopRole"; import { GuildShopRoles } from "@prisma/client";
export const execute = async (_client: Client, role: IShopRole) => { export const execute = async (_client: Client, role: GuildShopRoles) => {
const { roleId } = role; const { roleId } = role;
logger.silly(`Shop role ${roleId} is not due for payment.`); logger.silly(`Shop role ${roleId} is not due for payment.`);

View file

@ -1,22 +1,14 @@
import { Client } from "discord.js"; import { Client } from "discord.js";
import logger from "../../../../../middlewares/logger"; import logger from "../../../../../middlewares/logger";
import { IShopRole } from "../../../../../interfaces/ShopRole"; import { GuildShopRoles } from "@prisma/client";
import guildSchema from "../../../../../models/guild"; import prisma from "../../../../../handlers/database";
import shopRoleSchema from "../../../../../models/shopRole";
import userSchema from "../../../../../models/user";
// Execute the component // Execute the component
export const execute = async (client: Client, role: IShopRole) => { export const execute = async (client: Client, role: GuildShopRoles) => {
const { guildId, userId, roleId } = role; const { guildId, userId, roleId } = role;
if (!userId) throw new Error("User ID not found for shop role."); if (!userId) throw new Error("User ID not found for shop role.");
const guildData = await guildSchema.findOne({ guildId });
if (!guildData) throw new Error("Guild not found.");
const userData = await userSchema.findOne({ guildId, userId });
if (!userData) throw new Error("User not found.");
const rGuild = client.guilds.cache.get(guildId); const rGuild = client.guilds.cache.get(guildId);
if (!rGuild) throw new Error("Guild not found."); if (!rGuild) throw new Error("Guild not found.");
@ -28,26 +20,44 @@ export const execute = async (client: Client, role: IShopRole) => {
logger.debug(`Shop role ${roleId} is due for payment.`); logger.debug(`Shop role ${roleId} is due for payment.`);
const { pricePerHour } = guildData.shop.roles; const getGuildMember = await prisma.guildMember.findUnique({
where: {
userId_guildId: {
userId,
guildId,
},
},
include: {
user: true,
guild: true,
},
});
if (userData.credits < pricePerHour) { logger.silly(getGuildMember);
if (!getGuildMember) throw new Error("Could not find guild member.");
const pricePerHour = getGuildMember.guild.shopRolesPricePerHour;
if (getGuildMember.creditsEarned < pricePerHour) {
await rMember.roles await rMember.roles
.remove(roleId) .remove(roleId)
.then(async () => { .then(async () => {
await shopRoleSchema const deleteShopRole = await prisma.guildShopRoles.delete({
.deleteOne({ where: {
userId, guildId_userId_roleId: {
roleId, guildId,
guildId, userId,
}) roleId,
.then(() => { },
logger.silly( },
`Shop role document ${roleId} has been deleted from user ${userId}.` });
);
}) logger.silly(deleteShopRole);
.catch(() => {
throw new Error("Failed deleting shop role from user."); logger.silly(
}); `Shop role document ${roleId} has been deleted from user ${userId}.`
);
}) })
.catch(() => { .catch(() => {
throw new Error(`Failed removing role from user.`); throw new Error(`Failed removing role from user.`);
@ -56,25 +66,63 @@ export const execute = async (client: Client, role: IShopRole) => {
throw new Error("User does not have enough credits."); throw new Error("User does not have enough credits.");
} }
userData.credits -= pricePerHour; const createGuildMember = await prisma.guildMember.upsert({
await userData where: {
.save() userId_guildId: {
.then(async () => { userId,
logger.silly(`User ${userId} has been updated.`); guildId,
},
},
update: { creditsEarned: { decrement: pricePerHour } },
create: {
creditsEarned: -pricePerHour,
user: {
connectOrCreate: {
create: {
id: userId,
},
where: {
id: userId,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guildId,
},
where: {
id: guildId,
},
},
},
},
include: {
user: true,
guild: true,
},
});
role.lastPayed = new Date(); logger.silly(createGuildMember);
await role
.save()
.then(() => {
logger.silly(`Shop role ${roleId} has been updated.`);
})
.catch(() => {
throw new Error("Failed updating shop role.");
});
logger.debug(`Shop role ${roleId} has been paid.`); logger.silly(`User ${userId} has been updated.`);
})
.catch(() => { const updateGuildShopRole = await prisma.guildShopRoles.update({
throw new Error("Failed updating user."); where: {
}); guildId_userId_roleId: {
guildId,
userId,
roleId,
},
},
data: {
lastPayed: new Date(),
},
});
logger.silly(updateGuildShopRole);
logger.silly(`Shop role ${roleId} has been updated.`);
logger.debug(`Shop role ${roleId} has been paid.`);
}; };

View file

@ -1,32 +1,27 @@
/* eslint-disable no-loops/no-loops */
import { Client } from "discord.js"; import { Client } from "discord.js";
import prisma from "../../../../handlers/database";
import { IShopRole } from "../../../../interfaces/ShopRole";
import shopRoleSchema from "../../../../models/shopRole";
import * as dueForPayment from "./components/dueForPayment"; import * as dueForPayment from "./components/dueForPayment";
import * as overDueForPayment from "./components/overDueForPayment"; import * as overDueForPayment from "./components/overDueForPayment";
export const execute = async (client: Client) => { export const execute = async (client: Client) => {
const roles = await shopRoleSchema.find(); const roles = await prisma.guildShopRoles.findMany();
await Promise.all( for await (const role of roles) {
roles.map(async (role: IShopRole) => { const { lastPayed } = role;
const { lastPayed } = role; const nextPayment = new Date(lastPayed.setHours(lastPayed.getHours() + 1));
const nextPayment = new Date(
lastPayed.setHours(lastPayed.getHours() + 1)
);
const now = new Date(); const now = new Date();
if (nextPayment > now) { if (nextPayment > now) {
await dueForPayment.execute(client, role); await dueForPayment.execute(client, role);
return; return;
} }
if (nextPayment < now) { if (nextPayment < now) {
await overDueForPayment.execute(client, role); await overDueForPayment.execute(client, role);
} }
}) }
);
}; };

View file

@ -1,36 +1,40 @@
/* eslint-disable no-loops/no-loops */
import logger from "../../middlewares/logger"; import logger from "../../middlewares/logger";
import timeoutSchema from "../../models/timeout";
import addSeconds from "../../helpers/addSeconds"; import addSeconds from "../../helpers/addSeconds";
import prisma from "../../handlers/database";
export const options = { export const options = {
schedule: "*/30 * * * *", // https://crontab.guru/ schedule: "*/30 * * * *", // https://crontab.guru/
}; };
// Execute the job // Execute the job
export const execute = async () => { export const execute = async () => {
const timeouts = await timeoutSchema.find(); const getCooldown = await prisma.cooldown.findMany();
await Promise.all(
timeouts.map(async (timeout) => {
const { guildId, userId, timeoutId, cooldown, createdAt } = timeout;
const overDue = (await addSeconds(cooldown, createdAt)) < new Date(); for await (const timeout of getCooldown) {
const { guildId, userId, timeoutId, cooldown, createdAt } = timeout;
if (overDue) { const overDue = (await addSeconds(cooldown, createdAt)) < new Date();
timeoutSchema
.deleteOne({ if (overDue) {
logger.info(timeout);
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId, guildId,
userId, userId,
timeoutId, timeoutId,
cooldown, },
}) },
.then(() => { });
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.` logger.silly(deleteCooldown);
);
}); logger.debug(
} `Timeout document ${timeoutId} has been deleted from user ${userId}.`
}) );
); }
}
}; };