diff --git a/backend/documents/admin.py b/backend/documents/admin.py
index 143e9f0e..e33f3f43 100644
--- a/backend/documents/admin.py
+++ b/backend/documents/admin.py
@@ -15,7 +15,6 @@ from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html, mark_safe
from django.urls import reverse
-from django_fsm import get_available_FIELD_transitions
from .models import Document, DocumentAcknowledgement
from django.contrib.auth import get_user_model
@@ -61,14 +60,13 @@ class DocumentAdmin(admin.ModelAdmin):
list_display = (
'title',
- 'status_badge', # FSM статус с цветовым индикатором
'file_thumbnail',
'file_info',
'uploaded_at',
'sent_to_all',
'acknowledgement_status',
)
- list_filter = ('status', 'sent_to_all', 'uploaded_at', 'departments')
+ list_filter = ('sent_to_all', 'uploaded_at', 'departments')
search_fields = ('title', 'description', 'file__name', 'file__description')
filter_horizontal = ('recipients', 'departments')
actions = ['send_document']
@@ -80,7 +78,6 @@ class DocumentAdmin(admin.ModelAdmin):
(None, {
'fields': (
'title',
- 'status', # FSM статус
'file', # FilerFileField с drag & drop
'file_preview', # Превью файла
'description',
@@ -89,10 +86,6 @@ class DocumentAdmin(admin.ModelAdmin):
'recipients'
),
}),
- (_('Workflow'), {
- 'fields': ('available_transitions',),
- 'classes': ('collapse',),
- }),
(_('Meta'), {
'fields': ('uploaded_by', 'uploaded_at', 'file_size', 'file_extension'),
'classes': ('collapse',),
@@ -102,8 +95,6 @@ class DocumentAdmin(admin.ModelAdmin):
}),
)
readonly_fields = (
- 'status', # FSM поле только через transitions
- 'available_transitions',
'uploaded_by',
'uploaded_at',
'file_preview',
@@ -119,43 +110,6 @@ class DocumentAdmin(admin.ModelAdmin):
obj.uploaded_by = request.user
super().save_model(request, obj, form, change)
- def status_badge(self, obj):
- """Статус документа с цветовым индикатором."""
- colors = {
- 'draft': '#6c757d', # серый
- 'in_review': '#0dcaf0', # голубой
- 'approved': '#198754', # зеленый
- 'published': '#0d6efd', # синий
- 'archived': '#6c757d', # серый
- 'rejected': '#dc3545', # красный
- }
- color = colors.get(obj.status, '#6c757d')
- return format_html(
- '{}',
- color,
- obj.get_status_display()
- )
- status_badge.short_description = _('Статус')
-
- def available_transitions(self, obj):
- """Список доступных переходов (transitions) для текущего состояния."""
- if not obj.pk:
- return '—'
-
- transitions = get_available_FIELD_transitions(obj, Document.status)
- if not transitions:
- return format_html('Нет доступных переходов')
-
- html = '
'
- for transition in transitions:
- html += f'- {transition.name}: {transition.target}
'
- html += '
'
-
- return mark_safe(html)
-
- available_transitions.short_description = _('Доступные переходы')
-
def file_thumbnail(self, obj):
"""Превью файла в списке документов."""
if not obj.file:
diff --git a/backend/eusrr_backend/settings.py b/backend/eusrr_backend/settings.py
index 5f98a48b..e5da09fc 100644
--- a/backend/eusrr_backend/settings.py
+++ b/backend/eusrr_backend/settings.py
@@ -198,6 +198,13 @@ REGISTRATION_ALLOWED_IPS = [
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
MEDIA_URL = "/media/"
+# Структура медиа папки:
+# media/
+# ├── documents/ ← Документы (читаемая структура по годам/месяцам)
+# ├── avatars/ ← Аватары пользователей
+# ├── chat_attachments/ ← Вложения в чате
+# └── temp/ ← Временные файлы
+
# Лимиты загрузки файлов
# По умолчанию Django ограничивает загрузку до 2.5MB
# Увеличиваем до 10MB для аватаров и документов
@@ -548,6 +555,44 @@ FILER_ENABLE_PERMISSIONS = True # Включаем ACL для файлов
FILER_IS_PUBLIC_DEFAULT = False # По умолчанию файлы приватные
FILER_CANONICAL_URL = 'canonical/' # URL для канонических ссылок
+# Настройка хранилищ для разных типов файлов
+FILER_STORAGES = {
+ 'public': {
+ 'main': {
+ 'ENGINE': 'filer.storage.PublicFileSystemStorage',
+ 'OPTIONS': {
+ 'location': os.path.join(MEDIA_ROOT, 'documents/public/'),
+ 'base_url': '/media/documents/public/',
+ },
+ 'UPLOAD_TO': 'filer.utils.generate_filename.by_date', # Структура: 2026/03/14/filename.pdf
+ },
+ 'thumbnails': {
+ 'ENGINE': 'filer.storage.PublicFileSystemStorage',
+ 'OPTIONS': {
+ 'location': os.path.join(MEDIA_ROOT, 'documents/public_thumbnails/'),
+ 'base_url': '/media/documents/public_thumbnails/',
+ },
+ },
+ },
+ 'private': {
+ 'main': {
+ 'ENGINE': 'filer.storage.PrivateFileSystemStorage',
+ 'OPTIONS': {
+ 'location': os.path.join(MEDIA_ROOT, 'documents/private/'),
+ 'base_url': '/smedia/documents/private/',
+ },
+ 'UPLOAD_TO': 'filer.utils.generate_filename.by_date', # Структура: 2026/03/14/filename.pdf
+ },
+ 'thumbnails': {
+ 'ENGINE': 'filer.storage.PrivateFileSystemStorage',
+ 'OPTIONS': {
+ 'location': os.path.join(MEDIA_ROOT, 'documents/private_thumbnails/'),
+ 'base_url': '/smedia/documents/private_thumbnails/',
+ },
+ },
+ },
+}
+
# easy-thumbnails настройки для filer
THUMBNAIL_PROCESSORS = (
'easy_thumbnails.processors.colorspace',
diff --git a/backend/eusrr_backend/urls.py b/backend/eusrr_backend/urls.py
index 5c51d773..47d4319d 100644
--- a/backend/eusrr_backend/urls.py
+++ b/backend/eusrr_backend/urls.py
@@ -42,7 +42,11 @@ urlpatterns = [
path("api/", include(("api.urls", "api"), namespace="api")),
# Service Worker должен быть в корне для правильного scope
path("sw.js", serve_service_worker, name="sw"),
- # django-filer URLs для обработки приватных файлов
+ # django-filer URLs для обработки приватных файлов (с проверкой прав доступа)
path("", include("filer.server.urls")),
path("", include("feed.urls_front", namespace="feed")),
-] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+]
+
+# Публичные медиа файлы (без проверки прав) - только в режиме разработки
+if settings.DEBUG:
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/backend/search/search_indexes.py b/backend/search/search_indexes.py
index c876fba3..19c75890 100644
--- a/backend/search/search_indexes.py
+++ b/backend/search/search_indexes.py
@@ -163,7 +163,7 @@ if Document:
Document,
adapter_cls=DocumentAdapter,
fields=("title", "description", "extracted_text"), # Добавлен extracted_text!
- store=("title", "uploaded_at", "status"),
+ store=("title", "uploaded_at"),
)
# 12. Уведомления (Notifications)