Add curator roles/permissions with Users admin, and fix lineage branch joins.

Staff accounts use admin/curator roles and fine-grained flags; transitions connect source-to-target with color gradients and stream cutout masks so overlaps stay seamless.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Danila KhodjaefandCursor committed 2026-07-27 18:04:17 +03:00
1 parent bfa21989c9
commit 0466b77328
31 files changed
+1492 -269

No files matched your search

+7 -7
View File
@@ -1,6 +1,6 @@
const express = require('express');
const pool = require('../db');
const { requireCurator } = require('../middleware/auth');
const { requirePermission } = require('../middleware/auth');
const { logCuratorAction } = require('../audit-log');
const {
TRANSLATABLE_FIELDS,
@@ -14,7 +14,7 @@ const router = express.Router();
const VALID_ENTITY_TYPES = new Set(Object.keys(TRANSLATABLE_FIELDS));
router.get('/worklist/:entityType', requireCurator, async (req, res) => {
router.get('/worklist/:entityType', requirePermission('translations'), async (req, res) => {
try {
const entityType = req.params.entityType;
const locale = typeof req.query.locale === 'string' ? req.query.locale : 'ru';
@@ -75,7 +75,7 @@ router.get('/worklist/:entityType', requireCurator, async (req, res) => {
}
});
router.get('/coverage', requireCurator, async (req, res) => {
router.get('/coverage', requirePermission('translations'), async (req, res) => {
try {
const locale = typeof req.query.locale === 'string' ? req.query.locale : 'ru';
const coverage = await getTranslationCoverage(locale);
@@ -86,7 +86,7 @@ router.get('/coverage', requireCurator, async (req, res) => {
}
});
router.get('/', requireCurator, async (req, res) => {
router.get('/', requirePermission('translations'), async (req, res) => {
try {
const entityType = typeof req.query.entityType === 'string' ? req.query.entityType : undefined;
const locale = typeof req.query.locale === 'string' ? req.query.locale : 'ru';
@@ -99,7 +99,7 @@ router.get('/', requireCurator, async (req, res) => {
}
});
router.get('/:entityType/:id', requireCurator, async (req, res) => {
router.get('/:entityType/:id', requirePermission('translations'), async (req, res) => {
try {
const entityType = req.params.entityType;
const entityId = parseInt(req.params.id, 10);
@@ -133,7 +133,7 @@ router.get('/:entityType/:id', requireCurator, async (req, res) => {
}
});
router.put('/:entityType/:id', requireCurator, async (req, res) => {
router.put('/:entityType/:id', requirePermission('translations'), async (req, res) => {
try {
const entityType = req.params.entityType;
const entityId = parseInt(req.params.id, 10);
@@ -185,7 +185,7 @@ router.put('/:entityType/:id', requireCurator, async (req, res) => {
}
});
router.post('/:entityType/:id/publish', requireCurator, async (req, res) => {
router.post('/:entityType/:id/publish', requirePermission('translations'), async (req, res) => {
try {
const entityType = req.params.entityType;
const entityId = parseInt(req.params.id, 10);