- remove requireAuth from all route files - delete auth.js, tokens.js, users.js routes - delete auth middleware - remove session middleware and all auth deps from index.js - delete login.html and auth-guard.js from web-ui
113 lines
3.8 KiB
JavaScript
113 lines
3.8 KiB
JavaScript
// Asset-scoped comments for the Asset Detail page.
|
|
//
|
|
// Mounted at /api/v1/assets/:assetId/comments via app.use('/api/v1/assets/:assetId/comments', router).
|
|
// Express's :assetId param flows through from the parent mount.
|
|
|
|
import express from 'express';
|
|
import pool from '../db/pool.js';
|
|
|
|
const router = express.Router({ mergeParams: true });
|
|
|
|
function rowToJson(r) {
|
|
return {
|
|
id: r.id,
|
|
asset_id: r.asset_id,
|
|
user_id: r.user_id,
|
|
body: r.body,
|
|
frame_ms: r.frame_ms,
|
|
resolved: r.resolved,
|
|
created_at: r.created_at,
|
|
updated_at: r.updated_at,
|
|
author_name: r.author_name || null,
|
|
author_initials: r.author_initials || null,
|
|
};
|
|
}
|
|
|
|
// GET /api/v1/assets/:assetId/comments
|
|
router.get('/', async (req, res, next) => {
|
|
try {
|
|
const { assetId } = req.params;
|
|
const result = await pool.query(
|
|
`SELECT c.*,
|
|
u.display_name AS author_name,
|
|
UPPER(SUBSTRING(COALESCE(u.display_name, u.username, '?'), 1, 2)) AS author_initials
|
|
FROM asset_comments c
|
|
LEFT JOIN users u ON u.id = c.user_id
|
|
WHERE c.asset_id = $1
|
|
ORDER BY c.created_at ASC`,
|
|
[assetId]
|
|
);
|
|
res.json({ comments: result.rows.map(rowToJson) });
|
|
} catch (err) { next(err); }
|
|
});
|
|
|
|
// POST /api/v1/assets/:assetId/comments
|
|
router.post('/', async (req, res, next) => {
|
|
try {
|
|
const { assetId } = req.params;
|
|
const { body, frame_ms } = req.body || {};
|
|
if (!body || !String(body).trim()) {
|
|
return res.status(400).json({ error: 'body is required' });
|
|
}
|
|
// Best-effort author lookup — pull from the session if AUTH_ENABLED is on.
|
|
const userId = req.session?.userId || null;
|
|
|
|
const ins = await pool.query(
|
|
`INSERT INTO asset_comments (asset_id, user_id, body, frame_ms)
|
|
VALUES ($1, $2, $3, $4)
|
|
RETURNING *`,
|
|
[assetId, userId, String(body).trim(), frame_ms != null ? Math.max(0, Math.round(Number(frame_ms))) : null]
|
|
);
|
|
|
|
// Re-fetch with the author join so the response has the same shape as list.
|
|
const result = await pool.query(
|
|
`SELECT c.*,
|
|
u.display_name AS author_name,
|
|
UPPER(SUBSTRING(COALESCE(u.display_name, u.username, '?'), 1, 2)) AS author_initials
|
|
FROM asset_comments c
|
|
LEFT JOIN users u ON u.id = c.user_id
|
|
WHERE c.id = $1`,
|
|
[ins.rows[0].id]
|
|
);
|
|
res.status(201).json(rowToJson(result.rows[0]));
|
|
} catch (err) { next(err); }
|
|
});
|
|
|
|
// PATCH /api/v1/assets/:assetId/comments/:id
|
|
router.patch('/:id', async (req, res, next) => {
|
|
try {
|
|
const { id, assetId } = req.params;
|
|
const { body, resolved } = req.body || {};
|
|
const fields = [];
|
|
const values = [];
|
|
let i = 1;
|
|
if (body !== undefined) { fields.push(`body = $${i++}`); values.push(String(body).trim()); }
|
|
if (resolved !== undefined) { fields.push(`resolved = $${i++}`); values.push(!!resolved); }
|
|
if (fields.length === 0) return res.status(400).json({ error: 'Nothing to update' });
|
|
fields.push('updated_at = NOW()');
|
|
values.push(id, assetId);
|
|
const result = await pool.query(
|
|
`UPDATE asset_comments SET ${fields.join(', ')}
|
|
WHERE id = $${i++} AND asset_id = $${i}
|
|
RETURNING *`,
|
|
values
|
|
);
|
|
if (result.rows.length === 0) return res.status(404).json({ error: 'Comment not found' });
|
|
res.json(rowToJson(result.rows[0]));
|
|
} catch (err) { next(err); }
|
|
});
|
|
|
|
// DELETE /api/v1/assets/:assetId/comments/:id
|
|
router.delete('/:id', async (req, res, next) => {
|
|
try {
|
|
const { id, assetId } = req.params;
|
|
const result = await pool.query(
|
|
`DELETE FROM asset_comments WHERE id = $1 AND asset_id = $2 RETURNING id`,
|
|
[id, assetId]
|
|
);
|
|
if (result.rows.length === 0) return res.status(404).json({ error: 'Comment not found' });
|
|
res.json({ id });
|
|
} catch (err) { next(err); }
|
|
});
|
|
|
|
export default router;
|