fix(features): админ видит и открывает все модули, даже отключённые
Скрытие фич в сайдбаре (и kill-switch геймификации) применялось независимо от роли — у админа тоже пропадали пункты отключённых модулей. Админ управляет модулями, поэтому должен видеть и открывать всё. Добавлен admin-override (_isAdminUser, читает getUser() синхронно из localStorage — работает и на ранней FOUC-инъекции): для админа _applyFeatureCss чистит <style>-скрытие и снимает .no-gamification; hideDisabledFeatures выходит до любых скрытий/редиректов; showBoardIfAllowed показывает доску админу всегда. Поведение для student/teacher не изменилось. Verified vm-смоук на реальном api.js 10/10. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -863,10 +863,24 @@ const FEATURE_WIDGETS = {
|
|||||||
pet: ['#hc-pet'],
|
pet: ['#hc-pet'],
|
||||||
textbooks: ['#hc-read'],
|
textbooks: ['#hc-read'],
|
||||||
};
|
};
|
||||||
|
/* Админ видит и имеет доступ ко ВСЕМУ, даже к отключённым модулям (он ими управляет).
|
||||||
|
Поэтому для админа никакие скрытия/редиректы фич не применяются. getUser() читает
|
||||||
|
localStorage синхронно (определён в начале файла) — работает и на ранней sync-инъекции. */
|
||||||
|
function _isAdminUser() {
|
||||||
|
try { return getUser()?.role === 'admin'; } catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
/* Инъекция CSS, прячущего отключённые фичи. Ставится синхронно из localStorage-кэша
|
/* Инъекция CSS, прячущего отключённые фичи. Ставится синхронно из localStorage-кэша
|
||||||
на ранней загрузке (ДО построения сайдбара/виджетов) — против мигания (FOUC),
|
на ранней загрузке (ДО построения сайдбара/виджетов) — против мигания (FOUC),
|
||||||
затем обновляется по свежему /api/features. */
|
затем обновляется по свежему /api/features. */
|
||||||
function _applyFeatureCss(feats) {
|
function _applyFeatureCss(feats) {
|
||||||
|
// Админ — без скрытий: чистим <style> и снимаем kill-switch геймификации.
|
||||||
|
if (_isAdminUser()) {
|
||||||
|
const elA = document.getElementById('ls-feat-hide');
|
||||||
|
if (elA) elA.textContent = '';
|
||||||
|
document.documentElement.classList.remove('no-gamification');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const sels = [];
|
const sels = [];
|
||||||
if (feats) {
|
if (feats) {
|
||||||
for (const [key, hrefs] of Object.entries(FEATURE_HREFS)) {
|
for (const [key, hrefs] of Object.entries(FEATURE_HREFS)) {
|
||||||
@@ -925,18 +939,22 @@ async function showBoardIfAllowed() {
|
|||||||
if (!el) return;
|
if (!el) return;
|
||||||
const user = getUser();
|
const user = getUser();
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
// Админ видит доску всегда (даже если фича отключена) — он ею управляет.
|
||||||
|
if (user.role === 'admin') { el.style.display = ''; return; }
|
||||||
const feats = await loadFeatures();
|
const feats = await loadFeatures();
|
||||||
// Фича выключена (глобально или для класса) → доску не показываем, даже учителю/админу.
|
// Фича выключена (глобально или для класса) → доску не показываем, даже учителю.
|
||||||
// Эта функция зовётся напрямую на многих страницах, поэтому проверка ОБЯЗАТЕЛЬНА,
|
// Эта функция зовётся напрямую на многих страницах, поэтому проверка ОБЯЗАТЕЛЬНА,
|
||||||
// иначе она перекрывает скрытие из hideDisabledFeatures().
|
// иначе она перекрывает скрытие из hideDisabledFeatures().
|
||||||
if (feats.board === false) { el.style.display = 'none'; return; }
|
if (feats.board === false) { el.style.display = 'none'; return; }
|
||||||
if (user.role === 'teacher' || user.role === 'admin') { el.style.display = ''; return; }
|
if (user.role === 'teacher') { el.style.display = ''; return; }
|
||||||
// Student: check if in a class
|
// Student: check if in a class
|
||||||
if (!feats._no_class) el.style.display = '';
|
if (!feats._no_class) el.style.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hideDisabledFeatures() {
|
async function hideDisabledFeatures() {
|
||||||
const feats = await loadFeatures(); // loadFeatures уже вызвал _applyFeatureCss (визуальное скрытие)
|
const feats = await loadFeatures(); // loadFeatures уже вызвал _applyFeatureCss (визуальное скрытие)
|
||||||
|
// Админ видит и открывает всё — никаких скрытий, редиректов и схлопывания групп.
|
||||||
|
if (_isAdminUser()) return;
|
||||||
// Редирект со страницы отключённой фичи (CSS прячет ссылки, а тут уводим со страницы).
|
// Редирект со страницы отключённой фичи (CSS прячет ссылки, а тут уводим со страницы).
|
||||||
for (const [key, hrefs] of Object.entries(FEATURE_HREFS)) {
|
for (const [key, hrefs] of Object.entries(FEATURE_HREFS)) {
|
||||||
if (feats[key] === false) {
|
if (feats[key] === false) {
|
||||||
|
|||||||
Reference in New Issue
Block a user