Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified prisma/dev.db
Binary file not shown.
Binary file added prisma/dev.db-journal
Binary file not shown.
9 changes: 9 additions & 0 deletions prisma/migrations/20250414211601_config_model/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- CreateTable
CREATE TABLE "Config" (
"guild_id" TEXT NOT NULL PRIMARY KEY,
"setting_type" TEXT NOT NULL,
"value" TEXT NOT NULL
);

-- CreateIndex
CREATE INDEX "Config_guild_id_setting_type_idx" ON "Config"("guild_id", "setting_type");
21 changes: 21 additions & 0 deletions prisma/migrations/20250414212408_update_config_id/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Warnings:

- The primary key for the `Config` table will be changed. If it partially fails, the table could be left without primary key constraint.

*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Config" (
"guild_id" TEXT NOT NULL,
"setting_type" TEXT NOT NULL,
"value" TEXT NOT NULL,

PRIMARY KEY ("guild_id", "setting_type")
);
INSERT INTO "new_Config" ("guild_id", "setting_type", "value") SELECT "guild_id", "setting_type", "value" FROM "Config";
DROP TABLE "Config";
ALTER TABLE "new_Config" RENAME TO "Config";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Warnings:

- The primary key for the `Config` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `guild_id` on the `Config` table. All the data in the column will be lost.
- You are about to drop the column `setting_type` on the `Config` table. All the data in the column will be lost.
- Added the required column `guildId` to the `Config` table without a default value. This is not possible if the table is not empty.
- Added the required column `settingType` to the `Config` table without a default value. This is not possible if the table is not empty.

*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Config" (
"guildId" TEXT NOT NULL,
"settingType" TEXT NOT NULL,
"value" TEXT NOT NULL,

PRIMARY KEY ("guildId", "settingType")
);
INSERT INTO "new_Config" ("value") SELECT "value" FROM "Config";
DROP TABLE "Config";
ALTER TABLE "new_Config" RENAME TO "Config";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
80 changes: 44 additions & 36 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,28 @@ model DiscordUser {
username String
discriminator String?
avatar String?
roles String // Stored as JSON string of role IDs
roles String // Stored as JSON string of role IDs
joinedAt DateTime @default(now())
lastSeen DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

// Relations
teams TeamMember[]
events EventParticipant[]
teamsLed Team[] // Teams where this user is the leader
submissions Submission[]
teams TeamMember[]
events EventParticipant[]
teamsLed Team[] // Teams where this user is the leader
submissions Submission[]
}

model Event {
id String @id @default(uuid())
id String @id @default(uuid())
name String
description String?
startDate DateTime
endDate DateTime?
status String @default("PLANNED") // PLANNED, ONGOING, COMPLETED, CANCELLED
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
status String @default("PLANNED") // PLANNED, ONGOING, COMPLETED, CANCELLED
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

// Relations
participants EventParticipant[]
Expand All @@ -48,7 +48,7 @@ model Team {
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
leaderId String // ID of the team leader
leaderId String // ID of the team leader
leader DiscordUser @relation(fields: [leaderId], references: [id])

// Relations
Expand All @@ -59,46 +59,54 @@ model Team {

// Junction tables for many-to-many relationships
model TeamMember {
id String @id @default(uuid())
userId String
teamId String
role String @default("MEMBER") // LEADER, MEMBER, etc.
joinedAt DateTime @default(now())
user DiscordUser @relation(fields: [userId], references: [id])
team Team @relation(fields: [teamId], references: [id])
id String @id @default(uuid())
userId String
teamId String
role String @default("MEMBER") // LEADER, MEMBER, etc.
joinedAt DateTime @default(now())
user DiscordUser @relation(fields: [userId], references: [id])
team Team @relation(fields: [teamId], references: [id])

@@unique([userId, teamId])
}

model EventParticipant {
id String @id @default(uuid())
userId String
eventId String
status String @default("REGISTERED") // REGISTERED, INTERESTED, UNPAID
user DiscordUser @relation(fields: [userId], references: [id])
event Event @relation(fields: [eventId], references: [id])
id String @id @default(uuid())
userId String
eventId String
status String @default("REGISTERED") // REGISTERED, INTERESTED, UNPAID
user DiscordUser @relation(fields: [userId], references: [id])
event Event @relation(fields: [eventId], references: [id])

@@unique([userId, eventId])
}

model Submission {
id String @id @default(uuid())
name String // Name of the submitted item
value String // Value of the submitted item
proofUrl String // URL to the proof image
status String @default("PENDING") // PENDING, APPROVED, REJECTED
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id String @id @default(uuid())
name String // Name of the submitted item
value String // Value of the submitted item
proofUrl String // URL to the proof image
status String @default("PENDING") // PENDING, APPROVED, REJECTED
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

// Relations
userId String // ID of the user who submitted
eventId String // ID of the event this submission is for
teamId String // ID of the team this submission belongs to
user DiscordUser @relation(fields: [userId], references: [id])
event Event @relation(fields: [eventId], references: [id])
team Team @relation(fields: [teamId], references: [id])
userId String // ID of the user who submitted
eventId String // ID of the event this submission is for
teamId String // ID of the team this submission belongs to
user DiscordUser @relation(fields: [userId], references: [id])
event Event @relation(fields: [eventId], references: [id])
team Team @relation(fields: [teamId], references: [id])

@@index([userId])
@@index([eventId])
@@index([teamId])
}

model Config {
guildId String
settingType String
value String

@@id([guildId, settingType])
}
4 changes: 4 additions & 0 deletions src/constants/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const SettingTypes = {
APPROVAL_CHANNEL: 'approval_channel',
ADMIN_ROLE: 'admin_role',
};
135 changes: 135 additions & 0 deletions src/services/configService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import prisma from '#utils/prisma.js';
import logger from '#utils/logger.js';
import { SettingTypes } from '#constants/settings.js';

export class ConfigService {
/**
* Get the approval channel for a guild
* @param {String} guildId - A Discord guild ID
* @returns {Promise<String>} The approval channel ID
*/
static async getApprovalChannel(guildId) {
try {
const config = await prisma.config.findUnique({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.APPROVAL_CHANNEL,
},
},
});

return config?.value;
} catch (error) {
logger.error(`Error getting approval channel for guild ${guildId}:`, error);
throw error;
}
}

/**
* Set the approval channel for a guild
* @param {String} guildId - A Discord guild ID
* @param {String} channelId - The approval channel ID
* @returns {Promise<void>}
*/
static async setApprovalChannel(guildId, channelId) {
try {
const existingConfig = await prisma.config.findUnique({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.APPROVAL_CHANNEL,
},
},
});

if (existingConfig) {
await prisma.config.update({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.APPROVAL_CHANNEL,
},
},
data: { value: channelId },
});
} else {
await prisma.config.create({
data: {
guildId,
settingType: SettingTypes.APPROVAL_CHANNEL,
value: channelId,
},
});
}
} catch (error) {
logger.error(`Error setting approval channel for guild ${guildId}:`, error);
throw error;
}
}

/**
* Get the admin role for a guild
* @param {String} guildId - A Discord guild ID
* @returns {Promise<String>} The admin role ID
*/
static async getAdminRole(guildId) {
try {
const config = await prisma.config.findUnique({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.ADMIN_ROLE,
},
},
});

return config?.value;
} catch (error) {
logger.error(`Error getting admin role for guild ${guildId}:`, error);
throw error;
}
}

/**
* Set the admin role for a guild
* @param {String} guildId - A Discord guild ID
* @param {String} roleId - The admin role ID
* @returns {Promise<void>}
*/
static async setAdminRole(guildId, roleId) {
try {
const existingConfig = await prisma.config.findUnique({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.ADMIN_ROLE,
},
},
});

if (existingConfig) {
await prisma.config.update({
where: {
guildId_settingType: {
guildId,
settingType: SettingTypes.ADMIN_ROLE,
},
},
data: { value: roleId },
});
} else {
await prisma.config.create({
data: {
guildId,
settingType: SettingTypes.ADMIN_ROLE,
value: roleId,
},
});
}
} catch (error) {
logger.error(`Error setting admin role for guild ${guildId}:`, error);
throw error;
}
}
}
4 changes: 1 addition & 3 deletions src/services/userService.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { PrismaClient } from '@prisma/client';
import prisma from '#utils/prisma.js';
import logger from '#utils/logger.js';

const prisma = new PrismaClient();

export class UserService {
/**
* Sync a Discord member to the database
Expand Down
5 changes: 5 additions & 0 deletions src/utils/prisma.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default prisma;
5 changes: 0 additions & 5 deletions utils/db.js

This file was deleted.