const posts = require('../../../model/posts/posts.model') const wiki = require('../../../model/wiki/wiki.model') const settings = require('../../../model/settings/settings.model') const pages = require('../../../model/pages/pages.model') const mailer = require('../../../utils/mailer') const { getUserFromRequest } = require('../../../utils/auth') const token = require('../../../auth/token') const log = require('../../../utils/logger')('public') // Staff (non-player) roles may see draft pages on the public route; everyone else // gets a 404 for a draft, indistinguishable from a missing page. const STAFF_ROLES = ['admin', 'editor', 'moderator'] function isStaff(req) { const user = getUserFromRequest(req) return Boolean(user && STAFF_ROLES.includes(user.role)) } async function getSettings(req, res) { try { return res.json(await settings.getPublic()) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getStatus(req, res) { try { return res.json({ mode: (await settings.get('site_mode')) || 'live', status_message: (await settings.get('status_message')) || '', }) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getPosts(req, res) { const { category } = req.params if (!posts.isValidUrlCategory(category)) { return res.status(404).json({ message: 'Unknown category' }) } try { return res.json(await posts.listPublished(category)) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getPost(req, res) { const { category, idOrSlug } = req.params if (!posts.isValidUrlCategory(category)) { return res.status(404).json({ message: 'Unknown category' }) } try { const post = await posts.getPublished(category, idOrSlug) if (!post) return res.status(404).json({ message: 'Not found' }) return res.json(post) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getWikiCategories(req, res) { try { return res.json(await wiki.listCategories()) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getWikiTags(req, res) { try { return res.json(await wiki.listTags()) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getWikiList(req, res) { try { // Full-text search takes precedence over category/tag filters. const q = (req.query.q || '').trim() if (q) return res.json(await wiki.search(q, { publishedOnly: true })) const filters = {} if (req.query.category) { const category = await wiki.getCategoryBySlug(req.query.category) if (!category) return res.json([]) // unknown category → no pages filters.categoryId = category.id } if (req.query.tag) { const tag = await wiki.getTagBySlug(req.query.tag) if (!tag) return res.json([]) // unknown tag → no pages filters.tagId = tag.id } return res.json(await wiki.listPublished(filters)) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getWikiPage(req, res) { try { // Public sees published pages only; drafts 404 like any missing page. const page = await wiki.getPublishedBySlug(req.params.slug) if (!page) return res.status(404).json({ message: 'Not found' }) return res.json(page) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function getPage(req, res) { try { // Staff see drafts (live preview); the public sees published pages only. const page = await pages.getBySlug(req.params.slug, { includeUnpublished: isStaff(req) }) if (!page) return res.status(404).json({ message: 'Not found' }) return res.json(page) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } // Token-gated draft preview: renders the page's current block state regardless of // status, for anyone holding the (short-lived, unguessable) link. async function getPagePreview(req, res) { try { const id = Number(req.params.id) const decoded = token.verifyPagePreview(req.params.token) if (!decoded || decoded.pageId !== id) { return res.status(404).json({ message: 'Preview not found or expired' }) } const page = await pages.getById(id) if (!page) return res.status(404).json({ message: 'Not found' }) return res.json(page) } catch (err) { return res.status(500).json({ message: 'Internal Server Error' }) } } async function contact(req, res) { const { name, email, message } = req.body try { const result = await mailer.sendContactMessage({ name, email, message }) return res.json(result) } catch (err) { log.error('contact send failed', err) return res.status(502).json({ message: 'Could not send message right now.' }) } } module.exports = { getSettings, getStatus, getPosts, getPost, getWikiCategories, getWikiTags, getWikiList, getWikiPage, getPage, getPagePreview, contact, }