Harden app security controls from audit
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { t } from "./i18n.js";
|
||||
import { state } from "./state.js";
|
||||
import { $ } from "./dom.js";
|
||||
import { buildLinkOptionLabel, escapeHtml, truncate } from "./ui-utils.js";
|
||||
import { buildLinkOptionLabel, truncate } from "./ui-utils.js";
|
||||
|
||||
function displayPlayerStatus(player) {
|
||||
if (!player) return "";
|
||||
@@ -16,14 +16,24 @@ function displayPlayerStatus(player) {
|
||||
}
|
||||
|
||||
function buildStatusSelect(player) {
|
||||
const statusText = displayPlayerStatus(player);
|
||||
const canMoveToSuggest = player.phase === "Vote";
|
||||
return `
|
||||
<select class="chip admin-status-select" data-set-player-phase="${player.playerId}" aria-label="${t("admin.playerStatus")}">
|
||||
<option value="" selected>${statusText}</option>
|
||||
<option value="Suggest" ${canMoveToSuggest ? "" : "disabled"}>${t("admin.statusMoveToSuggest")}</option>
|
||||
</select>
|
||||
`;
|
||||
const select = document.createElement("select");
|
||||
select.className = "chip admin-status-select";
|
||||
select.dataset.setPlayerPhase = player.playerId;
|
||||
select.setAttribute("aria-label", t("admin.playerStatus"));
|
||||
|
||||
const current = document.createElement("option");
|
||||
current.value = "";
|
||||
current.selected = true;
|
||||
current.textContent = displayPlayerStatus(player);
|
||||
|
||||
const suggest = document.createElement("option");
|
||||
suggest.value = "Suggest";
|
||||
suggest.disabled = !canMoveToSuggest;
|
||||
suggest.textContent = t("admin.statusMoveToSuggest");
|
||||
|
||||
select.append(current, suggest);
|
||||
return select;
|
||||
}
|
||||
|
||||
export function renderAdminVoteStatus() {
|
||||
@@ -36,17 +46,49 @@ export function renderAdminVoteStatus() {
|
||||
table.innerHTML = "";
|
||||
state.adminVoteStatus.voters.forEach((v) => {
|
||||
const tr = document.createElement("tr");
|
||||
const gamesTooltip = escapeHtml((v.suggestionTitles || []).join(", "));
|
||||
const nameText = escapeHtml(truncate(v.name, 28));
|
||||
const userText = escapeHtml(truncate(v.username, 24));
|
||||
tr.innerHTML = `
|
||||
<td title="${escapeHtml(v.name)}">${nameText}</td>
|
||||
<td class="muted small" title="${escapeHtml(v.username)}">${userText}</td>
|
||||
<td>${buildStatusSelect(v)}</td>
|
||||
<td title="${gamesTooltip}">${v.suggestionCount ?? 0}</td>
|
||||
<td><button class="chip" data-grant-joker="${v.playerId}" type="button">${v.hasJoker ? "🎟" : t("admin.grantJokerChip")}</button></td>
|
||||
<td><button class="chip danger-chip" data-delete-player="${v.playerId}" data-name="${v.name}" type="button">✕</button></td>
|
||||
`;
|
||||
const gamesTooltip = (v.suggestionTitles || []).join(", ");
|
||||
|
||||
const nameCell = document.createElement("td");
|
||||
nameCell.title = v.name ?? "";
|
||||
nameCell.textContent = truncate(v.name, 28);
|
||||
|
||||
const usernameCell = document.createElement("td");
|
||||
usernameCell.className = "muted small";
|
||||
usernameCell.title = v.username ?? "";
|
||||
usernameCell.textContent = truncate(v.username, 24);
|
||||
|
||||
const statusCell = document.createElement("td");
|
||||
statusCell.appendChild(buildStatusSelect(v));
|
||||
|
||||
const countCell = document.createElement("td");
|
||||
countCell.title = gamesTooltip;
|
||||
countCell.textContent = String(v.suggestionCount ?? 0);
|
||||
|
||||
const jokerCell = document.createElement("td");
|
||||
const jokerButton = document.createElement("button");
|
||||
jokerButton.className = "chip";
|
||||
jokerButton.dataset.grantJoker = v.playerId;
|
||||
jokerButton.type = "button";
|
||||
jokerButton.textContent = v.hasJoker ? "🎟" : t("admin.grantJokerChip");
|
||||
jokerCell.appendChild(jokerButton);
|
||||
|
||||
const deleteCell = document.createElement("td");
|
||||
const deleteButton = document.createElement("button");
|
||||
deleteButton.className = "chip danger-chip";
|
||||
deleteButton.dataset.deletePlayer = v.playerId;
|
||||
deleteButton.dataset.name = v.name ?? "";
|
||||
deleteButton.type = "button";
|
||||
deleteButton.textContent = "✕";
|
||||
deleteCell.appendChild(deleteButton);
|
||||
|
||||
tr.append(
|
||||
nameCell,
|
||||
usernameCell,
|
||||
statusCell,
|
||||
countCell,
|
||||
jokerCell,
|
||||
deleteCell,
|
||||
);
|
||||
table.appendChild(tr);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user