ed7dcaae3b
Заменяет статичный макет documents.html реальным браузером Group Folders: - access.py: accessible_sections (разделы по правам: Компания/Обучение/Обмен, отдел сотрудника, Кадровые дела для суперюзера) + safe_relpath (посегментная валидация подпути от path traversal); раздел резолвится только из whitelist - views: documents_browse/download/upload с проверкой раздела и пути на каждом эндпоинте, запись — только в writable-разделы - documents.html: вкладки разделов + ленивый HTMX-браузер с хлебными крошками, навигацией по папкам, скачиванием и загрузкой - documents_view отдаёт доступные разделы; тесты разделов, путей и авторизации Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
2.6 KiB
HTML
47 lines
2.6 KiB
HTML
{% load i18n %}
|
|
<div class="page-content">
|
|
|
|
<div style="margin-bottom:1.5rem;">
|
|
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">{% trans "Документы" %}</h1>
|
|
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{% trans "Файловое хранилище: общие документы, обучение, отделы" %}</p>
|
|
</div>
|
|
|
|
{% if sections %}
|
|
<!-- Разделы хранилища -->
|
|
<div style="display:flex; gap:2px; background:var(--color-muted); border-radius:var(--radius); padding:3px; width:fit-content; margin-bottom:1.25rem; flex-wrap:wrap;">
|
|
{% for s in sections %}
|
|
<button type="button" class="doc-section-btn{% if forloop.first %} doc-section-active{% endif %}" data-section="{{ s.key }}"
|
|
onclick="docSectionSwitch('{{ s.key }}')"
|
|
style="padding:0.3125rem 1rem; border-radius:calc(var(--radius) - 2px); font-size:0.8125rem; font-weight:500; border:none; cursor:pointer; {% if forloop.first %}background:var(--color-card); color:var(--color-foreground);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{{ s.label }}</button>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); padding:1.25rem;">
|
|
<div id="documents-browser"
|
|
style="font-size:0.8125rem; color:var(--color-muted-foreground);"
|
|
hx-get="/documents/browse/?section={{ sections.0.key }}"
|
|
hx-trigger="load" hx-swap="innerHTML">
|
|
{% trans "Загрузка…" %}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.5rem; font-size:0.875rem; color:var(--color-muted-foreground);">
|
|
{% trans "Нет доступных разделов документов." %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
<script>
|
|
function docSectionSwitch(key) {
|
|
document.querySelectorAll('.doc-section-btn').forEach(function (btn) {
|
|
var active = btn.getAttribute('data-section') === key;
|
|
btn.classList.toggle('doc-section-active', active);
|
|
btn.style.background = active ? 'var(--color-card)' : 'transparent';
|
|
btn.style.color = active ? 'var(--color-foreground)' : 'var(--color-muted-foreground)';
|
|
});
|
|
htmx.ajax('GET', '/documents/browse/?section=' + encodeURIComponent(key),
|
|
{ target: '#documents-browser', swap: 'innerHTML' });
|
|
}
|
|
</script>
|