fix(materials): картинки материалов отдаются публично (рендер/открытие/скачивание)
/api/files/:id/download требует Bearer-заголовок, поэтому <img>, переход по
ссылке и «Скачать» для сохранённых картинок ломались (битое изображение,
клик не открывал). Теперь личные картинки складываются в uploads/materials и
отдаются статикой (как flashcards): POST /api/files/personal возвращает
{ url:'/uploads/materials/<file>' }. board-clip, material-save, textbook-clip
и рисовалка в my-materials сохраняют этот публичный url.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,11 +47,23 @@ const upload = multer({
|
||||
},
|
||||
});
|
||||
|
||||
/* Personal image upload (Мои материалы): image-only, no library permission. */
|
||||
/* Personal image upload (Мои материалы): image-only, no library permission.
|
||||
* Stored in uploads/materials and served statically (public) so the saved
|
||||
* <img>/open/download URL works without an auth header — these are personal
|
||||
* study clips (board crops, drawings, textbook regions), not gated files. */
|
||||
const MATERIALS_DIR = path.join(UPLOADS_DIR, 'materials');
|
||||
try { require('fs').mkdirSync(MATERIALS_DIR, { recursive: true }); } catch (e) { /* exists */ }
|
||||
const IMG_MIME = ['image/png','image/jpeg','image/gif','image/webp'];
|
||||
const IMG_EXT = new Set(['.png','.jpg','.jpeg','.gif','.webp']);
|
||||
const materialStorage = multer.diskStorage({
|
||||
destination: MATERIALS_DIR,
|
||||
filename: (_req, file, cb) => {
|
||||
const ext = path.extname(file.originalname || '') || '.png';
|
||||
cb(null, require('crypto').randomBytes(16).toString('hex') + ext);
|
||||
},
|
||||
});
|
||||
const imageUpload = multer({
|
||||
storage,
|
||||
storage: materialStorage,
|
||||
limits: { fileSize: 20 * 1024 * 1024 }, // 20 MB
|
||||
fileFilter: (_req, file, cb) => {
|
||||
const ext = path.extname(file.originalname || '').toLowerCase();
|
||||
@@ -65,7 +77,7 @@ 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);
|
||||
router.post('/personal', imageUpload.single('file'), ctrl.uploadPersonalFile);
|
||||
|
||||
/* ── folder routes (must be before /:id to avoid conflicts) ── */
|
||||
router.get('/folders', ctrl.listFolders);
|
||||
|
||||
Reference in New Issue
Block a user