Files
Learn_System/frontend/js/material-save.js
T
Maxim Dolgolyov 55c8c5fa51 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>
2026-06-04 14:21:18 +03:00

56 lines
2.5 KiB
JavaScript

'use strict';
/* material-save.js — универсальная кнопка «В мои материалы».
* Тонкий слой поверх LS.saveMaterial / LS.uploadFile: сохраняет заметку,
* ссылку или изображение в личную коллекцию ученика из любой части платформы
* (учебник, экзамен, лаборатория, чат и т.п.).
*
* MaterialSave.note({ title, body, sourceTitle }, btn?)
* MaterialSave.link({ title, url, sourceTitle }, btn?)
* MaterialSave.image({ title, url|blob, name?, sourceTitle }, btn?)
*
* Требует window.LS (api.js). Показывает тост; кнопку (если передана) блокирует на время.
*/
(function () {
function ok() { if (window.LS && LS.toast) LS.toast('Сохранено в «Мои материалы»', 'success'); }
function err(e) { if (window.LS && LS.toast) LS.toast((e && e.message) || 'Ошибка сохранения', 'error'); }
async function note(o, btn) {
o = o || {};
if (!String(o.body || '').trim() && !String(o.title || '').trim()) { err({ message: 'Пустая заметка' }); return; }
if (btn) btn.disabled = true;
try {
await LS.saveMaterial({ kind: 'note', title: o.title || '', body: o.body || '', sourceTitle: o.sourceTitle || null });
ok();
} catch (e) { err(e); } finally { if (btn) btn.disabled = false; }
}
async function link(o, btn) {
o = o || {};
if (!o.url) { err({ message: 'Нет ссылки' }); return; }
if (btn) btn.disabled = true;
try {
await LS.saveMaterial({ kind: 'link', title: o.title || '', url: o.url, sourceTitle: o.sourceTitle || null });
ok();
} catch (e) { err(e); } finally { if (btn) btn.disabled = false; }
}
async function image(o, btn) {
o = o || {};
if (btn) btn.disabled = true;
try {
let url = o.url;
if (o.blob) {
const fd = new FormData();
fd.append('file', o.blob, o.name || 'image.png');
const up = await LS.uploadMaterialFile(fd);
url = LS.downloadFileUrl(up.id);
}
if (!url) throw new Error('Нет изображения');
await LS.saveMaterial({ kind: 'image', title: o.title || '', url: url, sourceTitle: o.sourceTitle || null });
ok();
} catch (e) { err(e); } finally { if (btn) btn.disabled = false; }
}
window.MaterialSave = { note: note, link: link, image: image };
})();