final changes
This commit is contained in:
@@ -107,41 +107,6 @@ router.get('/users/page/:from/:to', adminRequired, async (req: Request, res: Res
|
||||
}
|
||||
});
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// Get users by page (admin only) - RECOMMENDED
|
||||
router.get('/users/page/:from/:to', adminRequired, async (req: Request, res: Response) => {
|
||||
try {
|
||||
const from = parseInt(req.params.from);
|
||||
const to = parseInt(req.params.to);
|
||||
const includeDeleted = req.query.includeDeleted === 'true';
|
||||
|
||||
if (isNaN(from) || isNaN(to) || from < 0 || to < from) {
|
||||
return res.status(400).json({ error: 'Invalid page parameters. "from" and "to" must be valid numbers with to >= from >= 0' });
|
||||
}
|
||||
|
||||
logRequest('Admin get users by page endpoint accessed', req, res, { from, to, includeDeleted });
|
||||
|
||||
const result = includeDeleted
|
||||
? await container.userRepository.findByPageIncludingDeleted(from, to)
|
||||
: await container.userRepository.findByPage(from, to);
|
||||
|
||||
logRequest('Admin users page retrieved successfully', req, res, {
|
||||
from,
|
||||
to,
|
||||
count: result.users.length,
|
||||
total: result.totalCount,
|
||||
includeDeleted
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logError('Admin get users by page endpoint error', error as Error, req, res);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
>>>>>>> origin/main
|
||||
// Get user by ID including soft-deleted ones
|
||||
router.get('/users/:userId',
|
||||
adminRequired,
|
||||
@@ -176,7 +141,6 @@ router.get('/users/:userId',
|
||||
});
|
||||
|
||||
// Search users including soft-deleted ones
|
||||
<<<<<<< HEAD
|
||||
// router.get('/users/search/:searchTerm',
|
||||
// adminRequired,
|
||||
// ValidationMiddleware.validateStringLength({ searchTerm: { min: 2, max: 100 } }),
|
||||
@@ -203,34 +167,6 @@ router.get('/users/:userId',
|
||||
// res.status(500).json({ error: 'Internal server error' });
|
||||
// }
|
||||
// });
|
||||
=======
|
||||
router.get('/users/search/:searchTerm',
|
||||
adminRequired,
|
||||
ValidationMiddleware.validateStringLength({ searchTerm: { min: 2, max: 100 } }),
|
||||
async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { searchTerm } = req.params;
|
||||
const includeDeleted = req.query.includeDeleted === 'true';
|
||||
|
||||
logRequest('Admin search users endpoint accessed', req, res, { searchTerm, includeDeleted });
|
||||
|
||||
const users = includeDeleted
|
||||
? await container.userRepository.searchIncludingDeleted(searchTerm)
|
||||
: await container.userRepository.search(searchTerm);
|
||||
|
||||
logRequest('Admin user search completed', req, res, {
|
||||
searchTerm,
|
||||
resultCount: Array.isArray(users) ? users.length : (users.totalCount || 0),
|
||||
includeDeleted
|
||||
});
|
||||
|
||||
res.json(users);
|
||||
} catch (error) {
|
||||
logError('Admin search users endpoint error', error as Error, req, res);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
>>>>>>> origin/main
|
||||
|
||||
// Update any user (admin only)
|
||||
router.patch('/users/:userId',
|
||||
@@ -422,7 +358,6 @@ router.get('/decks/search/:searchTerm', adminRequired, async (req: Request, res:
|
||||
}
|
||||
});
|
||||
|
||||
<<<<<<< HEAD
|
||||
//modify deck (admin only)
|
||||
router.patch('/decks/:id', adminRequired, async (req: Request, res: Response) => {
|
||||
try {
|
||||
@@ -447,8 +382,6 @@ router.patch('/decks/:id', adminRequired, async (req: Request, res: Response) =>
|
||||
}
|
||||
});
|
||||
|
||||
=======
|
||||
>>>>>>> origin/main
|
||||
// Hard delete deck (admin only)
|
||||
router.delete('/decks/:id/hard', adminRequired, async (req: Request, res: Response) => {
|
||||
try {
|
||||
|
||||
@@ -5,9 +5,53 @@ import { ErrorResponseService } from '../../Application/Services/ErrorResponseSe
|
||||
import { ValidationMiddleware } from '../../Application/Services/ValidationMiddleware';
|
||||
import { GeneralSearchService } from '../../Application/Search/Generalsearch';
|
||||
import { logRequest, logError, logWarning } from '../../Application/Services/Logger';
|
||||
import { Type, CType } from '../../Domain/Deck/DeckAggregate';
|
||||
|
||||
const deckRouter = Router();
|
||||
|
||||
/**
|
||||
* Helper function to convert string enum values to integer enum values
|
||||
*/
|
||||
function convertEnumValues(data: any): any {
|
||||
const converted = { ...data };
|
||||
|
||||
// Convert Type enum
|
||||
if (converted.type && typeof converted.type === 'string') {
|
||||
switch (converted.type.toUpperCase()) {
|
||||
case 'LUCK':
|
||||
converted.type = Type.LUCK;
|
||||
break;
|
||||
case 'JOKER':
|
||||
converted.type = Type.JOKER;
|
||||
break;
|
||||
case 'QUESTION':
|
||||
converted.type = Type.QUESTION;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid deck type. Must be LUCK, JOKER, or QUESTION');
|
||||
}
|
||||
}
|
||||
|
||||
// Convert CType enum
|
||||
if (converted.ctype && typeof converted.ctype === 'string') {
|
||||
switch (converted.ctype.toUpperCase()) {
|
||||
case 'PUBLIC':
|
||||
converted.ctype = CType.PUBLIC;
|
||||
break;
|
||||
case 'PRIVATE':
|
||||
converted.ctype = CType.PRIVATE;
|
||||
break;
|
||||
case 'ORGANIZATION':
|
||||
converted.ctype = CType.ORGANIZATION;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid deck ctype. Must be PUBLIC, PRIVATE, or ORGANIZATION');
|
||||
}
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
// Create search service that isn't in the container yet
|
||||
const searchService = new GeneralSearchService(container.userRepository, container.organizationRepository, container.deckRepository);
|
||||
|
||||
@@ -60,18 +104,25 @@ deckRouter.post('/', authRequired, async (req, res) => {
|
||||
try {
|
||||
const userId = (req as any).user.userId;
|
||||
logRequest('Create deck endpoint accessed', req, res, { name: req.body.name, userId });
|
||||
<<<<<<< HEAD
|
||||
req.body.userid = userId; // Set userId in request body
|
||||
=======
|
||||
|
||||
>>>>>>> origin/main
|
||||
const result = await container.createDeckCommandHandler.execute(req.body);
|
||||
// Convert string enum values to integers
|
||||
const command = convertEnumValues({
|
||||
...req.body,
|
||||
userid: userId
|
||||
});
|
||||
|
||||
const result = await container.createDeckCommandHandler.execute(command);
|
||||
|
||||
logRequest('Deck created successfully', req, res, { deckId: result.id, name: req.body.name, userId });
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logError('Create deck endpoint error', error as Error, req, res);
|
||||
|
||||
// Handle enum validation errors
|
||||
if (error instanceof Error && error.message.includes('Invalid deck')) {
|
||||
return res.status(400).json({ error: error.message });
|
||||
}
|
||||
|
||||
if (error instanceof Error && (error.message.includes('duplicate') || error.message.includes('unique constraint'))) {
|
||||
return res.status(409).json({ error: 'Deck with this name already exists' });
|
||||
}
|
||||
@@ -144,23 +195,27 @@ deckRouter.get('/:id', authRequired, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
<<<<<<< HEAD
|
||||
deckRouter.patch('/:id', authRequired, async (req, res) => {
|
||||
=======
|
||||
deckRouter.put('/:id', authRequired, async (req, res) => {
|
||||
>>>>>>> origin/main
|
||||
try {
|
||||
const deckId = req.params.id;
|
||||
const userId = (req as any).user.userId;
|
||||
logRequest('Update deck endpoint accessed', req, res, { deckId, userId, updateFields: Object.keys(req.body) });
|
||||
|
||||
const result = await container.updateDeckCommandHandler.execute({ id: deckId, ...req.body });
|
||||
// Convert string enum values to integers
|
||||
const updateData = convertEnumValues(req.body);
|
||||
|
||||
const result = await container.updateDeckCommandHandler.execute({ id: deckId, ...updateData });
|
||||
|
||||
logRequest('Deck updated successfully', req, res, { deckId, userId });
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logError('Update deck endpoint error', error as Error, req, res);
|
||||
|
||||
// Handle enum validation errors
|
||||
if (error instanceof Error && error.message.includes('Invalid deck')) {
|
||||
return res.status(400).json({ error: error.message });
|
||||
}
|
||||
|
||||
if (error instanceof Error && error.message.includes('not found')) {
|
||||
return res.status(404).json({ error: 'Deck not found' });
|
||||
}
|
||||
@@ -172,13 +227,10 @@ deckRouter.put('/:id', authRequired, async (req, res) => {
|
||||
if (error instanceof Error && error.message.includes('validation')) {
|
||||
return res.status(400).json({ error: 'Invalid input data', details: error.message });
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
|
||||
if (error instanceof Error && error.message.includes('admin')) {
|
||||
return res.status(403).json({ error: 'Forbidden: ' + error.message });
|
||||
}
|
||||
=======
|
||||
>>>>>>> origin/main
|
||||
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
|
||||
@@ -206,7 +206,26 @@ gameRouter.post('/join', optionalAuth, async (req, res) => {
|
||||
playerName: actualPlayerName
|
||||
});
|
||||
|
||||
res.json(game);
|
||||
// Create game token for WebSocket authentication
|
||||
const gameTokenService = container.gameTokenService;
|
||||
const gameToken = gameTokenService.createGameToken(
|
||||
game.id,
|
||||
game.gamecode,
|
||||
actualPlayerName || 'Anonymous',
|
||||
actualPlayerId
|
||||
);
|
||||
|
||||
// Return clean response with essential data + game token
|
||||
res.json({
|
||||
id: game.id,
|
||||
gamecode: game.gamecode,
|
||||
playerName: actualPlayerName,
|
||||
playerCount: game.players.length,
|
||||
maxPlayers: game.maxplayers,
|
||||
gameType: LoginType[gameToJoin.logintype],
|
||||
isAuthenticated: !!actualPlayerId,
|
||||
gameToken: gameToken
|
||||
});
|
||||
} catch (error) {
|
||||
logError('Join game endpoint error', error as Error, req, res);
|
||||
|
||||
|
||||
@@ -32,11 +32,7 @@ userRouter.post('/login',
|
||||
logAuth('User login successful', result.user.id, { username: result.user.username }, req, res);
|
||||
res.json(result);
|
||||
} else {
|
||||
<<<<<<< HEAD
|
||||
throw new Error(`Login failed: ${result}`);
|
||||
=======
|
||||
return ErrorResponseService.sendUnauthorized(res, 'Invalid username or password');
|
||||
>>>>>>> origin/main
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -52,12 +48,9 @@ userRouter.post('/login',
|
||||
if (error.message.includes('not verified')) {
|
||||
return ErrorResponseService.sendUnauthorized(res, 'Please verify your email address');
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
if (error.message.includes('restriction')) {
|
||||
return ErrorResponseService.sendUnauthorized(res, 'Please verify your email address');
|
||||
}
|
||||
=======
|
||||
>>>>>>> origin/main
|
||||
if (error.message.includes('deactivated')) {
|
||||
return ErrorResponseService.sendUnauthorized(res, 'Account has been deactivated');
|
||||
}
|
||||
@@ -94,12 +87,8 @@ userRouter.post('/create',
|
||||
res.status(201).json(result);
|
||||
|
||||
} catch (error) {
|
||||
<<<<<<< HEAD
|
||||
// Don't log here since CreateUserCommandHandler already logs system errors
|
||||
// Only log validation/user input errors at router level
|
||||
=======
|
||||
logError('Create user endpoint error', error as Error, req, res);
|
||||
>>>>>>> origin/main
|
||||
|
||||
if (error instanceof Error) {
|
||||
if (error.message.includes('already exists')) {
|
||||
@@ -108,13 +97,10 @@ userRouter.post('/create',
|
||||
if (error.message.includes('validation')) {
|
||||
return ErrorResponseService.sendBadRequest(res, error.message);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
// Log unexpected errors that weren't handled by the command handler
|
||||
if (!error.message.includes('Failed to create user')) {
|
||||
logError('Unexpected create user endpoint error', error as Error, req, res);
|
||||
}
|
||||
=======
|
||||
>>>>>>> origin/main
|
||||
}
|
||||
|
||||
return ErrorResponseService.sendInternalServerError(res);
|
||||
@@ -187,7 +173,6 @@ userRouter.patch('/profile', authRequired, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
<<<<<<< HEAD
|
||||
//Soft delete user (current user)
|
||||
userRouter.delete('/profile', authRequired, async (req, res) => {
|
||||
try {
|
||||
@@ -214,6 +199,32 @@ userRouter.post('/logout', authRequired, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh token endpoint
|
||||
userRouter.post('/refresh-token', async (req, res) => {
|
||||
try {
|
||||
logRequest('Token refresh endpoint accessed', req, res);
|
||||
|
||||
const jwtService = container.jwtService;
|
||||
const newTokenPair = jwtService.attemptTokenRefresh(req, res);
|
||||
|
||||
if (newTokenPair) {
|
||||
logRequest('Token refresh successful', req, res);
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Tokens refreshed successfully',
|
||||
accessToken: newTokenPair.accessToken,
|
||||
refreshToken: newTokenPair.refreshToken
|
||||
});
|
||||
} else {
|
||||
logWarning('Token refresh failed - invalid or missing refresh token', undefined, req, res);
|
||||
return ErrorResponseService.sendUnauthorized(res, 'Invalid or expired refresh token');
|
||||
}
|
||||
} catch (error) {
|
||||
logError('Refresh token endpoint error', error as Error, req, res);
|
||||
return ErrorResponseService.sendInternalServerError(res);
|
||||
}
|
||||
});
|
||||
|
||||
// Email verification endpoint
|
||||
userRouter.get('/verify-email/:token', async (req, res) => {
|
||||
try {
|
||||
@@ -325,6 +336,4 @@ userRouter.post('/reset-password',
|
||||
}
|
||||
});
|
||||
|
||||
=======
|
||||
>>>>>>> origin/main
|
||||
export default userRouter;
|
||||
|
||||
Reference in New Issue
Block a user