import { Role } from "@app/shared/types/roles"; import pool from "../../db"; import { Member, MemberCardDetails, MemberLight, memberSettings, MemberState, PaginatedMembers } from '@app/shared/types/member' import { logger } from "../logging/logger"; import { memberCache } from "../../routes/auth"; import * as mariadb from 'mariadb'; export async function getFilteredMembers( page: number = 1, pageSize: number = 15, search?: string, status?: string, unitId?: string ): Promise { try { const offset = (page - 1) * pageSize; const whereClauses: string[] = []; const params: any[] = []; if (status && status !== 'all') { whereClauses.push(`m.state = ?`); params.push(status); } if (search) { whereClauses.push(`v.member_name LIKE ?`); params.push(`%${search}%`); } if (unitId && unitId !== 'all') { whereClauses.push(`v.unit = ?`); params.push(unitId); } const whereClause = whereClauses.length > 0 ? ` WHERE ${whereClauses.join(' AND ')}` : ''; // COUNT QUERY const countQuery = `SELECT COUNT(*) as total FROM view_member_rank_unit_status_latest v INNER JOIN members m ON v.member_id = m.id ${whereClause}`; const [countResults]: any[] = await pool.query(countQuery, params); const total = Number(countResults?.total) || 0; // DATA QUERY const dataQuery = ` 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 INNER JOIN members m ON v.member_id = m.id ${whereClause} -- Added back correctly ORDER BY v.member_name ASC LIMIT ? OFFSET ? `; const rows: any[] = await pool.query(dataQuery, [...params, pageSize, offset]); // Map rows to Member type const members: Member[] = rows.map(row => ({ member_id: Number(row.member_id), member_name: row.member_name, displayName: row.displayName, rank: row.rank, rank_date: row.rank_date, unit: row.unit, unit_date: row.unit_date, status: row.status, status_date: row.status_date, loa_until: row.loa_until ? new Date(row.loa_until) : undefined, })); return { data: members, pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize), }, }; } catch (error) { logger.error('app', 'Error fetching filtered members', { error: error instanceof Error ? error.message : String(error), }); throw error; } } export async function getUserData(userID: number): Promise { const sql = `SELECT * FROM view_member_rank_unit_status_latest WHERE member_id = ?`; const res: Member = await pool.query(sql, [userID]); return res[0] ?? null; } export async function setUserState(userID: number, state: MemberState, con: mariadb.Pool | mariadb.Connection = pool) { try { const sql = `UPDATE members SET state = ? WHERE id = ?;`; return await con.query(sql, [state, userID]); } catch (error) { logger.error('app', 'Error setting user state', error); } finally { memberCache.Invalidate(userID); } } export async function getUserState(user: number): Promise { let out = await pool.query(`SELECT state FROM members WHERE id = ?`, [user]); return (out[0].state as MemberState); } export async function getMemberSettings(id: number): Promise { const sql = `SELECT * FROM view_member_settings WHERE id = ?`; let out: memberSettings[] = await pool.query(sql, [id]); if (out.length != 1) throw new Error("Could not get user settings"); return out[0]; } export async function setUserSettings(id: number, settings: memberSettings) { const sql = `UPDATE view_member_settings SET displayName = ? WHERE id = ?;`; let result = await pool.query(sql, [settings.displayName, id]) } export async function getMembersLite(ids: number[]): Promise { const sql = `SELECT m.member_id AS id, m.member_name AS username, m.displayName, u.color FROM view_member_rank_unit_status_latest m LEFT JOIN units u ON u.name = m.unit WHERE member_id IN (?);`; const res: MemberLight[] = await pool.query(sql, [ids]); return res; } export async function getAllMembersLite(): Promise { const sql = `SELECT m.member_id AS id, m.member_name AS username, m.displayName, u.color FROM view_member_rank_unit_status_latest m LEFT JOIN units u ON u.name = m.unit;`; const res: MemberLight[] = await pool.query(sql); return res; } export async function getMembersFull(ids: number[]): Promise { const sql = ` SELECT m.*, COALESCE( JSON_ARRAYAGG( CASE WHEN r.id IS NOT NULL THEN JSON_OBJECT( 'id', r.id, 'name', r.name, 'color', r.color, 'description', r.description ) END ), JSON_ARRAY() ) AS roles FROM view_member_rank_unit_status_latest m LEFT JOIN members_roles mr ON m.member_id = mr.member_id LEFT JOIN roles r ON mr.role_id = r.id WHERE m.member_id IN (?) GROUP BY m.member_id; `; const rows: any[] = await pool.query(sql, [ids]); return rows.map(row => { const member: Member = { member_id: row.member_id, member_name: row.member_name, displayName: row.displayName, rank: row.rank, rank_date: row.rank_date, unit: row.unit, unit_date: row.unit_date, status: row.status, status_date: row.status_date, loa_until: row.loa_until ? new Date(row.loa_until) : undefined, }; // roles comes as array of strings; parse each one const roles: Role[] = row.roles; return { member, roles }; }); } export async function mapDiscordtoID(id: number): Promise { const sql = `SELECT id FROM members WHERE discord_id = ?;` let res = await pool.query(sql, [id]); return res.length > 0 ? res[0].id : null; }