85c5c995ee
Los formularios de crear categoría/foro aceptan nombre/descripción en inglés, y se añade EDICIÓN en línea de categorías (name, name_en, order) y foros (name, name_en, description, description_en). lib/admin-forum: createCategory/createForum con EN + updateCategory/updateForum; rutas PUT en category/[id] y forum/[id]. Claves Admin nuevas (nombre/descripción EN). Verificado: listado con EN + update round-trip; PUT protegido (403 sin admin). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
118 lines
3.8 KiB
TypeScript
118 lines
3.8 KiB
TypeScript
import type { RowDataPacket, ResultSetHeader } from 'mysql2'
|
|
import { db, DB } from './db'
|
|
|
|
export interface AdminCategory {
|
|
id: number
|
|
name: string
|
|
name_en: string
|
|
order: number
|
|
}
|
|
|
|
export interface AdminForum {
|
|
id: number
|
|
category_id: number
|
|
name: string
|
|
name_en: string
|
|
description: string
|
|
description_en: string
|
|
order: number
|
|
visibility: number
|
|
}
|
|
|
|
/** Categorías con sus foros (incluye ocultos y sin borrar), para el admin. */
|
|
export async function listCategoriesWithForums(): Promise<
|
|
{ category: AdminCategory; forums: AdminForum[] }[]
|
|
> {
|
|
const [cats] = await db(DB.web).query<RowDataPacket[]>(
|
|
'SELECT id, name, name_en, `order` FROM forum_categories ORDER BY `order`, id',
|
|
)
|
|
const [forums] = await db(DB.web).query<RowDataPacket[]>(
|
|
'SELECT id, category_id, name, name_en, description, description_en, `order`, visibility FROM forums WHERE deleted = 0 ORDER BY `order`, id',
|
|
)
|
|
return cats.map((c) => ({
|
|
category: { id: c.id, name: c.name, name_en: c.name_en || '', order: c.order },
|
|
forums: forums
|
|
.filter((f) => f.category_id === c.id)
|
|
.map((f) => ({
|
|
id: f.id,
|
|
category_id: f.category_id,
|
|
name: f.name,
|
|
name_en: f.name_en || '',
|
|
description: f.description,
|
|
description_en: f.description_en || '',
|
|
order: f.order,
|
|
visibility: f.visibility,
|
|
})),
|
|
}))
|
|
}
|
|
|
|
export async function createCategory(name: string, nameEn: string | null, order: number): Promise<number> {
|
|
const [res] = await db(DB.web).query<ResultSetHeader>(
|
|
'INSERT INTO forum_categories (name, name_en, `order`, created_at) VALUES (?, ?, ?, NOW())',
|
|
[name, nameEn || null, order],
|
|
)
|
|
return res.insertId
|
|
}
|
|
|
|
export async function updateCategory(id: number, name: string, nameEn: string | null, order: number): Promise<void> {
|
|
await db(DB.web).query('UPDATE forum_categories SET name = ?, name_en = ?, `order` = ? WHERE id = ?', [
|
|
name,
|
|
nameEn || null,
|
|
order,
|
|
id,
|
|
])
|
|
}
|
|
|
|
/** Borra una categoría solo si no tiene foros (no borrados). */
|
|
export async function deleteCategory(id: number): Promise<boolean> {
|
|
const [f] = await db(DB.web).query<RowDataPacket[]>(
|
|
'SELECT COUNT(*) AS n FROM forums WHERE category_id = ? AND deleted = 0',
|
|
[id],
|
|
)
|
|
if (Number(f[0]?.n ?? 0) > 0) return false
|
|
await db(DB.web).query('DELETE FROM forum_categories WHERE id = ?', [id])
|
|
return true
|
|
}
|
|
|
|
export async function createForum(
|
|
categoryId: number,
|
|
name: string,
|
|
nameEn: string | null,
|
|
description: string,
|
|
descriptionEn: string | null,
|
|
order: number,
|
|
visibility: number,
|
|
): Promise<number> {
|
|
const [res] = await db(DB.web).query<ResultSetHeader>(
|
|
'INSERT INTO forums (category_id, name, name_en, description, description_en, `order`, type, visibility, deleted, created_at, updated_at) ' +
|
|
'VALUES (?, ?, ?, ?, ?, ?, 0, ?, 0, NOW(), NOW())',
|
|
[categoryId, name, nameEn || null, description, descriptionEn || null, order, visibility ? 1 : 0],
|
|
)
|
|
return res.insertId
|
|
}
|
|
|
|
export async function updateForum(
|
|
id: number,
|
|
name: string,
|
|
nameEn: string | null,
|
|
description: string,
|
|
descriptionEn: string | null,
|
|
order: number,
|
|
visibility: number,
|
|
): Promise<void> {
|
|
await db(DB.web).query(
|
|
'UPDATE forums SET name = ?, name_en = ?, description = ?, description_en = ?, `order` = ?, visibility = ?, updated_at = NOW() WHERE id = ?',
|
|
[name, nameEn || null, description, descriptionEn || null, order, visibility ? 1 : 0, id],
|
|
)
|
|
}
|
|
|
|
/** Borrado lógico de un foro (deleted = 1). */
|
|
export async function deleteForum(id: number): Promise<void> {
|
|
await db(DB.web).query('UPDATE forums SET deleted = 1 WHERE id = ?', [id])
|
|
}
|
|
|
|
/** Cambia la visibilidad de un foro. */
|
|
export async function setForumVisibility(id: number, visible: boolean): Promise<void> {
|
|
await db(DB.web).query('UPDATE forums SET visibility = ? WHERE id = ?', [visible ? 1 : 0, id])
|
|
}
|