integrated the new logger across the entire API

This commit is contained in:
2025-12-31 21:45:38 -05:00
parent 510d4a13ac
commit 9f895a202d
10 changed files with 670 additions and 125 deletions

View File

@@ -46,29 +46,64 @@ router.get('/coc', async (req: Request, res: Response) => {
// POST /application
router.post('/', [requireLogin], async (req, res) => {
const memberID = req.user.id;
const App = req.body?.App || {};
const appVersion = 1;
try {
const App = req.body?.App || {};
const memberID = req.user.id;
req.profiler?.start('createApplication');
await createApplication(memberID, appVersion, JSON.stringify(App));
req.profiler?.end('createApplication');
const appVersion = 1;
await createApplication(memberID, appVersion, JSON.stringify(App))
req.profiler?.start('setUserState');
await setUserState(memberID, MemberState.Applicant);
req.profiler?.end('setUserState');
res.sendStatus(201);
// Log full route profiling
const summary = req.profiler?.summary();
if (summary) {
logger.info(
'profiling',
'POST /application completed',
{
memberID,
appVersion,
...summary,
},
'profiling'
);
}
} catch (err) {
console.error('Failed to create application: \n', err);
logger.error(
'app',
'Failed to create application',
{
memberID,
error: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to create application' });
}
});
// GET /application/all
router.get('/all', [requireLogin, requireRole("Recruiter")], async (req, res) => {
try {
const rows = await getApplicationList();
res.status(200).json(rows);
} catch (err) {
console.error(err);
logger.error(
'app',
'Failed to get applications',
{
error: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined,
}
);
res.status(500);
}
});
@@ -82,8 +117,16 @@ router.get('/meList', async (req, res) => {
return res.status(200).json(application);
} catch (error) {
console.error('Failed to load applications: \n', error);
return res.status(500).json(error);
logger.error(
'app',
'Failed to get applications for user',
{
user: userID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
return res.status(500);
}
})
@@ -108,12 +151,20 @@ router.get('/me', [requireLogin], async (req, res) => {
return res.status(200).json(output);
} catch (error) {
console.error('Failed to load application:', error);
logger.error(
'app',
'Failed to load application',
{
user: userID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
return res.status(500).json(error);
}
})
// GET /application/:id
// GET /me/:id
router.get('/me/:id', [requireLogin], async (req: Request, res: Response) => {
let appID = Number(req.params.id);
let member = req.user.id;
@@ -133,9 +184,18 @@ router.get('/me/:id', [requireLogin], async (req: Request, res: Response) => {
}
return res.status(200).json(output);
}
catch (err) {
console.error('Query failed:', err);
return res.status(500).json({ error: 'Failed to load application' });
catch (error) {
logger.error(
'app',
'Failed to load application',
{
application: appID,
user: member,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
return res.status(500);
}
});
@@ -157,9 +217,17 @@ router.get('/:id', [requireLogin, requireRole("Recruiter")], async (req: Request
}
return res.status(200).json(output);
}
catch (err) {
console.error('Query failed:', err);
return res.status(500).json({ error: 'Failed to load application' });
catch (error) {
logger.error(
'app',
'Failed to load application',
{
application: appID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
return res.status(500);
}
});
@@ -177,9 +245,22 @@ router.post('/approve/:id', [requireLogin, requireRole("Recruiter")], async (req
await pool.query('CALL sp_accept_new_recruit_validation(?, ?, ?, ?)', [Number(process.env.CONFIG_ID), app.member_id, approved_by, approved_by])
logger.info('app', "Member application approved", {
application: app.id,
applicant: app.member_id,
approver: approved_by
})
res.sendStatus(200);
} catch (err) {
console.error('Approve failed:', err);
} catch (error) {
logger.error(
'app',
'Failed to approve application',
{
application: appID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to approve application' });
}
});
@@ -193,9 +274,23 @@ router.post('/deny/:id', [requireLogin, requireRole("Recruiter")], async (req: R
const app = await getApplicationByID(appID);
await denyApplication(appID, approver);
await setUserState(app.member_id, MemberState.Denied);
logger.info('app', "Member application approved", {
application: app.id,
applicant: app.member_id,
approver: approver
})
res.sendStatus(200);
} catch (err) {
console.error('Approve failed:', err);
} catch (error) {
logger.error(
'app',
'Failed to deny application',
{
application: appID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to deny application' });
}
});
@@ -233,10 +328,25 @@ VALUES(?, ?, ?);`
INNER JOIN members AS member ON member.id = app.poster_id
WHERE app.id = ?; `;
const comment = await conn.query(getSQL, [result.insertId])
logger.info('app', "Application comment posted", {
application: appID,
poster: user.id,
comment: result.insertId,
})
res.status(201).json(comment[0]);
} catch (err) {
console.error('Comment failed:', err);
} catch (error) {
logger.error(
'app',
'Failed to post comment',
{
application: appID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Could not post comment' });
} finally {
conn.release();
@@ -277,10 +387,24 @@ VALUES(?, ?, ?, 1);`
INNER JOIN members AS member ON member.id = app.poster_id
WHERE app.id = ?; `;
const comment = await conn.query(getSQL, [result.insertId])
res.status(201).json(comment[0]);
} catch (err) {
console.error('Comment failed:', err);
logger.info('app', "Admin application comment posted", {
application: appID,
poster: user.id,
comment: result.insertId,
})
res.status(201).json(comment[0]);
} catch (error) {
logger.error(
'app',
'Failed to post comment',
{
application: appID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Could not post comment' });
} finally {
conn.release();
@@ -291,9 +415,22 @@ router.post('/restart', async (req: Request, res: Response) => {
const user = req.user.id;
try {
await setUserState(user, MemberState.Guest);
logger.info('app', "Member restarted application", {
user: user
})
res.sendStatus(200);
} catch (error) {
console.error('Comment failed:', error);
logger.error(
'app',
'Failed to restart application',
{
user: user,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Could not rester application' });
}
})

View File

@@ -79,7 +79,6 @@ passport.use(new OpenIDConnectStrategy({
});
} else {
console.log("New Account");
// new account
const username = sub.username;
const result = await con.query(
@@ -168,8 +167,12 @@ router.get('/logout', [requireLogin], function (req, res, next) {
client_id: process.env.AUTH_CLIENT_ID,
returnTo: process.env.CLIENT_URL
};
res.redirect(process.env.AUTH_END_SESSION_URI + '?' + querystring.stringify(params));
logger.info('auth', `Member logged out`, {
user: req.user.id,
});
res.redirect(process.env.AUTH_END_SESSION_URI + '?' + querystring.stringify(params));
})
});
});

View File

@@ -3,6 +3,7 @@ import { createEvent, getEventAttendance, getEventDetails, getShortEventsInRange
import { CalendarAttendance, CalendarEvent } from "@app/shared/types/calendar";
import { requireLogin, requireMemberState, requireRole } from "../middleware/auth";
import { MemberState } from "@app/shared/types/member";
import { logger } from "../services/logging/logger";
const express = require('express');
const r = express.Router();
@@ -28,7 +29,14 @@ r.get('/', async (req, res) => {
res.status(200).json(events);
} catch (error) {
console.error('Error fetching calendar events:', error);
logger.error(
'app',
'Failed to get calendar events',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send('Error fetching calendar events');
}
});
@@ -41,9 +49,21 @@ r.post('/:id/cancel', [requireLogin, requireMemberState(MemberState.Member)], as
try {
const eventID = Number(req.params.id);
setEventCancelled(eventID, true);
logger.info('app', 'Calendar event cancelled', {
event: eventID,
user: req.user.id
})
res.sendStatus(200);
} catch (error) {
console.error('Error setting cancel status:', error);
logger.error(
'app',
'Failed to get cancel calendar event',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send('Error setting cancel status');
}
})
@@ -51,9 +71,21 @@ r.post('/:id/uncancel', [requireLogin, requireMemberState(MemberState.Member)],
try {
const eventID = Number(req.params.id);
setEventCancelled(eventID, false);
logger.info('app', 'Calendar event un-cancelled', {
event: eventID,
user: req.user.id
})
res.sendStatus(200);
} catch (error) {
console.error('Error setting cancel status:', error);
logger.error(
'app',
'Failed to uncancel calendar event',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send('Error setting cancel status');
}
})
@@ -65,12 +97,27 @@ r.post('/:id/attendance', [requireLogin, requireMemberState(MemberState.Member)]
let event = Number(req.params.id);
let state = req.query.state as CalendarAttendance;
setAttendanceStatus(member, event, state);
logger.info('app', 'Member set calendar event attendance', {
event: event,
user: req.user.id,
state: state
})
res.sendStatus(200);
} catch (error) {
console.error('Failed to set attendance:', error);
logger.error(
'app',
'Failed to set attendance',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})
//get event details
r.get('/:id', async (req: Request, res: Response) => {
try {
@@ -79,9 +126,16 @@ r.get('/:id', async (req: Request, res: Response) => {
let details: CalendarEvent = await getEventDetails(eventID);
details.eventSignups = await getEventAttendance(eventID);
res.status(200).json(details);
} catch (err) {
console.error('Insert failed:', err);
res.status(500).json(err);
} catch (error) {
logger.error(
'app',
'Failed to get calendar event details',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500);
}
})
@@ -95,9 +149,22 @@ r.post('/', [requireLogin, requireMemberState(MemberState.Member)], async (req:
event.start = new Date(event.start);
event.end = new Date(event.end);
createEvent(event);
logger.info('app', 'Calendar event posted', {
event: event.id,
user: req.user.id
})
res.sendStatus(200);
} catch (error) {
console.error('Failed to create event:', error);
logger.error(
'app',
'Failed to create calendar event',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})
@@ -108,9 +175,22 @@ r.put('/', [requireLogin, requireMemberState(MemberState.Member)], async (req: R
event.start = new Date(event.start);
event.end = new Date(event.end);
updateEvent(event);
logger.info('app', 'Calendar event updated', {
event: event.id,
user: req.user.id
})
res.sendStatus(200);
} catch (error) {
console.error('Failed to update event:', error);
logger.error(
'app',
'Failed to update calendar event',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})

View File

@@ -3,6 +3,7 @@ import { getAllCourses, getCourseEventAttendees, getCourseEventDetails, getCours
import { Request, Response, Router } from "express";
import { requireLogin, requireMemberState } from "../middleware/auth";
import { MemberState } from "@app/shared/types/member";
import { logger } from "../services/logging/logger";
const cr = Router();
const er = Router();
@@ -16,9 +17,16 @@ cr.get('/', async (req, res) => {
try {
const courses = await getAllCourses();
res.status(200).json(courses);
} catch (err) {
console.error('failed to fetch courses', err);
res.status(500).json('failed to fetch courses\n' + err);
} catch (error) {
logger.error(
'app',
'Failed to fetch courses',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json('failed to fetch courses');
}
})
@@ -26,12 +34,20 @@ cr.get('/roles', async (req, res) => {
try {
const roles = await getCourseEventRoles();
res.status(200).json(roles);
} catch (err) {
console.error('failed to fetch course roles', err);
res.status(500).json('failed to fetch course roles\n' + err);
} catch (error) {
logger.error(
'app',
'Failed to fetch course roles',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json('failed to fetch course roles');
}
})
//get event list
er.get('/', async (req: Request, res: Response) => {
try {
const allowedSorts = new Map([
@@ -55,7 +71,14 @@ er.get('/', async (req: Request, res: Response) => {
let events = await getCourseEvents(sortDir, search, page, pageSize);
res.status(200).json(events);
} catch (error) {
console.error('failed to fetch reports', error);
logger.error(
'app',
'Failed to fetch course events',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
});
@@ -65,7 +88,14 @@ er.get('/:id', async (req: Request, res: Response) => {
let out = await getCourseEventDetails(Number(req.params.id));
res.status(200).json(out);
} catch (error) {
console.error('failed to fetch report', error);
logger.error(
'app',
'Failed to fetch course event',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
});
@@ -74,9 +104,16 @@ er.get('/attendees/:id', async (req: Request, res: Response) => {
try {
const attendees: CourseAttendee[] = await getCourseEventAttendees(Number(req.params.id));
res.status(200).json(attendees);
} catch (err) {
console.error('failed to fetch attendees', err);
res.status(500).json("failed to fetch attendees\n" + err);
} catch (error) {
logger.error(
'app',
'Failed to fetch course event attendees',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json("failed to fetch attendees");
}
})
@@ -87,9 +124,19 @@ er.post('/', async (req: Request, res: Response) => {
data.created_by = posterID;
data.event_date = new Date(data.event_date);
const id = await insertCourseEvent(data);
logger.info('app', 'Training report posted', { user: posterID, report: id })
res.status(201).json(id);
} catch (error) {
console.error('failed to post training', error);
logger.error(
'app',
'Failed to post training report',
{
user: posterID,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json("failed to post training\n" + error)
}
})

View File

@@ -3,22 +3,55 @@ const router = express.Router();
import { Request, Response } from 'express';
import { requireLogin } from '../middleware/auth';
import { logger } from '../services/logging/logger';
// GET /welcome
router.get('/welcome', [requireLogin], async (req: Request, res: Response) => {
const output = await fetch(`${process.env.DOC_HOST}/api/pages/717`, {
headers: {
Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
}
})
const t0 = performance.now(); // optional profiling start
if (output.ok) {
const out = await output.json();
try {
const response = await fetch(`${process.env.DOC_HOST}/api/pages/717`, {
headers: {
Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
},
});
if (!response.ok) {
const text = await response.text();
logger.error('app', 'Failed to fetch welcome page from Bookstack', {
status: response.status,
statusText: response.statusText,
body: text,
userId: req.user?.id,
});
return res.sendStatus(500);
}
const out = await response.json();
res.status(200).json(out.html);
} else {
console.error("Failed to fetch LOA policy from bookstack");
// optional profiling log
const duration = performance.now() - t0;
logger.info(
'profiling',
'GET /welcome completed',
{
userId: req.user?.id,
total_ms: duration,
},
'profiling'
);
} catch (error) {
logger.error('app', 'Error fetching welcome page from Bookstack', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
userId: req.user?.id,
});
res.sendStatus(500);
}
})
});
export const docsRouter = router;

View File

@@ -6,6 +6,7 @@ import pool from '../db';
import { closeLOA, createNewLOA, getAllLOA, getLOAbyID, getLoaTypes, getUserLOA, setLOAExtension } from '../services/db/loaService';
import { LOARequest } from '@app/shared/types/loa';
import { requireLogin, requireRole } from '../middleware/auth';
import { logger } from '../services/logging/logger';
router.use(requireLogin);
@@ -18,9 +19,17 @@ router.post("/", async (req: Request, res: Response) => {
try {
await createNewLOA(LOARequest);
logger.info('app', 'LOA Posted', { poster: req.user.id, user: LOARequest.member_id })
res.sendStatus(201);
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to post LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send(error);
}
});
@@ -32,10 +41,17 @@ router.post("/admin", [requireRole(['17th Administrator', '17th HQ', '17th Comma
LOARequest.filed_date = new Date();
try {
await createNewLOA(LOARequest);
logger.info('app', 'LOA Posted', { poster: req.user.id, user: LOARequest.member_id })
res.sendStatus(201);
} catch (error) {
console.error(error);
res.status(500).send(error);
logger.error(
'app',
'Failed to post LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
); res.status(500).send(error);
}
});
@@ -46,7 +62,14 @@ router.get("/me", async (req: Request, res: Response) => {
const result = await getUserLOA(user);
res.status(200).json(result)
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to get user current LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send(error);
}
})
@@ -62,7 +85,14 @@ router.get("/history", async (req: Request, res: Response) => {
const result = await getUserLOA(user, page, pageSize);
res.status(200).json(result)
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to get user LOA history',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send(error);
}
})
@@ -74,7 +104,14 @@ router.get('/all', [requireRole(['17th Administrator', '17th HQ', '17th Command'
const result = await getAllLOA(page, pageSize);
res.status(200).json(result)
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to get full LOA history',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).send(error);
}
})
@@ -84,8 +121,15 @@ router.get('/types', async (req: Request, res: Response) => {
let out = await getLoaTypes();
res.status(200).json(out);
} catch (error) {
logger.error(
'app',
'Failed to get LOA types',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
console.error(error);
}
})
@@ -99,9 +143,19 @@ router.post('/cancel/:id', async (req: Request, res: Response) => {
}
await closeLOA(Number(req.params.id), closer);
logger.info('app', 'LOA Closed', { closed_by: closer, LOA: id })
res.sendStatus(200);
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to cancel LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})
@@ -111,14 +165,24 @@ router.post('/adminCancel/:id', [requireRole(['17th Administrator', '17th HQ', '
let closer = req.user.id;
try {
await closeLOA(Number(req.params.id), closer);
logger.info('app', 'LOA Closed', { closed_by: closer, LOA: req.params.id })
res.sendStatus(200);
} catch (error) {
console.error(error);
logger.error(
'app',
'Failed to cancel LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})
// TODO: Enforce admin only
// extend LOA
router.post('/extend/:id', [requireRole(['17th Administrator', '17th HQ', '17th Command'])], async (req: Request, res: Response) => {
const to: Date = req.body.to;
@@ -128,27 +192,71 @@ router.post('/extend/:id', [requireRole(['17th Administrator', '17th HQ', '17th
try {
await setLOAExtension(Number(req.params.id), to);
logger.info('app', 'LOA Extended', { extended_by: req.user.id, LOA: req.params.id })
res.sendStatus(200);
} catch (error) {
console.error(error)
logger.error(
'app',
'Failed to extend LOA',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json(error);
}
})
// GET /policy
router.get('/policy', async (req: Request, res: Response) => {
const output = await fetch(`${process.env.DOC_HOST}/api/pages/42`, {
headers: {
Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
}
})
const t0 = performance.now();
if (output.ok) {
const out = await output.json();
try {
const response = await fetch(`${process.env.DOC_HOST}/api/pages/42`, {
headers: {
Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
},
});
if (!response.ok) {
const text = await response.text();
logger.error('app', 'Failed to fetch policy page from Bookstack', {
pageId: 42,
status: response.status,
statusText: response.statusText,
body: text,
userId: req.user?.id,
});
return res.sendStatus(500);
}
const out = await response.json();
res.status(200).json(out.html);
} else {
console.error("Failed to fetch LOA policy from bookstack");
logger.info(
'profiling',
'GET /policy completed',
{
pageId: 42,
total_ms: performance.now() - t0,
},
'profiling'
);
} catch (error) {
logger.error('app', 'Error fetching policy page from Bookstack', {
pageId: 42,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
userId: req.user?.id,
});
res.sendStatus(500);
}
})
});
export const loaRouter = router;

View File

@@ -29,8 +29,15 @@ router.get('/', [requireLogin, requireMemberState(MemberState.Member)], async (r
END AS on_loa
FROM view_member_rank_unit_status_latest v;`);
return res.status(200).json(result);
} catch (err) {
console.error('Error fetching users:', err);
} 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' });
}
});
@@ -92,7 +99,14 @@ router.get('/settings', [requireLogin], async (req: Request, res: Response) => {
let output = await getMemberSettings(user);
res.status(200).json(output);
} catch (error) {
console.error(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);
}
})
@@ -102,10 +116,17 @@ router.put('/settings', [requireLogin], async (req: Request, res: Response) => {
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) {
console.error(error);
res.status(500).json(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);
}
})
@@ -114,7 +135,14 @@ router.get('/lite', [requireLogin], async (req: Request, res: Response) => {
let out = await getAllMembersLite();
res.status(200).json(out);
} catch (error) {
console.error(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);
}
})
@@ -125,7 +153,14 @@ router.post('/lite/bulk', async (req: Request, res: Response) => {
let out = await getMembersLite(ids);
res.status(200).json(out);
} catch (error) {
console.error(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);
}
})
@@ -137,22 +172,36 @@ router.post('/full/bulk', async (req: Request, res: Response) => {
let out = await getMembersFull(ids);
res.status(200).json(out);
} catch (error) {
console.error(error);
res.status(500).json(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 userId = req.params.id;
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 (err) {
console.error('Error fetching user:', err);
return res.status(500).json({ error: 'Failed to fetch user' });
} 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' });
}
});

View File

@@ -4,6 +4,7 @@ import { batchInsertMemberRank, getAllRanks, getPromotionHistorySummary, getProm
import { BatchPromotion, BatchPromotionMember } from '@app/shared/schemas/promotionSchema'
import express = require('express');
import { logger } from "../services/logging/logger";
const r = express.Router();
const ur = express.Router();
@@ -19,10 +20,17 @@ ur.post('/', [requireRole(["17th Command", "17th Administrator", "17th HQ"]), re
if (!change) res.sendStatus(400);
await batchInsertMemberRank(change, author);
logger.info('app', 'Promotion batch submitted', { author: author })
res.sendStatus(201);
} catch (err) {
console.error('Insert failed:', err);
} catch (error) {
logger.error(
'app',
'Failed to post rank change',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to update ranks' });
}
});
@@ -31,9 +39,16 @@ ur.get('/', async (req: express.Request, res: express.Response) => {
try {
const promos = await getPromotionHistorySummary();
res.status(200).json(promos);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
} catch (error) {
logger.error(
'app',
'Failed to get rank change history',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
});
@@ -41,12 +56,20 @@ ur.get('/:day', async (req: express.Request, res: express.Response) => {
try {
if (!req.params.day) res.sendStatus(400);
let day = new Date(req.params.day)
var day = new Date(req.params.day)
const promos = await getPromotionsOnDay(day);
res.status(200).json(promos);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
} catch (error) {
logger.error(
'app',
'Failed to get rank change history on day',
{
day: day,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
})
@@ -55,8 +78,15 @@ r.get('/', async (req, res) => {
try {
const ranks = await getAllRanks();
res.json(ranks);
} catch (err) {
console.error(err);
} catch (error) {
logger.error(
'app',
'Failed to get all ranks',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Internal server error' });
}
});

View File

@@ -7,44 +7,69 @@ import pool from '../db';
import { requireLogin, requireMemberState, requireRole } from '../middleware/auth';
import { assignUserGroup, createGroup, getAllRoles, getRole, getUsersWithRole } from '../services/db/rolesService';
import { Request, Response } from 'express';
import { logger } from '../services/logging/logger';
r.use(requireLogin)
ur.use(requireLogin)
//manually assign a member to a group
ur.post('/', [requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req, res) => {
ur.post('/', [requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res) => {
const body = req.body;
try {
const body = req.body;
await assignUserGroup(body.member_id, body.role_id);
logger.info('app', 'User assigned role', { user: body.member_id, role: body.role_id, assigner: req.user.id })
res.sendStatus(201);
} catch (err) {
if (err?.code === 'ER_DUP_ENTRY') {
} catch (error) {
if (error?.code === 'ER_DUP_ENTRY') {
return res.status(400).json({
error: 'Member already has this role',
});
}
console.error('Insert failed:', err);
logger.error(
'app',
'Failed to assign role',
{
user: body.member_id,
role: body.role_id,
assigner: req.user.id,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to add to group' });
}
});
//manually remove member from group
ur.delete('/', [requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req, res) => {
ur.delete('/', [requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res: Response) => {
const body = req.body;
try {
const body = req.body;
const sql = 'DELETE FROM members_roles WHERE member_id = ? AND role_id = ?'
await pool.query(sql, [body.member_id, body.role_id])
logger.info('app', 'User removed role', { user: body.member_id, role: body.role_id, assigner: req.user.id })
res.sendStatus(200);
}
catch (err) {
console.error("delete failed: ", err)
catch (error) {
logger.error(
'app',
'Failed to remove role',
{
user: body.member_id,
role: body.role_id,
assigner: req.user.id,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.status(500).json({ error: 'Failed to remove from group' });
}
})
@@ -52,9 +77,18 @@ ur.delete('/', [requireMemberState(MemberState.Member), requireRole("17th Admini
r.get('/', [requireMemberState(MemberState.Member)], async (req, res) => {
try {
const roles = await getAllRoles();
//@ts-ignore
test();
res.status(200).json(roles);
} catch (err) {
console.error(err);
} catch (error) {
logger.error(
'app',
'Failed to get all roles',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
});
@@ -63,8 +97,16 @@ r.get('/:id/members', [requireMemberState(MemberState.Member)], async (req: Requ
try {
const members = await getUsersWithRole(Number(req.params.id));
res.status(200).json(members);
} catch (err) {
console.error(err);
} catch (error) {
logger.error(
'app',
'Failed to get role members',
{
role: req.params.id,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
})
@@ -74,8 +116,16 @@ r.get('/:id', [requireMemberState(MemberState.Member)], async (req: Request, res
try {
const role = await getRole(Number(req.params.id));
res.status(200).json(role);
} catch (err) {
console.error(err);
} catch (error) {
logger.error(
'app',
'Failed to get role members',
{
role: req.params.id,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
})

View File

@@ -4,6 +4,7 @@ const memberStatusR = express.Router();
import pool from '../db';
import { requireLogin } from '../middleware/auth';
import { logger } from '../services/logging/logger';
statusR.use(requireLogin);
memberStatusR.use(requireLogin);
@@ -38,9 +39,16 @@ statusR.get('/', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM statuses;');
res.json(result);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
} catch (error) {
logger.error(
'app',
'Failed to get all statuses',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
});