import type { ResultSetHeader, RowDataPacket } from 'mysql2' import { db, DB } from './db' import { cleanPostHtml } from './forum-sanitize' // Escritura del foro (esquema FusionCMS, ver lib/forum.ts). `poster` es el AccountID. // El texto se guarda como HTML ya saneado con nh3 (cleanPostHtml), no como BBCode: // es la adaptación a nuestro editor TinyMCE. El esquema no cambia (columna `text`). // El título vive en forum_topics.name, un varchar(45) del esquema original. Se recorta // a 45 para no chocar con el modo estricto de MySQL; la validación de longitud real la // hace la API antes de llegar aquí. const TITLE_MAX = 45 export async function createTopic( forumId: number, name: string, posterId: number, text: string, ): Promise { const clean = cleanPostHtml(text) const [res] = await db(DB.web).query( 'INSERT INTO forum_topics (forum, name, sticky, locked, deleted, created) VALUES (?, ?, 0, 0, 0, NOW())', [forumId, name.slice(0, TITLE_MAX)], ) const topicId = res.insertId await db(DB.web).query( 'INSERT INTO forum_posts (topic, poster, text, time, deleted) VALUES (?, ?, ?, NOW(), 0)', [topicId, posterId, clean], ) return topicId } export async function createPost(topicId: number, posterId: number, text: string): Promise { const clean = cleanPostHtml(text) const [res] = await db(DB.web).query( 'INSERT INTO forum_posts (topic, poster, text, time, deleted) VALUES (?, ?, ?, NOW(), 0)', [topicId, posterId, clean], ) return res.insertId } /** Datos mínimos de un post para comprobar permisos (autor + tema). */ export async function getPost( postId: number, ): Promise<{ id: number; topic: number; poster: number; text: string; deleted: boolean } | null> { const [rows] = await db(DB.web).query( 'SELECT id, topic, poster, text, deleted FROM forum_posts WHERE id = ?', [postId], ) const r = rows[0] return r ? { id: r.id, topic: r.topic, poster: r.poster, text: r.text, deleted: r.deleted === 1 } : null } export async function updatePost(postId: number, text: string): Promise { const clean = cleanPostHtml(text) await db(DB.web).query('UPDATE forum_posts SET text = ? WHERE id = ?', [clean, postId]) } export async function setPostDeleted(postId: number, deleted: boolean): Promise { await db(DB.web).query('UPDATE forum_posts SET deleted = ? WHERE id = ?', [deleted ? 1 : 0, postId]) } /** Cambia una bandera del tema (sticky/locked/deleted). Solo moderación. */ export async function setTopicFlag( topicId: number, field: 'sticky' | 'locked' | 'deleted', value: boolean, ): Promise { if (!['sticky', 'locked', 'deleted'].includes(field)) throw new Error('campo no permitido') await db(DB.web).query(`UPDATE forum_topics SET ${field} = ? WHERE id = ?`, [value ? 1 : 0, topicId]) } /** ¿El tema existe, no está borrado y admite respuestas (no cerrado)? */ export async function topicIsReplyable(topicId: number): Promise { const [rows] = await db(DB.web).query( 'SELECT locked FROM forum_topics WHERE id = ? AND deleted = 0', [topicId], ) return Boolean(rows[0] && rows[0].locked !== 1) }