Files
SerpentRace/SerpentRace_Backend/src/Api/routers/organizationRouter.ts
T

205 lines
6.8 KiB
TypeScript

import { Router } from 'express';
import { authRequired } from '../../Application/Services/AuthMiddleware';
import { container } from '../../Application/Services/DIContainer';
import { ErrorResponseService } from '../../Application/Services/ErrorResponseService';
import { ValidationMiddleware } from '../../Application/Services/ValidationMiddleware';
import { GeneralSearchService } from '../../Application/Search/Generalsearch';
import { logRequest, logError, logWarning, logAuth } from '../../Application/Services/Logger';
const organizationRouter = Router();
// Create search service that isn't in the container yet
const searchService = new GeneralSearchService(container.userRepository, container.organizationRepository, container.deckRepository);
// Auth routes - Get organizations with pagination (RECOMMENDED)
organizationRouter.get('/page/:from/:to', authRequired, async (req, res) => {
try {
const from = parseInt(req.params.from);
const to = parseInt(req.params.to);
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('Get organizations by page endpoint accessed', req, res, { from, to });
const result = await container.getOrganizationsByPageQueryHandler.execute({ from, to });
logRequest('Organizations page retrieved successfully', req, res, {
from,
to,
count: result.organizations.length,
totalCount: result.totalCount
});
res.json(result);
} catch (error) {
logError('Get organizations by page endpoint error', error as Error, req, res);
res.status(500).json({ error: 'Internal server error' });
}
});
organizationRouter.get('/search', authRequired, async (req, res) => {
try {
const { query, limit, offset } = req.query;
logRequest('Search organizations endpoint accessed', req, res, { query, limit, offset });
if (!query || typeof query !== 'string') {
logWarning('Organization search attempted without query', { query, hasQuery: !!query }, req, res);
return res.status(400).json({ error: 'Search query is required' });
}
const searchQuery = {
query: query.trim(),
limit: limit ? parseInt(limit as string) : 20,
offset: offset ? parseInt(offset as string) : 0
};
// Validate pagination parameters
if (searchQuery.limit < 1 || searchQuery.limit > 100) {
logWarning('Invalid organization search limit parameter', { limit: searchQuery.limit }, req, res);
return res.status(400).json({ error: 'Limit must be between 1 and 100' });
}
if (searchQuery.offset < 0) {
logWarning('Invalid organization search offset parameter', { offset: searchQuery.offset }, req, res);
return res.status(400).json({ error: 'Offset must be non-negative' });
}
const result = await searchService.searchFromUrl(req.originalUrl, searchQuery);
logRequest('Organization search completed successfully', req, res, {
query: searchQuery.query,
resultCount: Array.isArray(result) ? result.length : 0
});
res.json(result);
} catch (error) {
logError('Search organizations endpoint error', error as Error, req, res);
res.status(500).json({ error: 'Internal server error' });
}
});
// Get organization login URL
organizationRouter.get('/:orgId/login-url', authRequired, async (req, res) => {
try {
const userId = (req as any).user.userId;
const { orgId } = req.params;
logRequest('Get organization login URL endpoint accessed', req, res, {
userId,
organizationId: orgId
});
const result = await container.getOrganizationLoginUrlQueryHandler.execute({
organizationId: orgId
});
if (!result) {
logWarning('Organization login URL not found', {
organizationId: orgId,
userId
}, req, res);
return ErrorResponseService.sendNotFound(res, 'Organization login URL not found');
}
logRequest('Organization login URL retrieved successfully', req, res, {
organizationId: orgId,
organizationName: result.organizationName,
hasUrl: !!result.loginUrl,
userId
});
res.json(result);
} catch (error) {
logError('Get organization login URL endpoint error', error as Error, req, res);
return ErrorResponseService.sendInternalServerError(res);
}
});
// Process third-party authentication callback
organizationRouter.post('/auth-callback', authRequired, async (req, res) => {
try {
const userId = (req as any).user.userId;
const { organizationId, status, authToken } = req.body;
logRequest('Organization auth callback endpoint accessed', req, res, {
userId,
organizationId,
status,
hasAuthToken: !!authToken
});
// Validate required fields
if (!organizationId || !status) {
logWarning('Missing required fields for organization auth callback', {
organizationId: !!organizationId,
status: !!status,
userId
}, req, res);
return ErrorResponseService.sendBadRequest(res, 'organizationId and status are required');
}
if (status !== 'ok' && status !== 'not_ok') {
logWarning('Invalid status value for organization auth callback', {
status,
userId,
organizationId
}, req, res);
return ErrorResponseService.sendBadRequest(res, 'status must be either "ok" or "not_ok"');
}
const result = await container.processOrgAuthCallbackCommandHandler.execute({
organizationId,
userId,
status,
authToken
});
if (!result.success) {
if (result.message.includes('not found')) {
logWarning('Organization auth callback failed - entity not found', {
userId,
organizationId,
message: result.message
}, req, res);
return ErrorResponseService.sendNotFound(res, result.message);
}
if (result.message.includes('does not belong')) {
logWarning('Organization auth callback failed - authorization error', {
userId,
organizationId,
message: result.message
}, req, res);
return ErrorResponseService.sendForbidden(res, result.message);
}
if (result.message.includes('authentication failed')) {
logAuth('Organization authentication failed via callback', userId, {
organizationId,
status
}, req, res);
return ErrorResponseService.sendUnauthorized(res, result.message);
}
logError('Organization auth callback internal error', new Error(result.message), req, res);
return ErrorResponseService.sendInternalServerError(res);
}
logAuth('Organization auth callback processed successfully', userId, {
organizationId,
status,
updatedFields: result.updatedFields
}, req, res);
res.json({
success: result.success,
message: result.message,
updatedFields: result.updatedFields
});
} catch (error) {
logError('Organization auth callback endpoint error', error as Error, req, res);
return ErrorResponseService.sendInternalServerError(res);
}
});
export default organizationRouter;