Merge remote-tracking branch 'origin/main' into backend_complete

This commit is contained in:
2025-09-21 03:49:22 +02:00
1039 changed files with 80635 additions and 19 deletions
@@ -21,6 +21,10 @@ export class UserMapper {
fname: user.fname,
lname: user.lname,
code: user.token,
<<<<<<< HEAD
=======
type: user.type,
>>>>>>> origin/main
phone: user.phone,
state: user.state,
};
@@ -24,6 +24,10 @@ export interface DetailUserDto {
fname: string;
lname: string;
code: string | null;
<<<<<<< HEAD
=======
type: string;
>>>>>>> origin/main
phone: string | null;
state: number;
}
@@ -1,6 +1,9 @@
export interface UpdateDeckCommand {
id: string;
<<<<<<< HEAD
userstate?: number;
=======
>>>>>>> origin/main
name?: string;
type?: number;
userid?: string;
@@ -2,13 +2,17 @@ import { IDeckRepository } from '../../../Domain/IRepository/IDeckRepository';
import { UpdateDeckCommand } from './UpdateDeckCommand';
import { ShortDeckDto } from '../../DTOs/DeckDto';
import { DeckMapper } from '../../DTOs/Mappers/DeckMapper';
<<<<<<< HEAD
import { DeckAggregate } from '../../../Domain/Deck/DeckAggregate';
import { logError } from '../../Services/Logger';
=======
>>>>>>> origin/main
export class UpdateDeckCommandHandler {
constructor(private readonly deckRepo: IDeckRepository) {}
async execute(cmd: UpdateDeckCommand): Promise<ShortDeckDto | null> {
<<<<<<< HEAD
if(cmd.state !== undefined && cmd.userstate!==1) {
throw new Error('Only admin users can change deck state');
}
@@ -46,5 +50,10 @@ export class UpdateDeckCommandHandler {
logError(`Error updating deck: ${cmd.id}`, error);
throw error;
}
=======
const updated = await this.deckRepo.update(cmd.id, { ...cmd });
if (!updated) return null;
return DeckMapper.toShortDto(updated);
>>>>>>> origin/main
}
}
@@ -1,14 +1,25 @@
import { IDeckRepository } from '../../../Domain/IRepository/IDeckRepository';
import { GetDeckByIdQuery } from './GetDeckByIdQuery';
<<<<<<< HEAD
import { DetailDeckDto } from '../../DTOs/DeckDto';
=======
import { ShortDeckDto } from '../../DTOs/DeckDto';
>>>>>>> origin/main
import { DeckMapper } from '../../DTOs/Mappers/DeckMapper';
export class GetDeckByIdQueryHandler {
constructor(private readonly deckRepo: IDeckRepository) {}
<<<<<<< HEAD
async execute(query: GetDeckByIdQuery): Promise<DetailDeckDto | null> {
const deck = await this.deckRepo.findById(query.id);
if (!deck) return null;
return DeckMapper.toDetailDto(deck);
=======
async execute(query: GetDeckByIdQuery): Promise<ShortDeckDto | null> {
const deck = await this.deckRepo.findById(query.id);
if (!deck) return null;
return DeckMapper.toShortDto(deck);
>>>>>>> origin/main
}
}
@@ -49,6 +49,7 @@ export class GeneralSearchService implements IGeneralSearchService {
};
}
<<<<<<< HEAD
// Ensure limit is at least 1 to prevent database issues
const effectiveLimit = Math.max(limit || 20, 1);
const effectiveOffset = Math.max(offset || 0, 0);
@@ -57,6 +58,12 @@ export class GeneralSearchService implements IGeneralSearchService {
const { users, totalCount } = await this.userRepo.search(query.trim(), effectiveLimit, effectiveOffset);
const results = users.map(user => UserMapper.toShortDto(user));
const hasMore = (effectiveOffset + effectiveLimit) < totalCount;
=======
try {
const { users, totalCount } = await this.userRepo.search(query.trim(), limit, offset);
const results = users.map(user => UserMapper.toShortDto(user));
const hasMore = (offset + limit) < totalCount;
>>>>>>> origin/main
return {
results,
@@ -109,6 +116,7 @@ export class GeneralSearchService implements IGeneralSearchService {
};
}
<<<<<<< HEAD
// Ensure limit is at least 1 to prevent database issues
const effectiveLimit = Math.max(limit || 20, 1);
const effectiveOffset = Math.max(offset || 0, 0);
@@ -128,6 +136,19 @@ export class GeneralSearchService implements IGeneralSearchService {
} catch (error) {
throw new Error('Failed to search decks');
}
=======
const { decks, totalCount } = await this.deckRepo.search(query.trim(), limit, offset);
const results = decks.map(deck => DeckMapper.toShortDto(deck));
const hasMore = (offset + limit) < totalCount;
return {
results,
totalCount,
hasMore,
searchQuery: query,
searchType: 'decks'
};
>>>>>>> origin/main
}
async searchByType(
@@ -1,5 +1,6 @@
import { Request, Response, NextFunction } from 'express';
import { JWTService } from './JWTService';
<<<<<<< HEAD
import { RedisService } from './RedisService';
import { logAuth, logWarning } from './Logger';
@@ -143,4 +144,60 @@ export async function adminRequired(req: Request, res: Response, next: NextFunct
logWarning('Admin authentication middleware error', { error: (error as Error).message }, req);
return res.status(500).json({ error: 'Internal server error' });
}
=======
import { logAuth, logWarning } from './Logger';
export const jwtService = new JWTService();
export function authRequired(req: Request, res: Response, next: NextFunction) {
const payload = jwtService.verify(req);
if (!payload) {
logAuth('Authentication failed - No valid token', undefined, {
ip: req.ip,
userAgent: req.get ? req.get('User-Agent') : 'unknown',
path: req.path
}, req);
return res.status(401).json({ error: 'Unauthorized' });
}
logAuth('Authentication successful', payload.userId, {
authLevel: payload.authLevel,
orgId: payload.orgId
}, req);
const refreshed = jwtService.refreshIfNeeded(payload, res);
if (refreshed) {
logAuth('Token refreshed', payload.userId, undefined, req);
}
(req as any).user = payload;
next();
}
export function adminRequired(req: Request, res: Response, next: NextFunction) {
const payload = jwtService.verify(req);
if (!payload || payload.authLevel !== 1) {
logWarning('Admin access denied', {
hasPayload: !!payload,
authLevel: payload?.authLevel,
userId: payload?.userId,
ip: req.ip,
path: req.path
}, req);
return res.status(403).json({ error: 'Forbidden' });
}
logAuth('Admin authentication successful', payload.userId, {
authLevel: payload.authLevel,
orgId: payload.orgId
}, req);
const refreshed = jwtService.refreshIfNeeded(payload, res);
if (refreshed) {
logAuth('Admin token refreshed', payload.userId, undefined, req);
}
(req as any).user = payload;
next();
>>>>>>> origin/main
}