const express = require('express'); const router = express.Router(); import { Request, Response } from 'express'; import pool from '../db'; import { requireLogin, requireMemberState, requireRole } from '../middleware/auth'; import { getUserActiveLOA } from '../services/db/loaService'; import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings, getFilteredMembers, setUserState } from '../services/db/memberService'; import { getUserRoles } from '../services/db/rolesService'; import { memberSettings, MemberState, myData } from '@app/shared/types/member'; import { Discharge } from '@app/shared/schemas/dischargeSchema'; import { Performance } from 'perf_hooks'; import { logger } from '../services/logging/logger'; import { memberCache } from './auth'; import { cancelLatestRank } from '../services/db/rankService'; import { cancelLatestUnit } from '../services/db/unitService'; //get all users router.get('/', [requireLogin, requireMemberState(MemberState.Member)], async (req, res) => { try { const result = await pool.query( `SELECT v.*, CASE WHEN EXISTS ( SELECT 1 FROM leave_of_absences l WHERE l.member_id = v.member_id AND l.deleted = 0 AND UTC_TIMESTAMP() BETWEEN l.start_date AND l.end_date ) THEN 1 ELSE 0 END AS on_loa FROM view_member_rank_unit_status_latest v;`); return res.status(200).json(result); } catch (error) { logger.error( 'app', 'Failed to get all users', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); return res.status(500).json({ error: 'Failed to fetch users' }); } }); router.get('/filtered', [requireLogin, requireMemberState(MemberState.Member)], async (req, res) => { try { // Extract Query Parameters const page = parseInt(req.query.page as string) || 1; const pageSize = parseInt(req.query.pageSize as string) || 15; const search = req.query.search as string | undefined; const status = req.query.status as string | undefined; const unitId = req.query.unitId as string | undefined; // Call the service function const result = await getFilteredMembers(page, pageSize, search, status, unitId); return res.status(200).json(result); } catch (error) { logger.error('app', 'Failed to get filtered users', { error: error instanceof Error ? error.message : String(error), }); return res.status(500).json({ error: 'Failed to fetch users' }); } }); router.get('/me', [requireLogin], async (req: Request, res) => { if (!req.user) return res.sendStatus(401); const routeStart = performance.now(); const timings: Record = {}; try { let t; t = performance.now(); const memData = await getUserData(req.user.id); timings.member = performance.now() - t; t = performance.now(); const LOAData = await getUserActiveLOA(req.user.id); timings.loa = performance.now() - t; t = performance.now(); const memState = await getUserState(req.user.id); timings.state = performance.now() - t; t = performance.now(); const roleData = await getUserRoles(req.user.id); timings.roles = performance.now() - t; const userDataFull: myData = { member: memData, LOAs: LOAData, roles: roleData, state: memState, }; res.status(200).json(userDataFull); logger.info('profiling', 'GET /members/me completed', { userId: req.user.id, total_ms: performance.now() - routeStart, breakdown_ms: timings, }, 'profiling'); } catch (error) { logger.error('profiling', 'GET /members/me failed', { userId: req.user?.id, error: error instanceof Error ? error.message : String(error), }); return res.status(500).json({ error: 'Failed to fetch user data' }); } }); router.get('/settings', [requireLogin], async (req: Request, res: Response) => { try { let user = req.user.id; let output = await getMemberSettings(user); res.status(200).json(output); } catch (error) { logger.error( 'app', 'Failed to get member settings', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); res.status(500).json(error); } }) router.put('/settings', [requireLogin], async (req: Request, res: Response) => { try { let user = req.user.id; let settings: memberSettings = req.body; await setUserSettings(user, settings); logger.info('app', 'User updated profile settings', { user: user }) res.sendStatus(200); } catch (error) { logger.error( 'app', 'Failed to update user settings', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); res.status(500).json(error); } }) router.get('/lite', [requireLogin], async (req: Request, res: Response) => { try { let out = await getAllMembersLite(); res.status(200).json(out); } catch (error) { logger.error( 'app', 'Failed to get lite users', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); res.status(500).json(error); } }) router.post('/lite/bulk', async (req: Request, res: Response) => { try { let ids = req.body.ids; let out = await getMembersLite(ids); res.status(200).json(out); } catch (error) { logger.error( 'app', 'Failed to get batch lite users', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); res.status(500).json(error); } }) router.post('/full/bulk', async (req: Request, res: Response) => { try { let ids = req.body.ids; let out = await getMembersFull(ids); res.status(200).json(out); } catch (error) { logger.error( 'app', 'Failed to get batch full users', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); res.status(500).json(error); } }) router.get('/:id', [requireLogin], async (req, res) => { const userId = req.params.id; try { const result = await pool.query('SELECT * FROM view_member_rank_unit_status_latest WHERE id = $1;', [userId]); if (result.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } return res.status(200).json(result.rows[0]); } catch (error) { logger.error( 'app', 'Failed to get user', { user: userId, error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, } ); return res.status(500).json({ error: 'Failed to fetch user' }); } }); //update a user's display name (stub) router.put('/:id/displayname', async (req, res) => { // Stub: not implemented yet return res.status(501); }); //discharge member router.post('/discharge', [requireLogin, requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res: Response) => { try { var con = await pool.getConnection(); con.beginTransaction(); var data: Discharge = req.body; setUserState(data.userID, MemberState.Retired, con); cancelLatestRank(data.userID, con); cancelLatestUnit(data.userID, con); con.commit(); memberCache.Invalidate(data.userID); res.sendStatus(200); } catch (error) { logger.error('app', 'Failed to discharge user', { data: data, caller: req.user.id, error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, }) } finally { if (con) con.release(); } }); export const memberRouter = router;