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
+1 -1
View File
@@ -20,7 +20,7 @@
async function uploadBlob(blob, name) {
const fd = new FormData();
fd.append('file', blob, name);
const up = await LS.uploadFile(fd);
const up = await LS.uploadMaterialFile(fd);
return LS.downloadFileUrl(up.id);
}
+1 -1
View File
@@ -42,7 +42,7 @@
if (o.blob) {
const fd = new FormData();
fd.append('file', o.blob, o.name || 'image.png');
const up = await LS.uploadFile(fd);
const up = await LS.uploadMaterialFile(fd);
url = LS.downloadFileUrl(up.id);
}
if (!url) throw new Error('Нет изображения');
+1 -1
View File
@@ -180,7 +180,7 @@
try {
var fd = new FormData();
fd.append('file', blob, 'textbook-region.png');
var up = await LS.uploadFile(fd);
var up = await LS.uploadMaterialFile(fd);
await LS.saveMaterial({
kind: 'image',
title: input.value.trim() || sectionTitle(),
+1 -1
View File
@@ -379,7 +379,7 @@
try {
if (!blob) throw new Error('Не удалось сохранить рисунок');
const fd = new FormData(); fd.append('file', blob, 'drawing.png');
const up = await LS.uploadFile(fd);
const up = await LS.uploadMaterialFile(fd);
await LS.saveMaterial({ kind: 'image', title: o.title || 'Рисунок', url: LS.downloadFileUrl(up.id), sourceTitle: o.sourceTitle || null });
close(); load(); LS.toast('Сохранено в «Мои материалы»', 'success');
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); btn.disabled = false; }