Split server/index.js into one file per area
Build and Push Docker Image / build-and-push (push) Successful in 5m37s
Build and Push Docker Image / build-and-push (push) Successful in 5m37s
Routes move to server/routes/ (auth, account, projects, reader, sharing, admin); index.js keeps setup only. A smoke test walks 90 API calls against the real server and compares every status with the pre-split behaviour. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
31ac6b9179
commit
9893883b19
12 files changed
+1337
-1040
No files matched your search
@@ -0,0 +1,104 @@
|
||||
// Studies: list, load, save (with conflict checks), earlier versions, delete.
|
||||
import { canEditProject, deleteProject, getAllProjects, getProject, getProjectEdited, getVersion, listVersions, restoreVersion, upsertProject } from '../db.js';
|
||||
import { requireAuth } from '../auth.js';
|
||||
import { isSaveConflict, parseBase } from '../projectSync.js';
|
||||
|
||||
export function registerProjectRoutes(app) {
|
||||
// GET /api/projects — list all project summaries owned by the current user
|
||||
// ---------------------------------------------------------------------------
|
||||
app.get('/api/projects', requireAuth, (req, res) => {
|
||||
try {
|
||||
const projects = getAllProjects(req.session.userId);
|
||||
res.json(projects);
|
||||
} catch (err) {
|
||||
console.error('GET /api/projects error:', err);
|
||||
res.status(500).json({ error: 'Failed to list projects.' });
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GET /api/projects/:id — fetch a single full project owned by the current user
|
||||
// ---------------------------------------------------------------------------
|
||||
app.get('/api/projects/:id', requireAuth, (req, res) => {
|
||||
try {
|
||||
const project = getProject(req.params.id, req.session.userId);
|
||||
if (!project) return res.status(404).json({ error: 'Project not found.' });
|
||||
res.json(project);
|
||||
} catch (err) {
|
||||
console.error('GET /api/projects/:id error:', err);
|
||||
res.status(500).json({ error: 'Failed to load project.' });
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PUT /api/projects/:id — create or update a project owned by the current user
|
||||
// ---------------------------------------------------------------------------
|
||||
app.put('/api/projects/:id', requireAuth, (req, res) => {
|
||||
try {
|
||||
const body = req.body;
|
||||
if (!body || typeof body !== 'object') {
|
||||
return res.status(400).json({ error: 'Invalid JSON body.' });
|
||||
}
|
||||
if (!body.id || !body.title || !Array.isArray(body.chapters)) {
|
||||
return res.status(400).json({ error: 'Missing required fields: id, title, chapters.' });
|
||||
}
|
||||
if (body.id !== req.params.id) {
|
||||
return res.status(400).json({ error: 'URL id does not match body id.' });
|
||||
}
|
||||
if (body.id.length > 100) return res.status(400).json({ error: 'Invalid project id.' });
|
||||
if (body.title.length > 500) return res.status(400).json({ error: 'Project title is too long.' });
|
||||
// Refuse to overwrite a copy another device saved after the one this device last saw
|
||||
const stored = getProjectEdited(body.id, req.session.userId);
|
||||
if (isSaveConflict({ stored, base: parseBase(req.get('X-Base-Edited')), force: req.query.force === '1' })) {
|
||||
return res.status(409).json({ error: 'This study was changed on another device.', code: 'conflict', serverEdited: stored });
|
||||
}
|
||||
const saved = upsertProject(body, req.session.userId);
|
||||
if (!saved) {
|
||||
return res.status(403).json({ error: 'That project belongs to a different account.' });
|
||||
}
|
||||
res.json(saved);
|
||||
} catch (err) {
|
||||
console.error('PUT /api/projects/:id error:', err);
|
||||
res.status(500).json({ error: 'Failed to save project.' });
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Earlier versions of a study: list, look at one, and put one back (the copy it replaces is kept too)
|
||||
// ---------------------------------------------------------------------------
|
||||
app.get('/api/projects/:id/versions', requireAuth, (req, res) => {
|
||||
if (!canEditProject(req.params.id, req.session.userId)) return res.status(404).json({ error: 'Project not found.' });
|
||||
res.json({ versions: listVersions(req.params.id) });
|
||||
});
|
||||
|
||||
app.get('/api/projects/:id/versions/:versionId', requireAuth, (req, res) => {
|
||||
if (!canEditProject(req.params.id, req.session.userId)) return res.status(404).json({ error: 'Project not found.' });
|
||||
const version = getVersion(req.params.id, Number(req.params.versionId));
|
||||
if (!version) return res.status(404).json({ error: 'That version is gone.' });
|
||||
res.json(version);
|
||||
});
|
||||
|
||||
app.post('/api/projects/:id/versions/:versionId/restore', requireAuth, (req, res) => {
|
||||
try {
|
||||
const restored = restoreVersion(req.params.id, Number(req.params.versionId), req.session.userId);
|
||||
if (!restored) return res.status(404).json({ error: 'That version is gone.' });
|
||||
res.json(restored);
|
||||
} catch (err) {
|
||||
console.error('POST restore error:', err);
|
||||
res.status(500).json({ error: 'Failed to restore that version.' });
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DELETE /api/projects/:id — remove a project owned by the current user
|
||||
// ---------------------------------------------------------------------------
|
||||
app.delete('/api/projects/:id', requireAuth, (req, res) => {
|
||||
try {
|
||||
deleteProject(req.params.id, req.session.userId);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error('DELETE /api/projects/:id error:', err);
|
||||
res.status(500).json({ error: 'Failed to delete project.' });
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user