Foro: mover tema entre foros (moderadores)

- lib/forum-write.ts: moveTopic (forum_id + moved=1). lib/forum.ts: listForumsForMove.
- API /api/forum/moderate: acción 'move' con forumId, validando foro destino visible
  y distinto del actual.
- TopicModBar: selector «Mover a» con los foros visibles (excl. el actual); tras mover,
  redirige al foro destino.
- i18n es/en: Forum.moveTopic.

Verificado: build OK, move 401 sin sesión, /forum 200.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-13 01:01:48 +00:00
parent 0247c6cc38
commit 7c1cd195ff
7 changed files with 69 additions and 10 deletions
@@ -1,7 +1,7 @@
import { notFound } from 'next/navigation'
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { Link } from '@/i18n/navigation'
import { getTopic, getPosts, countPosts } from '@/lib/forum'
import { getTopic, getPosts, countPosts, listForumsForMove } from '@/lib/forum'
import { getSession } from '@/lib/session'
import { forumIsModerator, canEditPost } from '@/lib/forum-perm'
import { ReplyForm } from '@/components/ReplyForm'
@@ -33,6 +33,7 @@ export default async function TopicPage({
const posts = await getPosts(id, (page - 1) * PER_PAGE, PER_PAGE)
const session = await getSession()
const isMod = await forumIsModerator(session)
const moveForums = isMod ? (await listForumsForMove()).filter((f) => f.id !== topic!.forum_id) : []
const canReply = Boolean(session.username) && (!topic!.locked || isMod)
return (
@@ -48,7 +49,9 @@ export default async function TopicPage({
{topic!.name}
</h1>
{isMod && <TopicModBar topicId={id} locked={topic!.locked} sticky={topic!.sticky} />}
{isMod && (
<TopicModBar topicId={id} locked={topic!.locked} sticky={topic!.sticky} moveForums={moveForums} />
)}
<div className="space-y-4">
{posts.map((post) => (
+14 -3
View File
@@ -1,9 +1,9 @@
import { getSession } from '@/lib/session'
import { getTopic } from '@/lib/forum'
import { setTopicFlag } from '@/lib/forum-write'
import { getTopic, getForum } from '@/lib/forum'
import { setTopicFlag, moveTopic } from '@/lib/forum-write'
import { forumIsModerator } from '@/lib/forum-perm'
type Action = 'lock' | 'unlock' | 'sticky' | 'unsticky' | 'delete'
type Action = 'lock' | 'unlock' | 'sticky' | 'unsticky' | 'delete' | 'move'
/** Moderación de temas: bloquear, fijar, borrar. Solo moderadores. */
export async function POST(request: Request) {
@@ -36,6 +36,17 @@ export async function POST(request: Request) {
case 'delete':
await setTopicFlag(topicId, 'deleted', true)
return Response.json({ success: true, forumId: topic.forum_id })
case 'move': {
const newForumId = Number(b.forumId)
if (!newForumId || newForumId === topic.forum_id) {
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
}
if (!(await getForum(newForumId))) {
return Response.json({ success: false, error: 'invalidForum' }, { status: 400 })
}
await moveTopic(topicId, newForumId)
return Response.json({ success: true })
}
default:
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
}