From d5c7cd0294cf668d38bb26b7dccd9ec7c896c970 Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Sat, 23 Nov 2024 15:30:11 +0100 Subject: [PATCH] Added CRUD logic for character hair, made some minor improvements, npm update --- package-lock.json | 18 +++---- .../20241123140835_lol/migration.sql | 2 + .../20241123141319_lol2/migration.sql | 2 + prisma/schema/user.prisma | 12 +++-- src/repositories/characterHairRepository.ts | 10 ++++ .../character/characterScreen/list_hair.ts | 0 .../assetManager/characterHair/create.ts | 37 ++++++++++++++ .../assetManager/characterHair/delete.ts | 40 +++++++++++++++ .../assetManager/characterHair/list.ts | 36 +++++++++++++ .../assetManager/characterHair/update.ts | 51 +++++++++++++++++++ .../assetManager/characterType/delete.ts | 2 - 11 files changed, 194 insertions(+), 16 deletions(-) create mode 100644 prisma/migrations/20241123140835_lol/migration.sql create mode 100644 prisma/migrations/20241123141319_lol2/migration.sql create mode 100644 src/repositories/characterHairRepository.ts create mode 100644 src/socketEvents/character/characterScreen/list_hair.ts create mode 100644 src/socketEvents/gameMaster/assetManager/characterHair/create.ts create mode 100644 src/socketEvents/gameMaster/assetManager/characterHair/delete.ts create mode 100644 src/socketEvents/gameMaster/assetManager/characterHair/list.ts create mode 100644 src/socketEvents/gameMaster/assetManager/characterHair/update.ts diff --git a/package-lock.json b/package-lock.json index b7b432f..02fc17b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -729,9 +729,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", - "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", + "version": "20.17.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.7.tgz", + "integrity": "sha512-sZXXnpBFMKbao30dUAvzKbdwA2JM1fwUtVEq/kxKuPI5mMwZiRElCpTXb0Biq/LMEVpXDZL5G5V0RPnxKeyaYg==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -949,9 +949,9 @@ "license": "BSD-3-Clause" }, "node_modules/bullmq": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.28.1.tgz", - "integrity": "sha512-iSoqziPLKH//mmoc4Aj3/opTmk1PgFdITwUrx/wDqrTxfBRjnTGInsu129LCEY6d+SmhZWnA9PYU6ciX+NT64A==", + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.29.1.tgz", + "integrity": "sha512-TZWiwRlPnpaN+Qwh4D8IQf2cYLpkiDX1LbaaWEabc6y37ojIttWOSynxDewpVHyW233LssSIC4+aLMSvAjtpmg==", "license": "MIT", "dependencies": { "cron-parser": "^4.6.0", @@ -2774,9 +2774,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/prisma/migrations/20241123140835_lol/migration.sql b/prisma/migrations/20241123140835_lol/migration.sql new file mode 100644 index 0000000..584f083 --- /dev/null +++ b/prisma/migrations/20241123140835_lol/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `CharacterHair` ADD COLUMN `gender` ENUM('MALE', 'FEMALE') NOT NULL DEFAULT 'MALE'; diff --git a/prisma/migrations/20241123141319_lol2/migration.sql b/prisma/migrations/20241123141319_lol2/migration.sql new file mode 100644 index 0000000..8b026a2 --- /dev/null +++ b/prisma/migrations/20241123141319_lol2/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `CharacterHair` ADD COLUMN `isEnabledForCharCreation` BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema/user.prisma b/prisma/schema/user.prisma index 017b8eb..f55eea6 100644 --- a/prisma/schema/user.prisma +++ b/prisma/schema/user.prisma @@ -43,11 +43,13 @@ model CharacterType { } model CharacterHair { - id Int @id @default(autoincrement()) - name String - sprite Sprite? @relation(fields: [spriteId], references: [id], onDelete: Cascade) - spriteId String? - characters Character[] + id Int @id @default(autoincrement()) + name String + gender CharacterGender @default(MALE) + isEnabledForCharCreation Boolean @default(false) + sprite Sprite? @relation(fields: [spriteId], references: [id], onDelete: Cascade) + spriteId String? + characters Character[] // @TODO: Do we need addedAt and updatedAt? } diff --git a/src/repositories/characterHairRepository.ts b/src/repositories/characterHairRepository.ts new file mode 100644 index 0000000..e4eeaa2 --- /dev/null +++ b/src/repositories/characterHairRepository.ts @@ -0,0 +1,10 @@ +import prisma from '../utilities/prisma' // Import the global Prisma instance +import { CharacterHair } from '@prisma/client' + +class CharacterHairRepository { + async getAll(): Promise { + return prisma.characterHair.findMany() + } +} + +export default new CharacterHairRepository() diff --git a/src/socketEvents/character/characterScreen/list_hair.ts b/src/socketEvents/character/characterScreen/list_hair.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/socketEvents/gameMaster/assetManager/characterHair/create.ts b/src/socketEvents/gameMaster/assetManager/characterHair/create.ts new file mode 100644 index 0000000..491ace7 --- /dev/null +++ b/src/socketEvents/gameMaster/assetManager/characterHair/create.ts @@ -0,0 +1,37 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../../utilities/types' +import prisma from '../../../../utilities/prisma' +import characterRepository from '../../../../repositories/characterRepository' + +export default class CharacterHairCreateEvent { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('gm:characterHair:create', this.handleEvent.bind(this)) + } + + private async handleEvent(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise { + try { + const character = await characterRepository.getById(this.socket.characterId as number) + if (!character) return callback(false) + + if (character.role !== 'gm') { + return callback(false) + } + + const newCharacterHair = await prisma.characterHair.create({ + data: { + name: 'New hair' + } + }) + + callback(true, newCharacterHair) + } catch (error) { + console.error('Error creating character hair:', error) + callback(false) + } + } +} diff --git a/src/socketEvents/gameMaster/assetManager/characterHair/delete.ts b/src/socketEvents/gameMaster/assetManager/characterHair/delete.ts new file mode 100644 index 0000000..5791125 --- /dev/null +++ b/src/socketEvents/gameMaster/assetManager/characterHair/delete.ts @@ -0,0 +1,40 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../../utilities/types' +import prisma from '../../../../utilities/prisma' +import characterRepository from '../../../../repositories/characterRepository' +import { gameMasterLogger } from '../../../../utilities/logger' + +interface IPayload { + id: number +} + +export default class characterHairDeleteEvent { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('gm:characterHair:remove', this.handleEvent.bind(this)) + } + + private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise { + const character = await characterRepository.getById(this.socket.characterId as number) + if (!character) return callback(false) + + if (character.role !== 'gm') { + return callback(false) + } + + try { + await prisma.characterHair.delete({ + where: { id: data.id } + }) + + callback(true) + } catch (error) { + gameMasterLogger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`) + callback(false) + } + } +} diff --git a/src/socketEvents/gameMaster/assetManager/characterHair/list.ts b/src/socketEvents/gameMaster/assetManager/characterHair/list.ts new file mode 100644 index 0000000..2a06b15 --- /dev/null +++ b/src/socketEvents/gameMaster/assetManager/characterHair/list.ts @@ -0,0 +1,36 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../../utilities/types' +import { CharacterHair } from '@prisma/client' +import characterRepository from '../../../../repositories/characterRepository' +import { gameMasterLogger } from '../../../../utilities/logger' +import characterHairRepository from '../../../../repositories/characterHairRepository' + +interface IPayload {} + +export default class characterHairListEvent { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('gm:characterHair:list', this.handleEvent.bind(this)) + } + + private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise { + const character = await characterRepository.getById(this.socket.characterId as number) + if (!character) { + gameMasterLogger.error('gm:characterHair:list error', 'Character not found') + return callback([]) + } + + if (character.role !== 'gm') { + gameMasterLogger.info(`User ${character.id} tried to list character hair but is not a game master.`) + return callback([]) + } + + // get all objects + const items = await characterHairRepository.getAll() + callback(items) + } +} diff --git a/src/socketEvents/gameMaster/assetManager/characterHair/update.ts b/src/socketEvents/gameMaster/assetManager/characterHair/update.ts new file mode 100644 index 0000000..9219e59 --- /dev/null +++ b/src/socketEvents/gameMaster/assetManager/characterHair/update.ts @@ -0,0 +1,51 @@ +import { Server } from 'socket.io' +import { TSocket } from '../../../../utilities/types' +import prisma from '../../../../utilities/prisma' +import characterRepository from '../../../../repositories/characterRepository' +import { CharacterGender, CharacterRace } from '@prisma/client' +import { gameMasterLogger } from '../../../../utilities/logger' + +type Payload = { + id: number + name: string + gender: CharacterGender + isEnabledForCharCreation: boolean + spriteId: string +} + +export default class CharacterHairUpdateEvent { + constructor( + private readonly io: Server, + private readonly socket: TSocket + ) {} + + public listen(): void { + this.socket.on('gm:characterHair:update', this.handleObjectUpdate.bind(this)) + } + + private async handleObjectUpdate(data: Payload, callback: (success: boolean) => void): Promise { + const character = await characterRepository.getById(this.socket.characterId as number) + if (!character) return callback(false) + + if (character.role !== 'gm') { + return callback(false) + } + + try { + await prisma.characterHair.update({ + where: { id: data.id }, + data: { + name: data.name, + gender: data.gender, + isEnabledForCharCreation: data.isEnabledForCharCreation, + spriteId: data.spriteId + } + }) + + return callback(true) + } catch (error) { + gameMasterLogger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`) + return callback(false) + } + } +} diff --git a/src/socketEvents/gameMaster/assetManager/characterType/delete.ts b/src/socketEvents/gameMaster/assetManager/characterType/delete.ts index 17567d2..abcbc8d 100644 --- a/src/socketEvents/gameMaster/assetManager/characterType/delete.ts +++ b/src/socketEvents/gameMaster/assetManager/characterType/delete.ts @@ -1,9 +1,7 @@ -import fs from 'fs' import { Server } from 'socket.io' import { TSocket } from '../../../../utilities/types' import prisma from '../../../../utilities/prisma' import characterRepository from '../../../../repositories/characterRepository' -import { getPublicPath } from '../../../../utilities/storage' import { gameMasterLogger } from '../../../../utilities/logger' interface IPayload {