fix(materials): личная загрузка картинок без права library.upload

POST /api/files требует teacher/admin + library.upload — поэтому сохранение
картинок в «Мои материалы» (вырезка области учебника, обрезка доски,
рисунок, аннотация) падало с 403 у учеников и учителей без этого права.

Добавлен auth-only эндпоинт POST /api/files/personal (только картинки,
is_public=1) + LS.uploadMaterialFile. На него переключены board-clip,
material-save, textbook-clip (вырезка области) и рисовалка в my-materials.
Загрузка в учительскую библиотеку (library/lesson-editor) не тронута.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-04 14:21:18 +03:00
parent ac1857c931
commit 55c8c5fa51
7 changed files with 63 additions and 6 deletions
+14
View File
@@ -47,11 +47,25 @@ const upload = multer({
},
});
/* Personal image upload (Мои материалы): image-only, no library permission. */
const IMG_MIME = ['image/png','image/jpeg','image/gif','image/webp'];
const IMG_EXT = new Set(['.png','.jpg','.jpeg','.gif','.webp']);
const imageUpload = multer({
storage,
limits: { fileSize: 20 * 1024 * 1024 }, // 20 MB
fileFilter: (_req, file, cb) => {
const ext = path.extname(file.originalname || '').toLowerCase();
cb(null, IMG_MIME.includes(file.mimetype) && (IMG_EXT.has(ext) || ext === ''));
},
});
/* ── routes ─────────────────────────────────────────────────────────────── */
router.use(authMiddleware);
router.get('/', ctrl.listFiles);
router.post('/', requireRole('teacher','admin'), requirePermission('library.upload'), upload.single('file'), fixUtf8Name, ctrl.uploadFile);
// Personal materials upload — any authenticated user (covered by router-level authMiddleware)
router.post('/personal', imageUpload.single('file'), fixUtf8Name, ctrl.uploadPersonalFile);
/* ── folder routes (must be before /:id to avoid conflicts) ── */
router.get('/folders', ctrl.listFolders);