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>
78 lines
4.0 KiB
HTML
78 lines
4.0 KiB
HTML
{% load i18n %}
|
|
{% if message %}
|
|
<div style="margin-bottom:0.875rem; padding:0.625rem 0.875rem; border-radius:0.5rem; font-size:0.8125rem;
|
|
{% if message_type == 'success' %}color:#137333; background:rgba(19,115,51,0.1); border:1px solid rgba(19,115,51,0.25);
|
|
{% else %}color:#d63333; background:rgba(214,51,51,0.1); border:1px solid rgba(214,51,51,0.25);{% endif %}">
|
|
{{ message }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Хлебные крошки -->
|
|
<div style="display:flex; align-items:center; gap:0.375rem; flex-wrap:wrap; margin-bottom:1rem; font-size:0.8125rem;">
|
|
<a href="#" hx-get="/documents/browse/?section={{ section.key }}" hx-target="#documents-browser" hx-swap="innerHTML"
|
|
style="color:var(--color-primary); text-decoration:none; font-weight:500;">{{ section.label }}</a>
|
|
{% for c in crumbs %}
|
|
<span style="color:var(--color-muted-foreground);">/</span>
|
|
{% if forloop.last %}
|
|
<span style="color:var(--color-foreground);">{{ c.name }}</span>
|
|
{% else %}
|
|
<a href="#" hx-get="/documents/browse/?section={{ section.key }}&path={{ c.path|urlencode }}"
|
|
hx-target="#documents-browser" hx-swap="innerHTML"
|
|
style="color:var(--color-primary); text-decoration:none;">{{ c.name }}</a>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{% if error == 'not_configured' %}
|
|
<div style="padding:0.875rem; font-size:0.8125rem; color:var(--color-muted-foreground);">
|
|
{% trans "Файловое хранилище пока не настроено." %}
|
|
</div>
|
|
{% elif error %}
|
|
<div style="padding:0.875rem; font-size:0.8125rem; color:#d63333;">
|
|
{% trans "Не удалось получить список документов." %}
|
|
</div>
|
|
{% else %}
|
|
{% if files %}
|
|
<div style="border:1px solid var(--color-border); border-radius:0.5rem; overflow:hidden; margin-bottom:1rem;">
|
|
<table style="width:100%; border-collapse:collapse; font-size:0.8125rem;">
|
|
<tbody>
|
|
{% for f in files %}
|
|
<tr style="border-bottom:1px solid var(--color-border);" class="tr-hover">
|
|
<td style="padding:0.5rem 0.75rem;">
|
|
{% if f.is_dir %}
|
|
<a href="#" hx-get="/documents/browse/?section={{ section.key }}&path={{ f.path|urlencode }}"
|
|
hx-target="#documents-browser" hx-swap="innerHTML"
|
|
style="color:var(--color-foreground); text-decoration:none; font-weight:500;">📁 {{ f.name }}</a>
|
|
{% else %}
|
|
<a href="/documents/download/?section={{ section.key }}&path={{ sub|urlencode }}&name={{ f.name|urlencode }}"
|
|
style="color:var(--color-primary); text-decoration:none;">📄 {{ f.name }}</a>
|
|
{% endif %}
|
|
</td>
|
|
<td style="padding:0.5rem 0.75rem; text-align:right; color:var(--color-muted-foreground); white-space:nowrap;">
|
|
{% if f.size is not None %}{{ f.size|filesizeformat }}{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div style="padding:0.875rem; font-size:0.8125rem; color:var(--color-muted-foreground); margin-bottom:1rem;">
|
|
{% trans "В этой папке пока нет файлов." %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if section.writable %}
|
|
<form method="post" action="/documents/upload/"
|
|
hx-post="/documents/upload/" hx-target="#documents-browser" hx-swap="innerHTML"
|
|
hx-encoding="multipart/form-data" enctype="multipart/form-data"
|
|
style="display:flex; gap:0.5rem; align-items:center;">
|
|
{% csrf_token %}
|
|
<input type="hidden" name="section" value="{{ section.key }}">
|
|
<input type="hidden" name="path" value="{{ sub }}">
|
|
<input type="file" name="file" required style="font-size:0.8125rem; flex:1; min-width:0;">
|
|
<button type="submit" class="btn btn-primary" style="font-size:0.8125rem; white-space:nowrap;">{% trans "Загрузить" %}</button>
|
|
</form>
|
|
{% endif %}
|
|
{% endif %}
|