268 lines
8.8 KiB
TypeScript
268 lines
8.8 KiB
TypeScript
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<string, number> = {};
|
|
|
|
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;
|