feat(modules): soft delete with restore and active filter
This commit is contained in:
@@ -670,8 +670,10 @@ async function ensureModulesTable() {
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(200) NOT NULL UNIQUE,
|
||||
lessons_count INT NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
)`);
|
||||
await pool.query('ALTER TABLE modules ADD COLUMN IF NOT EXISTS is_active BOOLEAN NOT NULL DEFAULT true');
|
||||
await pool.query('ALTER TABLE entries ADD COLUMN IF NOT EXISTS module_id INT REFERENCES modules(id) ON DELETE SET NULL');
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_entries_module_id ON entries(module_id)');
|
||||
}
|
||||
@@ -1346,6 +1348,7 @@ function normalizeRestoreData(data) {
|
||||
id: reqInt(x.id),
|
||||
name: reqStr(x.name, 200),
|
||||
lessons_count: optInt(x.lessons_count, 0, 10000) ?? 0,
|
||||
is_active: x.is_active !== false,
|
||||
created_at: optTs(x.created_at),
|
||||
}));
|
||||
const entry_photos = (data.entry_photos || []).map(x => ({
|
||||
@@ -1529,8 +1532,8 @@ app.post('/api/restore', requireAdmin, uploadBackup.single('backup'), async (req
|
||||
}
|
||||
for (const x of ndata.modules) {
|
||||
await client.query(
|
||||
'INSERT INTO modules (id, name, lessons_count, created_at) VALUES ($1,$2,$3,$4)',
|
||||
[x.id, x.name, x.lessons_count, x.created_at]
|
||||
'INSERT INTO modules (id, name, lessons_count, is_active, created_at) VALUES ($1,$2,$3,$4,$5)',
|
||||
[x.id, x.name, x.lessons_count, x.is_active, x.created_at]
|
||||
);
|
||||
}
|
||||
for (const x of ndata.entries) {
|
||||
@@ -2291,17 +2294,18 @@ app.put('/api/groups/:id/photos/:photoId/cover', requireAuth, async (req, res) =
|
||||
|
||||
// --- Modules (темы модулей) ---
|
||||
app.get('/api/modules', apiLimiter, async (req, res) => {
|
||||
const { limit, offset, search } = req.query;
|
||||
const { limit, offset, search, active } = req.query;
|
||||
const conditions = [];
|
||||
const params = [];
|
||||
if (search?.trim()) { params.push(`%${search.trim()}%`); conditions.push(`m.name ILIKE $${params.length}`); }
|
||||
if (active === '1' || active === 'true') conditions.push('m.is_active = true');
|
||||
const where = conditions.length ? ' WHERE ' + conditions.join(' AND ') : '';
|
||||
const { rows: crows } = await pool.query(`SELECT count(*)::int AS n FROM modules m${where}`, params);
|
||||
const total = crows[0].n;
|
||||
let q = `SELECT m.*, count(e.id)::int AS entries_count
|
||||
FROM modules m
|
||||
LEFT JOIN entries e ON e.module_id = m.id${where}
|
||||
GROUP BY m.id ORDER BY m.id`;
|
||||
GROUP BY m.id ORDER BY m.is_active DESC, m.id`;
|
||||
const qparams = params.slice();
|
||||
const lim = parseInt(limit, 10);
|
||||
if (lim > 0) { qparams.push(lim); q += ` LIMIT $${qparams.length}`; }
|
||||
@@ -2358,12 +2362,19 @@ app.put('/api/modules/:id', requireAdmin, async (req, res) => {
|
||||
});
|
||||
|
||||
app.delete('/api/modules/:id', requireAdmin, async (req, res) => {
|
||||
const { rows } = await pool.query('DELETE FROM modules WHERE id = $1 RETURNING id', [req.params.id]);
|
||||
const { rows } = await pool.query('UPDATE modules SET is_active = false WHERE id = $1 RETURNING id', [req.params.id]);
|
||||
if (!rows.length) return res.status(404).json({ error: 'Не найдено' });
|
||||
await logAudit(req, 'module.delete', { id: req.params.id });
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
app.put('/api/modules/:id/restore', requireAdmin, async (req, res) => {
|
||||
const { rows } = await pool.query('UPDATE modules SET is_active = true WHERE id = $1 RETURNING *', [req.params.id]);
|
||||
if (!rows.length) return res.status(404).json({ error: 'Не найдено' });
|
||||
await logAudit(req, 'module.restore', { id: req.params.id });
|
||||
res.json(rows[0]);
|
||||
});
|
||||
|
||||
// --- Students CRUD ---
|
||||
app.get('/api/students', apiLimiter, optionalAuth, async (req, res) => {
|
||||
const rows = await cacheWrap('students:list:' + scopeKey(req.user), PUBLIC_TTL_MS, async () => {
|
||||
|
||||
Reference in New Issue
Block a user