Merge branch 'main' into database-view-updates
This commit is contained in:
@@ -21,7 +21,13 @@ CLIENT_URL= # This is whatever URL the client web app is served on
|
||||
CLIENT_DOMAIN= #whatever.com
|
||||
APPLICATION_VERSION= # Should match release tag
|
||||
APPLICATION_ENVIRONMENT= # dev / prod
|
||||
CONFIG_ID= # configures
|
||||
|
||||
# Glitchtip
|
||||
GLITCHTIP_DSN=
|
||||
DISABLE_GLITCHTIP= # true/false
|
||||
DISABLE_GLITCHTIP= # true/false
|
||||
|
||||
# Bookstack
|
||||
DOC_HOST= # https://bookstack.whatever.com/
|
||||
DOC_TOKEN_SECRET=
|
||||
DOC_TOKEN_ID=
|
||||
@@ -2,11 +2,31 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
import pool from '../db';
|
||||
import { approveApplication, createApplication, getApplicationByID, getApplicationComments, getApplicationList, getMemberApplication } from '../services/applicationService';
|
||||
import { approveApplication, createApplication, denyApplication, getAllMemberApplications, getApplicationByID, getApplicationComments, getApplicationList, getMemberApplication } from '../services/applicationService';
|
||||
import { MemberState, setUserState } from '../services/memberService';
|
||||
import { getRankByName, insertMemberRank } from '../services/rankService';
|
||||
import { ApplicationFull, CommentRow } from "@app/shared/types/application"
|
||||
import { assignUserToStatus } from '../services/statusService';
|
||||
import { Request, response, Response } from 'express';
|
||||
import { getUserRoles } from '../services/rolesService';
|
||||
|
||||
//get CoC
|
||||
router.get('/coc', async (req: Request, res: Response) => {
|
||||
const output = await fetch(`${process.env.DOC_HOST}/api/pages/714`, {
|
||||
headers: {
|
||||
Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
|
||||
}
|
||||
})
|
||||
|
||||
if (output.ok) {
|
||||
const out = await output.json();
|
||||
res.status(200).json(out.html);
|
||||
} else {
|
||||
console.error("Failed to fetch LOA policy from bookstack");
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// POST /application
|
||||
router.post('/', async (req, res) => {
|
||||
@@ -16,13 +36,13 @@ router.post('/', async (req, res) => {
|
||||
|
||||
const appVersion = 1;
|
||||
|
||||
createApplication(memberID, appVersion, JSON.stringify(App))
|
||||
setUserState(memberID, MemberState.Applicant);
|
||||
await createApplication(memberID, appVersion, JSON.stringify(App))
|
||||
await setUserState(memberID, MemberState.Applicant);
|
||||
|
||||
res.sendStatus(201);
|
||||
} catch (err) {
|
||||
console.error('Insert failed:', err);
|
||||
res.status(500).json({ error: 'Failed to save application' });
|
||||
console.error('Failed to create application: \n', err);
|
||||
res.status(500).json({ error: 'Failed to create application' });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,6 +57,20 @@ router.get('/all', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/meList', async (req, res) => {
|
||||
|
||||
let userID = req.user.id;
|
||||
|
||||
try {
|
||||
let application = await getAllMemberApplications(userID);
|
||||
|
||||
return res.status(200).json(application);
|
||||
} catch (error) {
|
||||
console.error('Failed to load applications: \n', error);
|
||||
return res.status(500).json(error);
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/me', async (req, res) => {
|
||||
|
||||
let userID = req.user.id;
|
||||
@@ -62,13 +96,17 @@ router.get('/me', async (req, res) => {
|
||||
})
|
||||
|
||||
// GET /application/:id
|
||||
router.get('/:id', async (req, res) => {
|
||||
let appID = req.params.id;
|
||||
console.log("HELLO")
|
||||
router.get('/me/:id', async (req: Request, res: Response) => {
|
||||
let appID = Number(req.params.id);
|
||||
let member = req.user.id;
|
||||
try {
|
||||
const application = await getApplicationByID(appID);
|
||||
if (application === undefined)
|
||||
return res.sendStatus(204);
|
||||
console.log(application.member_id, member)
|
||||
if (application.member_id != member) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
const comments: CommentRow[] = await getApplicationComments(appID);
|
||||
|
||||
@@ -84,30 +122,64 @@ router.get('/:id', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /application/:id
|
||||
router.get('/:id', async (req: Request, res: Response) => {
|
||||
let appID = Number(req.params.id);
|
||||
let asAdmin = !!req.query.admin || false;
|
||||
let user = req.user.id;
|
||||
|
||||
//TODO: Replace this with bigger authorization system eventually
|
||||
if (asAdmin) {
|
||||
let allowed = (await getUserRoles(user)).some((role) =>
|
||||
role.name.toLowerCase() === 'dev' ||
|
||||
role.name.toLowerCase() === 'recruiter' ||
|
||||
role.name.toLowerCase() === 'administrator')
|
||||
console.log(allowed)
|
||||
if (!allowed) {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
}
|
||||
try {
|
||||
const application = await getApplicationByID(appID);
|
||||
if (application === undefined)
|
||||
return res.sendStatus(204);
|
||||
|
||||
const comments: CommentRow[] = await getApplicationComments(appID, asAdmin);
|
||||
|
||||
const output: ApplicationFull = {
|
||||
application,
|
||||
comments,
|
||||
}
|
||||
return res.status(200).json(output);
|
||||
}
|
||||
catch (err) {
|
||||
console.error('Query failed:', err);
|
||||
return res.status(500).json({ error: 'Failed to load application' });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /application/approve/:id
|
||||
router.post('/approve/:id', async (req, res) => {
|
||||
const appID = req.params.id;
|
||||
router.post('/approve/:id', async (req: Request, res: Response) => {
|
||||
const appID = Number(req.params.id);
|
||||
const approved_by = req.user.id;
|
||||
|
||||
try {
|
||||
const app = await getApplicationByID(appID);
|
||||
const result = await approveApplication(appID);
|
||||
|
||||
console.log("START");
|
||||
console.log(app, result);
|
||||
|
||||
//guard against failures
|
||||
if (result.affectedRows != 1) {
|
||||
throw new Error("Something went wrong approving the application");
|
||||
}
|
||||
|
||||
console.log(app.member_id);
|
||||
//update user profile
|
||||
await setUserState(app.member_id, MemberState.Member);
|
||||
|
||||
let nextRank = await getRankByName('Recruit')
|
||||
await insertMemberRank(app.member_id, nextRank.id);
|
||||
//assign user to "pending basic"
|
||||
await assignUserToStatus(app.member_id, 1);
|
||||
await pool.query('CALL sp_accept_new_recruit_validation(?, ?, ?, ?)', [Number(process.env.CONFIG_ID), app.member_id, approved_by, approved_by])
|
||||
// let nextRank = await getRankByName('Recruit')
|
||||
// await insertMemberRank(app.member_id, nextRank.id);
|
||||
// //assign user to "pending basic"
|
||||
// await assignUserToStatus(app.member_id, 1);
|
||||
res.sendStatus(200);
|
||||
} catch (err) {
|
||||
console.error('Approve failed:', err);
|
||||
@@ -119,26 +191,11 @@ router.post('/approve/:id', async (req, res) => {
|
||||
router.post('/deny/:id', async (req, res) => {
|
||||
const appID = req.params.id;
|
||||
|
||||
const sql = `
|
||||
UPDATE applications
|
||||
SET denied_at = NOW()
|
||||
WHERE id = ?
|
||||
AND approved_at IS NULL
|
||||
AND denied_at IS NULL
|
||||
`;
|
||||
try {
|
||||
const result = await pool.execute(sql, appID);
|
||||
|
||||
console.log(result);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
res.status(400).json('Something went wrong denying the application');
|
||||
}
|
||||
|
||||
if (result.affectedRows == 1) {
|
||||
res.sendStatus(200);
|
||||
}
|
||||
|
||||
const app = await getApplicationByID(appID);
|
||||
await denyApplication(appID);
|
||||
await setUserState(app.member_id, MemberState.Denied);
|
||||
res.sendStatus(200);
|
||||
} catch (err) {
|
||||
console.error('Approve failed:', err);
|
||||
res.status(500).json({ error: 'Failed to deny application' });
|
||||
@@ -146,10 +203,12 @@ router.post('/deny/:id', async (req, res) => {
|
||||
});
|
||||
|
||||
// POST /application/:id/comment
|
||||
router.post('/:id/comment', async (req, res) => {
|
||||
router.post('/:id/comment', async (req: Request, res: Response) => {
|
||||
const appID = req.params.id;
|
||||
const data = req.body.message;
|
||||
const user = 1;
|
||||
const user = req.user;
|
||||
|
||||
console.log(user)
|
||||
|
||||
const sql = `INSERT INTO application_comments(
|
||||
application_id,
|
||||
@@ -161,7 +220,7 @@ VALUES(?, ?, ?);`
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
|
||||
const result = await conn.query(sql, [appID, user, data])
|
||||
const result = await conn.query(sql, [appID, user.id, data])
|
||||
console.log(result)
|
||||
if (result.affectedRows !== 1) {
|
||||
conn.release();
|
||||
@@ -186,4 +245,61 @@ VALUES(?, ?, ?);`
|
||||
}
|
||||
});
|
||||
|
||||
// POST /application/:id/comment
|
||||
router.post('/:id/adminComment', async (req: Request, res: Response) => {
|
||||
const appID = req.params.id;
|
||||
const data = req.body.message;
|
||||
const user = req.user;
|
||||
|
||||
console.log(user)
|
||||
|
||||
const sql = `INSERT INTO application_comments(
|
||||
application_id,
|
||||
poster_id,
|
||||
post_content,
|
||||
admin_only
|
||||
)
|
||||
VALUES(?, ?, ?, 1);`
|
||||
|
||||
try {
|
||||
const conn = await pool.getConnection();
|
||||
|
||||
const result = await conn.query(sql, [appID, user.id, data])
|
||||
console.log(result)
|
||||
if (result.affectedRows !== 1) {
|
||||
conn.release();
|
||||
throw new Error("Insert Failure")
|
||||
}
|
||||
|
||||
const getSQL = `SELECT app.id AS comment_id,
|
||||
app.post_content,
|
||||
app.poster_id,
|
||||
app.post_time,
|
||||
app.last_modified,
|
||||
app.admin_only,
|
||||
member.name AS poster_name
|
||||
FROM application_comments AS app
|
||||
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);
|
||||
res.status(500).json({ error: 'Could not post comment' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/restart', async (req: Request, res: Response) => {
|
||||
const user = req.user.id;
|
||||
try {
|
||||
await setUserState(user, MemberState.Guest);
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.error('Comment failed:', error);
|
||||
res.status(500).json({ error: 'Could not rester application' });
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
import pool from '../db';
|
||||
|
||||
//post a new LOA
|
||||
router.post("/", async (req, res) => {
|
||||
const { member_id, filed_date, start_date, end_date, reason } = req.body;
|
||||
|
||||
if (!member_id || !filed_date || !start_date || !end_date) {
|
||||
return res.status(400).json({ error: "Missing required fields" });
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`INSERT INTO leave_of_absences
|
||||
(member_id, filed_date, start_date, end_date, reason)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[member_id, filed_date, start_date, end_date, reason]
|
||||
);
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send('Something went wrong', error);
|
||||
}
|
||||
});
|
||||
|
||||
//get my current LOA
|
||||
router.get("/me", async (req, res) => {
|
||||
//TODO: implement current user getter
|
||||
const user = 89;
|
||||
|
||||
try {
|
||||
const result = await pool.query("SELECT * FROM leave_of_absences WHERE member_id = ?", [user])
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/all', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT loa.*, members.name
|
||||
FROM leave_of_absences AS loa
|
||||
INNER JOIN members ON loa.member_id = members.id;
|
||||
`);
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = router;
|
||||
148
api/src/routes/loa.ts
Normal file
148
api/src/routes/loa.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
import pool from '../db';
|
||||
import { closeLOA, createNewLOA, getAllLOA, getLOAbyID, getLoaTypes, getUserLOA, setLOAExtension } from '../services/loaService';
|
||||
import { LOARequest } from '@app/shared/types/loa';
|
||||
|
||||
//member posts LOA
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
let LOARequest = req.body as LOARequest;
|
||||
LOARequest.member_id = req.user.id;
|
||||
LOARequest.created_by = req.user.id;
|
||||
LOARequest.filed_date = new Date();
|
||||
|
||||
try {
|
||||
await createNewLOA(LOARequest);
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
});
|
||||
|
||||
//admin posts LOA
|
||||
router.post("/admin", async (req: Request, res: Response) => {
|
||||
let LOARequest = req.body as LOARequest;
|
||||
LOARequest.created_by = req.user.id;
|
||||
LOARequest.filed_date = new Date();
|
||||
|
||||
console.log(LOARequest);
|
||||
|
||||
try {
|
||||
await createNewLOA(LOARequest);
|
||||
res.sendStatus(201);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
});
|
||||
|
||||
//get my current LOA
|
||||
router.get("/me", async (req: Request, res: Response) => {
|
||||
const user = req.user.id;
|
||||
try {
|
||||
const result = await getUserLOA(user);
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
})
|
||||
|
||||
//get my LOA history
|
||||
router.get("/history", async (req: Request, res: Response) => {
|
||||
const user = req.user.id;
|
||||
try {
|
||||
const result = await getUserLOA(user);
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/all', async (req, res) => {
|
||||
try {
|
||||
const result = await getAllLOA();
|
||||
res.status(200).json(result)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send(error);
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/types', async (req: Request, res: Response) => {
|
||||
try {
|
||||
let out = await getLoaTypes();
|
||||
res.status(200).json(out);
|
||||
} catch (error) {
|
||||
res.status(500).json(error);
|
||||
console.error(error);
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/cancel/:id', async (req: Request, res: Response) => {
|
||||
let closer = req.user.id;
|
||||
let id = Number(req.params.id);
|
||||
try {
|
||||
let loa = await getLOAbyID(id);
|
||||
if (loa.member_id != closer) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
await closeLOA(Number(req.params.id), closer);
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json(error);
|
||||
}
|
||||
})
|
||||
|
||||
//TODO: enforce admin only
|
||||
router.post('/adminCancel/:id', async (req: Request, res: Response) => {
|
||||
let closer = req.user.id;
|
||||
try {
|
||||
await closeLOA(Number(req.params.id), closer);
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).json(error);
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Enforce admin only
|
||||
router.post('/extend/:id', async (req: Request, res: Response) => {
|
||||
const to: Date = req.body.to;
|
||||
|
||||
if (!to) {
|
||||
res.status(400).send("Extension length is required");
|
||||
}
|
||||
|
||||
try {
|
||||
await setLOAExtension(Number(req.params.id), to);
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
res.status(500).json(error);
|
||||
}
|
||||
})
|
||||
|
||||
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}`,
|
||||
}
|
||||
})
|
||||
|
||||
if (output.ok) {
|
||||
const out = await output.json();
|
||||
res.status(200).json(out.html);
|
||||
} else {
|
||||
console.error("Failed to fetch LOA policy from bookstack");
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = router;
|
||||
@@ -2,6 +2,7 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
import pool from '../db';
|
||||
import { getUserActiveLOA } from '../services/loaService';
|
||||
import { getUserData } from '../services/memberService';
|
||||
import { getUserRoles } from '../services/rolesService';
|
||||
|
||||
@@ -40,12 +41,13 @@ router.get('/me', async (req, res) => {
|
||||
|
||||
try {
|
||||
const { id, name, state } = await getUserData(req.user.id);
|
||||
const LOAData = await pool.query(
|
||||
`SELECT *
|
||||
FROM leave_of_absences
|
||||
WHERE member_id = ?
|
||||
AND deleted = 0
|
||||
AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`, req.user.id);
|
||||
// const LOAData = await pool.query(
|
||||
// `SELECT *
|
||||
// FROM leave_of_absences
|
||||
// WHERE member_id = ?
|
||||
// AND deleted = 0
|
||||
// AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`, req.user.id);
|
||||
const LOAData = await getUserActiveLOA(req.user.id);
|
||||
|
||||
const roleData = await getUserRoles(req.user.id);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ApplicationListRow, ApplicationRow, CommentRow } from "@app/shared/types/application";
|
||||
import pool from "../db";
|
||||
import { error } from "console";
|
||||
|
||||
export async function createApplication(memberID: number, appVersion: number, app: string) {
|
||||
const sql = `INSERT INTO applications (member_id, app_version, app_data) VALUES (?, ?, ?);`;
|
||||
@@ -12,12 +13,13 @@ export async function getMemberApplication(memberID: number): Promise<Applicatio
|
||||
member.name AS member_name
|
||||
FROM applications AS app
|
||||
INNER JOIN members AS member ON member.id = app.member_id
|
||||
WHERE app.member_id = ?;`;
|
||||
WHERE app.member_id = ? ORDER BY submitted_at DESC LIMIT 1;`;
|
||||
|
||||
let app: ApplicationRow[] = await pool.query(sql, [memberID]);
|
||||
return app[0];
|
||||
}
|
||||
|
||||
|
||||
export async function getApplicationByID(appID: number): Promise<ApplicationRow> {
|
||||
const sql =
|
||||
`SELECT app.*,
|
||||
@@ -44,7 +46,20 @@ export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
||||
return rows;
|
||||
}
|
||||
|
||||
export async function approveApplication(id) {
|
||||
export async function getAllMemberApplications(memberID: number): Promise<ApplicationListRow[]> {
|
||||
const sql = `SELECT
|
||||
app.id,
|
||||
app.member_id,
|
||||
app.submitted_at,
|
||||
app.app_status
|
||||
FROM applications AS app WHERE app.member_id = ? ORDER BY submitted_at DESC;`;
|
||||
|
||||
const rows: ApplicationListRow[] = await pool.query(sql, [memberID])
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
export async function approveApplication(id: number) {
|
||||
const sql = `
|
||||
UPDATE applications
|
||||
SET approved_at = NOW()
|
||||
@@ -57,15 +72,38 @@ export async function approveApplication(id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getApplicationComments(appID: number): Promise<CommentRow[]> {
|
||||
export async function denyApplication(id: number) {
|
||||
const sql = `
|
||||
UPDATE applications
|
||||
SET denied_at = NOW()
|
||||
WHERE id = ?
|
||||
AND approved_at IS NULL
|
||||
AND denied_at IS NULL
|
||||
`;
|
||||
|
||||
const result = await pool.execute(sql, id);
|
||||
|
||||
if (result.affectedRows == 1) {
|
||||
return
|
||||
} else {
|
||||
throw new Error(`"Something went wrong denying application with ID ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getApplicationComments(appID: number, admin: boolean = false): Promise<CommentRow[]> {
|
||||
const excludeAdmin = ' AND app.admin_only = false';
|
||||
|
||||
const whereClause = `WHERE app.application_id = ?${!admin ? excludeAdmin : ''}`;
|
||||
|
||||
return await pool.query(`SELECT app.id AS comment_id,
|
||||
app.post_content,
|
||||
app.poster_id,
|
||||
app.post_time,
|
||||
app.last_modified,
|
||||
app.admin_only,
|
||||
member.name AS poster_name
|
||||
FROM application_comments AS app
|
||||
INNER JOIN members AS member ON member.id = app.poster_id
|
||||
WHERE app.application_id = ?;`,
|
||||
${whereClause}`,
|
||||
[appID]);
|
||||
}
|
||||
98
api/src/services/loaService.ts
Normal file
98
api/src/services/loaService.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { toDateTime } from "@app/shared/utils/time";
|
||||
import pool from "../db";
|
||||
import { LOARequest, LOAType } from '@app/shared/types/loa'
|
||||
|
||||
export async function getLoaTypes(): Promise<LOAType[]> {
|
||||
return await pool.query('SELECT * FROM leave_of_absences_types;');
|
||||
}
|
||||
|
||||
export async function getAllLOA(page = 1, pageSize = 20): Promise<LOARequest[]> {
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
const sql = `
|
||||
SELECT loa.*, members.name, t.name AS type_name
|
||||
FROM leave_of_absences AS loa
|
||||
LEFT JOIN members ON loa.member_id = members.id
|
||||
LEFT JOIN leave_of_absences_types AS t ON loa.type_id = t.id
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN loa.closed IS NULL
|
||||
AND NOW() > COALESCE(loa.extended_till, loa.end_date) THEN 1
|
||||
WHEN loa.closed IS NULL
|
||||
AND NOW() BETWEEN loa.start_date AND COALESCE(loa.extended_till, loa.end_date) THEN 2
|
||||
WHEN loa.closed IS NULL AND NOW() < loa.start_date THEN 3
|
||||
WHEN loa.closed IS NOT NULL THEN 4
|
||||
END,
|
||||
loa.start_date DESC
|
||||
LIMIT ? OFFSET ?;
|
||||
`;
|
||||
|
||||
let res: LOARequest[] = await pool.query(sql, [pageSize, offset]) as LOARequest[];
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function getUserLOA(userId: number): Promise<LOARequest[]> {
|
||||
const result: LOARequest[] = await pool.query(`
|
||||
SELECT loa.*, members.name, t.name AS type_name
|
||||
FROM leave_of_absences AS loa
|
||||
LEFT JOIN members ON loa.member_id = members.id
|
||||
LEFT JOIN leave_of_absences_types AS t ON loa.type_id = t.id
|
||||
WHERE member_id = ?
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN loa.closed IS NULL
|
||||
AND NOW() > COALESCE(loa.extended_till, loa.end_date) THEN 1
|
||||
WHEN loa.closed IS NULL
|
||||
AND NOW() BETWEEN loa.start_date AND COALESCE(loa.extended_till, loa.end_date) THEN 2
|
||||
WHEN loa.closed IS NULL AND NOW() < loa.start_date THEN 3
|
||||
WHEN loa.closed IS NOT NULL THEN 4
|
||||
END,
|
||||
loa.start_date DESC
|
||||
`, [userId])
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getUserActiveLOA(userId: number): Promise<LOARequest[]> {
|
||||
const sql = `SELECT *
|
||||
FROM leave_of_absences
|
||||
WHERE member_id = ?
|
||||
AND closed IS NULL
|
||||
AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`
|
||||
const LOAData = await pool.query(sql, [userId]);
|
||||
return LOAData;
|
||||
}
|
||||
|
||||
export async function createNewLOA(data: LOARequest) {
|
||||
const sql = `INSERT INTO leave_of_absences
|
||||
(member_id, filed_date, start_date, end_date, type_id, reason)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`;
|
||||
await pool.query(sql, [data.member_id, toDateTime(data.filed_date), toDateTime(data.start_date), toDateTime(data.end_date), data.type_id, data.reason])
|
||||
return;
|
||||
}
|
||||
|
||||
export async function closeLOA(id: number, closer: number) {
|
||||
const sql = `UPDATE leave_of_absences
|
||||
SET closed = 1,
|
||||
closed_by = ?
|
||||
WHERE leave_of_absences.id = ?`;
|
||||
let out = await pool.query(sql, [closer, id]);
|
||||
console.log(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
export async function getLOAbyID(id: number): Promise<LOARequest> {
|
||||
let res = await pool.query(`SELECT * FROM leave_of_absences WHERE id = ?`, [id]);
|
||||
console.log(res);
|
||||
if (res.length != 1)
|
||||
throw new Error(`LOA with id ${id} not found`);
|
||||
return res[0];
|
||||
}
|
||||
|
||||
export async function setLOAExtension(id: number, extendTo: Date) {
|
||||
let res = await pool.query(`UPDATE leave_of_absences
|
||||
SET extended_till = ?
|
||||
WHERE leave_of_absences.id = ? `, [toDateTime(extendTo), id]);
|
||||
if (res.affectedRows != 1)
|
||||
throw new Error(`Could not extend LOA`);
|
||||
return res[0];
|
||||
}
|
||||
Reference in New Issue
Block a user