monitor/core/routes/player/modal.ts
2025-04-16 22:30:27 +07:00

98 lines
3.6 KiB
TypeScript

const modulename = 'WebServer:PlayerModal';
import dateFormat from 'dateformat';
import playerResolver from '@lib/player/playerResolver';
import { PlayerHistoryItem, PlayerModalResp, PlayerModalPlayerData } from '@shared/playerApiTypes';
import { DatabaseActionType } from '@modules/Database/databaseTypes';
import { ServerPlayer } from '@lib/player/playerClasses';
import consoleFactory from '@lib/console';
import { AuthedCtx } from '@modules/WebServer/ctxTypes';
import { now } from '@lib/misc';
import { SYM_CURRENT_MUTEX } from '@lib/symbols';
const console = consoleFactory(modulename);
//Helpers
const processHistoryLog = (hist: DatabaseActionType[]) => {
try {
return hist.map((log): PlayerHistoryItem => {
return {
id: log.id,
type: log.type,
reason: log.reason,
author: log.author,
ts: log.timestamp,
exp: log.expiration ? log.expiration : undefined,
revokedBy: log.revocation.author ? log.revocation.author : undefined,
revokedAt: log.revocation.timestamp ? log.revocation.timestamp : undefined,
};
});
} catch (error) {
console.error(`Error processing player history: ${(error as Error).message}`);
return [];
}
};
/**
* Returns the data for the player's modal
* NOTE: sending license instead of id to be able to show data even for offline players
*/
export default async function PlayerModal(ctx: AuthedCtx) {
//Sanity check
if (typeof ctx.query === 'undefined') {
return ctx.utils.error(400, 'Invalid Request');
}
const { mutex, netid, license } = ctx.query;
const sendTypedResp = (data: PlayerModalResp) => ctx.send(data);
//Finding the player
let player;
try {
const refMutex = mutex === 'current' ? SYM_CURRENT_MUTEX : mutex;
player = playerResolver(refMutex, parseInt((netid as string)), license);
} catch (error) {
return sendTypedResp({ error: (error as Error).message });
}
//Prepping player data
const playerData: PlayerModalPlayerData = {
displayName: player.displayName,
pureName: player.pureName,
isRegistered: player.isRegistered,
isConnected: player.isConnected,
license: player.license,
ids: player.ids,
hwids: player.hwids,
actionHistory: processHistoryLog(player.getHistory()),
}
if (player instanceof ServerPlayer) {
playerData.netid = player.netid;
playerData.sessionTime = Math.ceil((now() - player.tsConnected) / 60);
}
const playerDbData = player.getDbData();
if (playerDbData) {
playerData.tsJoined = playerDbData.tsJoined;
playerData.playTime = playerDbData.playTime;
playerData.tsWhitelisted = playerDbData.tsWhitelisted ? playerDbData.tsWhitelisted : undefined;
playerData.oldIds = playerDbData.ids;
playerData.oldHwids = playerDbData.hwids;
playerData.tsLastConnection = playerDbData.tsLastConnection;
if (playerDbData.notes?.lastAdmin && playerDbData.notes?.tsLastEdit) {
playerData.notes = playerDbData.notes.text;
const lastEditObj = new Date(playerDbData.notes.tsLastEdit * 1000);
const lastEditString = dateFormat(lastEditObj, 'longDate');
playerData.notesLog = `Last modified by ${playerDbData.notes.lastAdmin} at ${lastEditString}`;
}
}
// console.dir(metaFields);
// console.dir(playerData);
return sendTypedResp({
serverTime: now(),
banTemplates: txConfig.banlist.templates, //TODO: move this to websocket push
player: playerData
});
};