feat(prep): мастер-флаг подготовки к направлению (ЦТ) + коллекции колод — бэкенд
Система «готовится к ЦТ»: флаг student_prep(user_id,track) открывает ученику ВЕСЬ контент трека (карточки + курс + пробники) динамически, без материализации. - мигр.078: таблица student_prep + flashcard_decks.collection + разметка ЦТ-колод 'ct-math' - services/prepTracks.js: реестр треков (трек→коллекция/курсы/экзамены), устойчив до миграции - contentAccess.resolve/allowedRefs: учитывают мастер-флаг (явный запрет ученика побеждает) - flashcardController.deckAccess/listDecks: колоды коллекции открыты по флагу - prepController + /api/prep: учитель (своим) и админ ставят/снимают флаг (ученику/классу) - js/api.js: LS.prep* обёртки Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
/* prepTracks — направления подготовки (ЦТ и др.) и их контент («мастер-флаг»).
|
||||
*
|
||||
* Флаг student_prep(user_id, track) открывает ученику ВЕСЬ контент трека:
|
||||
* - коллекцию флешкарт (flashcard_decks.collection)
|
||||
* - курсы (content_type='course', content_ref=id курса)
|
||||
* - экзамен-модули (content_type='exam', content_ref=exam_key)
|
||||
* Доступ резолвится ДИНАМИЧЕСКИ (без материализации правил content_access):
|
||||
* - contentAccess.resolve/allowedRefs читают trackGrants/trackRefs;
|
||||
* - flashcardController.deckAccess/listDecks читают studentCollections.
|
||||
*
|
||||
* Добавить направление = добавить запись в TRACKS (+ при необходимости миграцию,
|
||||
* проставляющую collection нужным колодам). Никаких изменений в резолверах. */
|
||||
const db = require('../db/db');
|
||||
|
||||
/* Реестр треков. collection — ключ коллекции колод (flashcard_decks.collection);
|
||||
content — что открывает трек, по типам content_access. */
|
||||
const TRACKS = {
|
||||
'ct-math': {
|
||||
title: 'ЦТ/ЦЭ — математика',
|
||||
label: 'Подготовка к ЦТ',
|
||||
collection: 'ct-math',
|
||||
content: { course: ['13'], exam: ['ctmath'] },
|
||||
},
|
||||
};
|
||||
|
||||
function isTrack(track) { return Object.prototype.hasOwnProperty.call(TRACKS, track); }
|
||||
|
||||
/* Множество известных треков, включённых у пользователя.
|
||||
Inline-prepare + try/catch: до миграции 078 (нет таблицы student_prep) фича
|
||||
просто не активна (пустой набор), а не падает на загрузке модуля/в тестах. */
|
||||
function studentTracks(userId) {
|
||||
try {
|
||||
const rows = db.prepare('SELECT track FROM student_prep WHERE user_id = ?').all(userId);
|
||||
return new Set(rows.map(r => r.track).filter(isTrack));
|
||||
} catch (_) {
|
||||
return new Set();
|
||||
}
|
||||
}
|
||||
|
||||
/* Множество collection-ключей, открытых пользователю его треками. */
|
||||
function studentCollections(userId) {
|
||||
const out = new Set();
|
||||
for (const t of studentTracks(userId)) {
|
||||
if (TRACKS[t].collection) out.add(TRACKS[t].collection);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Открывает ли какой-либо трек пользователя данный (type, ref)? */
|
||||
function trackGrants(userId, type, ref) {
|
||||
const r = String(ref);
|
||||
for (const t of studentTracks(userId)) {
|
||||
const refs = TRACKS[t].content && TRACKS[t].content[type];
|
||||
if (refs && refs.includes(r)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* content_ref'ы данного типа, открытые треками пользователя (для allowedRefs). */
|
||||
function trackRefs(userId, type) {
|
||||
const out = new Set();
|
||||
for (const t of studentTracks(userId)) {
|
||||
const refs = TRACKS[t].content && TRACKS[t].content[type];
|
||||
if (refs) refs.forEach(x => out.add(String(x)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Список треков для UI: [{ key, title, label }]. */
|
||||
function listTracks() {
|
||||
return Object.entries(TRACKS).map(([key, t]) => ({ key, title: t.title, label: t.label }));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TRACKS, isTrack, studentTracks, studentCollections,
|
||||
trackGrants, trackRefs, listTracks,
|
||||
};
|
||||
Reference in New Issue
Block a user