Merge pull request 'fixes' (#79) from Backend_Fix into main

Reviewed-on: #79
This commit was merged in pull request #79.
This commit is contained in:
2025-10-27 19:22:59 +00:00
12 changed files with 24 additions and 59 deletions
@@ -1,7 +1,6 @@
import { DeckAggregate } from '../../../Domain/Deck/DeckAggregate'; import { DeckAggregate } from '../../../Domain/Deck/DeckAggregate';
import { UserAggregate } from '../../../Domain/User/UserAggregate'; import { UserAggregate } from '../../../Domain/User/UserAggregate';
import { CreateDeckDto, UpdateDeckDto, ShortDeckDto, DetailDeckDto } from '../DeckDto'; import { CreateDeckDto, UpdateDeckDto, ShortDeckDto, DetailDeckDto } from '../DeckDto';
import e from 'express';
export class DeckMapper { export class DeckMapper {
static toShortDto(deck: DeckAggregate, userId?: string): ShortDeckDto { static toShortDto(deck: DeckAggregate, userId?: string): ShortDeckDto {
@@ -22,7 +22,7 @@ export class OrganizationMapper {
contactemail: org.contactemail, contactemail: org.contactemail,
state: org.state, state: org.state,
regdate: org.regdate, regdate: org.regdate,
updatedate: org.updatedate, updateDate: org.updateDate,
url: org.url, url: org.url,
userinorg: org.userinorg, userinorg: org.userinorg,
maxOrganizationalDecks: org.maxOrganizationalDecks, maxOrganizationalDecks: org.maxOrganizationalDecks,
@@ -27,7 +27,7 @@ export interface DetailOrganizationDto {
contactemail: string; contactemail: string;
state: number; state: number;
regdate: Date; regdate: Date;
updatedate: Date; updateDate: Date;
url: string | null; url: string | null;
userinorg: number; userinorg: number;
maxOrganizationalDecks: number | null; maxOrganizationalDecks: number | null;
@@ -9,12 +9,12 @@ export class UpdateDeckCommandHandler {
constructor(private readonly deckRepo: IDeckRepository) {} constructor(private readonly deckRepo: IDeckRepository) {}
async execute(cmd: UpdateDeckCommand): Promise<ShortDeckDto | null> { async execute(cmd: UpdateDeckCommand): Promise<ShortDeckDto | null> {
if(cmd.state !== undefined && cmd.userstate!==1) { if(cmd.state !== undefined && cmd.authLevel!==1) {
throw new Error('Only admin users can change deck state'); throw new Error('Only admin users can change deck state');
} }
try { try {
let existingDeck: DeckAggregate | null = null; let existingDeck: DeckAggregate | null = null;
if (cmd.userstate === 1) { if (cmd.authLevel === 1) {
existingDeck = await this.deckRepo.findByIdIncludingDeleted(cmd.id); existingDeck = await this.deckRepo.findByIdIncludingDeleted(cmd.id);
} else { } else {
existingDeck = await this.deckRepo.findById(cmd.id); existingDeck = await this.deckRepo.findById(cmd.id);
@@ -86,7 +86,7 @@ export class LogoutCommandHandler {
// 5. Update user's last logout timestamp in database // 5. Update user's last logout timestamp in database
try { try {
const updateResult = await this.userRepo.update(userId, { updatedate: new Date() }); const updateResult = await this.userRepo.update(userId, { updateDate: new Date() });
if (updateResult) { if (updateResult) {
logAuth('User last logout timestamp updated', userId); logAuth('User last logout timestamp updated', userId);
} }
@@ -151,7 +151,7 @@ export class LogoutCommandHandler {
} }
// Update user logout timestamp // Update user logout timestamp
await this.userRepo.update(userId, { updatedate: new Date() }); await this.userRepo.update(userId, { updateDate: new Date() });
logAuth('User logged out from all devices', userId); logAuth('User logged out from all devices', userId);
return true; return true;
@@ -74,8 +74,8 @@ export class DeckAggregate {
@Column({ type: 'int', default: CType.PUBLIC }) @Column({ type: 'int', default: CType.PUBLIC })
ctype!: CType; ctype!: CType;
@UpdateDateColumn({ name: 'update_date' }) @UpdateDateColumn()
updatedate!: Date; updateDate!: Date;
@Column({ type: 'int', default: State.ACTIVE }) @Column({ type: 'int', default: State.ACTIVE })
state!: State; state!: State;
@@ -86,8 +86,8 @@ export class GameAggregate {
@Column({ type: 'timestamp', nullable: true, name: 'finishDate' }) @Column({ type: 'timestamp', nullable: true, name: 'finishDate' })
enddate!: Date | null; enddate!: Date | null;
@UpdateDateColumn({ name: 'updateDate' }) @UpdateDateColumn()
updatedate!: Date; updateDate!: Date;
} }
// Board Generation Types // Board Generation Types
@@ -35,8 +35,8 @@ export class OrganizationAggregate {
@CreateDateColumn() @CreateDateColumn()
regdate!: Date; regdate!: Date;
@UpdateDateColumn() @UpdateDateColumn({ name: 'updateDate' })
updatedate!: Date; updateDate!: Date;
@Column({ type: 'varchar', length: 500, nullable: true }) @Column({ type: 'varchar', length: 500, nullable: true })
url!: string | null; url!: string | null;
@@ -51,7 +51,7 @@ export class UserAggregate {
regdate!: Date; regdate!: Date;
@UpdateDateColumn() @UpdateDateColumn()
updatedate!: Date; updateDate!: Date;
@Column({ type: 'timestamp', nullable: true }) @Column({ type: 'timestamp', nullable: true })
Orglogindate!: Date | null; Orglogindate!: Date | null;
@@ -29,7 +29,7 @@ export class DeckRepository implements IDeckRepository {
// Get paginated results // Get paginated results
const decks = await this.repo.find({ const decks = await this.repo.find({
where: { state: Not(State.SOFT_DELETE) }, where: { state: Not(State.SOFT_DELETE) },
order: { updatedate: 'DESC' }, order: { updateDate: 'DESC' },
take: limit, take: limit,
skip: offset skip: offset
}); });
@@ -57,7 +57,7 @@ export class DeckRepository implements IDeckRepository {
// Get paginated results // Get paginated results
const decks = await this.repo.find({ const decks = await this.repo.find({
order: { updatedate: 'DESC' }, order: { updateDate: 'DESC' },
take: limit, take: limit,
skip: offset skip: offset
}); });
@@ -39,7 +39,7 @@ export class GameRepository implements IGameRepository {
// Get paginated results // Get paginated results
const games = await this.repo.find({ const games = await this.repo.find({
where: { state: Not(GameState.CANCELLED) }, where: { state: Not(GameState.CANCELLED) },
order: { updatedate: 'DESC' }, order: { updateDate: 'DESC' },
take: limit, take: limit,
skip: offset skip: offset
}); });
@@ -67,7 +67,7 @@ export class GameRepository implements IGameRepository {
// Get paginated results (including deleted) // Get paginated results (including deleted)
const games = await this.repo.find({ const games = await this.repo.find({
order: { updatedate: 'DESC' }, order: { updateDate: 'DESC' },
take: limit, take: limit,
skip: offset skip: offset
}); });
@@ -153,7 +153,7 @@ export class GameRepository implements IGameRepository {
queryBuilder.skip(offset); queryBuilder.skip(offset);
} }
const games = await queryBuilder.orderBy('game.updatedate', 'DESC').getMany(); const games = await queryBuilder.orderBy('game.updateDate', 'DESC').getMany();
const endTime = performance.now(); const endTime = performance.now();
logDatabase('Game search completed', `executionTime: ${Math.round(endTime - startTime)}ms, query: ${query}, found: ${games.length}, total: ${totalCount}`); logDatabase('Game search completed', `executionTime: ${Math.round(endTime - startTime)}ms, query: ${query}, found: ${games.length}, total: ${totalCount}`);
@@ -184,7 +184,7 @@ export class GameRepository implements IGameRepository {
queryBuilder.skip(offset); queryBuilder.skip(offset);
} }
const games = await queryBuilder.orderBy('game.updatedate', 'DESC').getMany(); const games = await queryBuilder.orderBy('game.updateDate', 'DESC').getMany();
const endTime = performance.now(); const endTime = performance.now();
logDatabase('Game search (including deleted) completed', `executionTime: ${Math.round(endTime - startTime)}ms, query: ${query}, found: ${games.length}, total: ${totalCount}`); logDatabase('Game search (including deleted) completed', `executionTime: ${Math.round(endTime - startTime)}ms, query: ${query}, found: ${games.length}, total: ${totalCount}`);
@@ -251,7 +251,7 @@ export class GameRepository implements IGameRepository {
try { try {
const games = await this.repo.find({ const games = await this.repo.find({
where: { state: GameState.ACTIVE }, where: { state: GameState.ACTIVE },
order: { updatedate: 'DESC' } order: { updateDate: 'DESC' }
}); });
const endTime = performance.now(); const endTime = performance.now();
logDatabase('Active games query completed', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${games.length}`); logDatabase('Active games query completed', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${games.length}`);
@@ -270,7 +270,7 @@ export class GameRepository implements IGameRepository {
const queryBuilder = this.repo.createQueryBuilder('game') const queryBuilder = this.repo.createQueryBuilder('game')
.where('game.state != :cancelledState', { cancelledState: GameState.CANCELLED }) .where('game.state != :cancelledState', { cancelledState: GameState.CANCELLED })
.andWhere('JSON_CONTAINS(game.players, :playerId)', { playerId: `"${playerId}"` }) .andWhere('JSON_CONTAINS(game.players, :playerId)', { playerId: `"${playerId}"` })
.orderBy('game.updatedate', 'DESC'); .orderBy('game.updateDate', 'DESC');
const games = await queryBuilder.getMany(); const games = await queryBuilder.getMany();
const endTime = performance.now(); const endTime = performance.now();
+3 -37
View File
@@ -19,7 +19,7 @@ CREATE TABLE "Users" (
"phone" VARCHAR(20) NULL, "phone" VARCHAR(20) NULL,
"state" INTEGER NOT NULL DEFAULT 0, "state" INTEGER NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"Orglogindate" TIMESTAMP NULL "Orglogindate" TIMESTAMP NULL
); );
@@ -33,7 +33,7 @@ CREATE TABLE "Organizations" (
"contactemail" VARCHAR(255) NOT NULL, "contactemail" VARCHAR(255) NOT NULL,
"state" INTEGER NOT NULL DEFAULT 0, "state" INTEGER NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"url" VARCHAR(500) NULL, "url" VARCHAR(500) NULL,
"userinorg" INTEGER NOT NULL DEFAULT 0, "userinorg" INTEGER NOT NULL DEFAULT 0,
"maxOrganizationalDecks" INTEGER NULL "maxOrganizationalDecks" INTEGER NULL
@@ -49,7 +49,7 @@ CREATE TABLE "Decks" (
"cards" JSONB NOT NULL DEFAULT '[]', "cards" JSONB NOT NULL DEFAULT '[]',
"played_number" INTEGER NOT NULL DEFAULT 0, "played_number" INTEGER NOT NULL DEFAULT 0,
"ctype" INTEGER NOT NULL DEFAULT 0, "ctype" INTEGER NOT NULL DEFAULT 0,
"update_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"state" INTEGER NOT NULL DEFAULT 0, "state" INTEGER NOT NULL DEFAULT 0,
"organization_id" UUID NULL "organization_id" UUID NULL
); );
@@ -174,40 +174,6 @@ CREATE INDEX "IDX_Games_State" ON "Games" ("state");
CREATE INDEX "IDX_Games_CreatedBy" ON "Games" ("createdBy"); CREATE INDEX "IDX_Games_CreatedBy" ON "Games" ("createdBy");
CREATE INDEX "IDX_Games_OrganizationId" ON "Games" ("organizationid"); CREATE INDEX "IDX_Games_OrganizationId" ON "Games" ("organizationid");
-- Create update trigger for updatedate columns
CREATE OR REPLACE FUNCTION update_updatedate_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updatedate = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
-- Apply update triggers
CREATE TRIGGER update_users_updatedate
BEFORE UPDATE ON "Users"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_organizations_updatedate
BEFORE UPDATE ON "Organizations"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_decks_updatedate
BEFORE UPDATE ON "Decks"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_chats_updatedate
BEFORE UPDATE ON "Chats"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_contacts_updatedate
BEFORE UPDATE ON "Contacts"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_games_updatedate
BEFORE UPDATE ON "Games"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
-- Comments for documentation -- Comments for documentation
COMMENT ON TABLE "Users" IS 'User accounts with authentication and profile information'; COMMENT ON TABLE "Users" IS 'User accounts with authentication and profile information';
COMMENT ON TABLE "Organizations" IS 'Organizations that can have multiple users and premium features'; COMMENT ON TABLE "Organizations" IS 'Organizations that can have multiple users and premium features';