Files
NightSpire/web-next/lib/admin-prices.ts
T
Inna 0f71e1f4d9 Admin: gestión de precios de los servicios de personaje
- lib/admin-prices.ts: PRICE_TABLES (rename/customize/change-race/change-faction/
  level-up/transfer -> home_*price), getAllPrices, setPrice (fila única: DELETE+INSERT).
- Route /api/admin/prices (POST, guard isAdmin). Página /admin/prices con
  AdminPricesManager (editar cada precio). Enlace en el dashboard admin.
- Catálogo Admin (precios + nombres de servicio).

Verificado: /admin/prices redirige sin permiso, API 403; setPrice escribe en BD
correctamente (probado con env cargado). Pendiente admin: sitios de voto, gold options,
moderación del foro.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 23:59:45 +00:00

42 lines
1.2 KiB
TypeScript

import type { RowDataPacket } from 'mysql2'
import { db, DB } from './db'
// Servicios con precio único (una fila) -> tabla django_wow.
export const PRICE_TABLES: Record<string, string> = {
rename: 'home_renameprice',
customize: 'home_customizeprice',
'change-race': 'home_changeraceprice',
'change-faction': 'home_changefactionprice',
'level-up': 'home_levelupprice',
transfer: 'home_transferprice',
}
export interface PriceRow {
service: string
price: number
}
export async function getAllPrices(): Promise<PriceRow[]> {
const out: PriceRow[] = []
for (const [service, table] of Object.entries(PRICE_TABLES)) {
let price = 0
try {
const [rows] = await db(DB.default).query<RowDataPacket[]>(`SELECT price FROM ${table} LIMIT 1`)
price = rows[0] ? Number(rows[0].price) : 0
} catch {
/* ignore */
}
out.push({ service, price })
}
return out
}
/** Fija el precio (fila única) de un servicio. */
export async function setPrice(service: string, value: number): Promise<boolean> {
const table = PRICE_TABLES[service]
if (!table || !(value >= 0)) return false
await db(DB.default).query(`DELETE FROM ${table}`)
await db(DB.default).query(`INSERT INTO ${table} (price) VALUES (?)`, [value])
return true
}