Commit Graph

51 Commits

Author SHA1 Message Date
lokses 31bd4c8fa7 it_manager: справочник типовых работ в журнале WorkLog.
Категория/работа/required_details вместо свободного work_type; seed Directory, отчёт и тесты.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-07 13:38:07 +03:00
lokses 7a149dd84d portal: отдельные виджеты PNMS/PVMS-прав в ролях и seed-миграции.
Вынесены can_* для кассы и посещаемости, синхронизация в builders/signals, seed групп в core.0023–0024.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 17:22:41 +03:00
lokses 5800f79eec documents: иерархия отделов и ACL на папки/файлы с people-picker.
В /documents/ добавлено дерево департаментов, права view/edit через DocumentAccessGrant и выдача доступа сотрудникам/отделам/группам.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 17:21:01 +03:00
lokses 9c8d0d109a mail: несколько ящиков с переключателем; дислокация без скоупа локаций
Сотрудник может подключить несколько IMAP-ящиков и переключаться между ними.
Дислокация снова показывает всю сеть, а не только назначенные аптеки.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 15:56:13 +03:00
lokses 9e1505296a nav: новая структура меню — Управление, Поддержка, отдельный блок IT
Справочники и Настройки в Управление; IT-отдел и AD — только при доступе.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 14:22:18 +03:00
lokses b0fb8c5218 rename: «Учётные данные» → «Операционный учёт» в меню и портале
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 14:14:31 +03:00
lokses bd176827c6 admin: search_fields у Directory — для autocomplete на карточке сотрудника
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 13:54:20 +03:00
lokses 4c2984a81e chat: same-origin /chat/api proxy вместо прямого CORS к Mattermost
Браузер больше не ходит на chat.* с portal.* — REST идёт через Django с PAT;
WS backoff без бесконечных 403; utilities.js ждёт DOMContentLoaded.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 12:53:04 +03:00
lokses a2fe4a49e3 mail + portal: самоподключение почты, веб-клиент и глобальный поиск
Сотрудник сам подключает ящик (autoconfig, вложения, пагинация списка, надёжный IMAP-поиск); в хедере работает /api/search по разделам и сущностям с ACL. Также устойчивость Mattermost-токена для чата.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 12:22:53 +03:00
lokses 3387418332 dashboard: группировка виджетов по ширине (½ / полная)
Каждому виджету можно задать ширину: «Полная» (на всю строку) или «½».
Виджеты выстраиваются в flex-сетку: два «½» встают в один ряд, «Полная»
занимает строку целиком. На узких экранах половинные переносятся в столбик.

- DashboardLayout.widget_widths (JSON {ключ: half|full}) + миграция 0022;
  поле widgets не тронуто — обратная совместимость сохранена
- core/dashboard: layout_widths, ширина в build_dashboard_context/
  customize_rows, save_layout(widths=...), normalize_width
- dashboard.html: flex-wrap сетка по ширине; customize: переключатель ½/полная
- tests: 6 (сохранение/чтение ширин, нормализация, дефолт, контекст, POST)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-22 10:47:14 +03:00
lokses 0057f367a2 core: кастомные страницы ошибок 404/403/500/503 + режим техработ
Единый стиль портала (логотип, тема, кнопки) через error_base.html:
- 404 — страница не найдена
- 403 — доступ запрещён (+ ссылка на IT-поддержку)
- 500 — внутренняя ошибка (автономна: без request/context-процессоров)
- 503 — технические работы

MaintenanceModeMiddleware: при MAINTENANCE_MODE=True отдаёт 503 всем, кроме
суперпользователей и путей входа/админки/статики (чтобы админ мог войти и
выключить режим). По умолчанию выключен — поведение не меняется.

- tests: рендер всех шаблонов, кастомный 404, режим техработ вкл/выкл/супер

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 23:54:34 +03:00
lokses 7d319a8331 tests: починка после переименования пути админки
Тесты больше не хардкодят /admin/ — путь берётся из reverse (admin:index /
именованный admin-URL), поэтому переименование префикса админки их не ломает.
Плюс подчинённому в EmployeeDetailTests задан email, не содержащий логин —
иначе проверка «логин скрыт от руководителя» ложно срабатывала на подстроку.

- apps/employees/tests: reverse('admin:employees_employee_change')
- core/tests_user_groups: matrix_url через reverse('admin:index')
- core/tests: distinct email у подчинённого

Полный прогон: 560 тестов, 0 провалов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 23:13:23 +03:00
lokses fa323d657c locations: недостающие модули области доступа + гейт reports
Делает HEAD целостным: коммит 5366799 уже импортировал эти файлы, но они
не были добавлены в git (свежий checkout падал с ImportError, а migrate не
создавал таблицу GroupLocationAccess).

- core/location_access.py: область данных (accessible_pharmacies/locations,
  scoped_queryset/employees, has_all_locations) — fail-closed
- apps/locations/models/access.py + миграция 0014: GroupLocationAccess,
  право locations.view_all_locations
- core/tests_location_access.py: 15 сценариев scoping
- apps/reports/*: снятие лишнего гейта has_all_locations с IT-отчёта отдела
  (руководитель не обязан иметь доступ ко всей сети) + тест
- apps/rro/tests: чужая аптека теперь 404 (единая область доступа), а не
  «200 с урезанными панелями» — под новую модель

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 22:59:47 +03:00
lokses 536679925a Правки логики 2026-09-21 20:37:18 +03:00
lokses 24331df462 dashboard: проверка доступности виджетов и плиток быстрого доступа
Виджеты теперь могут требовать доступ к разделу портала (required_section).
Недоступный виджет не отдаётся и не предлагается в настройке — даже если
остался в сохранённой раскладке или в наборе по умолчанию; save_layout
отбрасывает недоступные ключи (защита от подмены). Виджет «Метрики»
(общекорпоративная сводка) требует доступа к разделу «Отчёты».

Плитки в «Быстром доступе» скрываются по can_section (Документы, Задачи,
Календарь, Сотрудники) — как email и справочники ранее; остаются только
разделы, доступные пользователю.

- core/dashboard.py: required_section, widget_allowed, accessible_keys;
  фильтрация в resolve/customize/save
- quick_access.html: плитки под can_section
- tests: 6 тестов доступности (скрытие/показ, отбрасывание, ре-фильтр)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 19:02:48 +03:00
lokses df137e1074 dashboard: виджеты «Ближайшие события», «Мои HR-заявки», «Мои IT-заявки»
Три новых виджета к кастомизируемому дашборду:
- upcoming — праздники, отпуска, ДР, смены и встречи на 2 недели вперёд;
  переиспользует сборщики календаря (с их логикой видимости) через новый
  calendar_service.upcoming_events()
- my_hr_requests — статусы моих кадровых заявок (отпуск/больничный/отгул)
- my_tickets — мои открытые обращения в IT-поддержку

Все три — в реестре DASHBOARD_WIDGETS, доступны в настройке дашборда и
наборах по умолчанию. Тесты: реестр, контекст HR-заявок, рендер виджетов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 18:53:06 +03:00
lokses d07b9c6e97 dashboard: кастомизируемый дашборд из виджетов + шаблоны по умолчанию
Дашборд теперь собирается из виджетов (приветствие, метрики, мои задачи,
новости, быстрый доступ). Сотрудник настраивает состав и порядок под себя
(вкл/выкл + перемещение ↑↓), а для тех, кто не настраивал, действует набор
по умолчанию по типу локации (Офис/Аптека/Склад), задаётся в админке.

- core/dashboard.py: реестр виджетов + сборка раскладки
- core/models/dashboard.py: DashboardLayout (персональная), DashboardDefaults
  (синглтон по типу локации)
- core/views.py: dashboard_view через реестр + dashboard_customize_view
- templates/pages/dashboard_widgets/*: виджеты-партиалы; dashboard.html —
  цикл по виджетам; dashboard_customize.html — настройка (HTMX + ↑↓)
- admin: DashboardDefaults (чекбоксами по локации) + read-only раскладки;
  пункт меню «Дашборд по умолчанию»
- core/tests_dashboard.py: 11 тестов (логика раскладки + view)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 18:42:21 +03:00
lokses b2f0c2a1e2 core/portal: сотрудник без группы видит только базовые разделы
Ранее разделы с perm=None (Новости, Задачи, Дислокация, Документы, Чат,
Календарь, HR-портал, Справка) были доступны любому вошедшему — сотрудник
без назначенной группы видел почти весь портал. Теперь такие разделы
требуют хотя бы одной группы; без групп доступны только базовые:
Главная, Профиль, Поддержка IT.

- user_can_access: BASELINE_OPEN_KEYS + gate «есть ли группа» для perm=None
- PortalSectionAccessMiddleware: барьер по префиксу URL (в т.ч. вложенные
  страницы вроде /tasks/5/), /settings/ не гейтим (редирект на свой профиль)
- index.html: пункты меню под can_section (сайдбар, дропдаун, bottom-nav),
  секция «Управление» скрывается целиком, если пусто
- тесты: политика без-группы + прямой заход по URL; тест-фабрики выдают
  группу (реальный сотрудник её имеет)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 18:26:15 +03:00
lokses a62f023a90 employees: сводка итоговых разрешений на карточке сотрудника
На карточке Employee — вкладка «Доступ (сводка)»: по каждому
ограниченному разделу портала показывает итог (есть/нет) и источник
(какая группа дала право, individual grant/revoke override, личное право).

Считается теми же правилами, что Employee.has_perm (override имеет
приоритет над группами), поэтому сводка 1-в-1 совпадает с реальной
проверкой доступа. Править по-прежнему: поле «Группы» + инлайн
«Доп. права на разделы портала» (grant/revoke).

- core/access_summary.py: employee_access_summary()
- EmployeeAdmin: readonly effective_access_summary + вкладка
- core/tests_access_summary.py: 6 тестов (в т.ч. совпадение с has_perm)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 17:21:58 +03:00
lokses 7074244479 admin: полная матрица доступа групп в админке
Кнопка «Матрица доступа» на списке групп (unfold actions_list) открывает
сетку: строки — разделы портала, колонки — все группы, галочки просмотра.
Сохранение через apply_full_access_matrix (CUD не трогает — они на карточке
группы). Логика переиспользована из user_groups_portal. Смоук-тесты рендера
и сохранения.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-21 15:33:25 +03:00
lokses e885e2924b core: команда авто-очистки (cleanup)
manage.py cleanup [--days N] [--dry-run] — удаляет устаревшие журналы
синхронизации (AD/Carbonio/Nextcloud/Mattermost), просроченные инвайты
паролей и истёкшие сессии. Бизнес-данные не трогает. Срок хранения —
settings.CLEANUP_LOG_RETENTION_DAYS (default 90, env-override). Запуск по cron.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-16 16:44:25 +03:00
lokses 598d26c52c Show employee login only to self and portal admins.
Managers and HR keep contact PII but no longer see usernames.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:25:02 +03:00
lokses bf5310e489 Hide peer logins on profiles and restrict view_all to published reports.
Login stays visible only to self/manager/HR; draft report docs stay department-head only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 15:20:49 +03:00
lokses 3ce3536e37 core: миграция extra_config для конфига OnlyOffice-коннектора
Догенерённая миграция под правку поля ConnectorConfig.extra_config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-10 13:19:48 +03:00
lokses 8db8f59d2f core: индивидуальные гранты отчётов в группах пользователей
Выдача/отзыв права на отчёты по всем отделам конкретному сотруднику
из портала управления группами.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-10 13:17:41 +03:00
lokses f41fefbaa7 nextcloud/onlyoffice: тип коннектора и UI редактора
- ConnectorConfig(onlyoffice) + миграция, подсказка по extra_config в админке.
- /documents/onlyoffice/ в whitelist 2FA — Document Server забирает файл
  без сессии портала (доступ по подписанному file-token + JWT DS).
- Страница редактора и кнопки «открыть в OnlyOffice» в браузере документов.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-10 13:17:41 +03:00
lokses ae54d93442 core: секции портала, контроль доступа и вью страниц
Section-based portal access, matrix прав по группам, аккаунтинг-портал,
управление группами пользователей, справочники, дашборд и общий каркас
навигации/стилей.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-09 18:03:20 +03:00
lokses 719d0b737b infra: надёжное обнаружение тестов, Redis-кэш и хардненинг прода
- AcoreDiscoverRunner собирает tests/tests_* всех локальных приложений
  (manage.py test находил 38 тестов из ~466 — теперь все).
- CACHES на Redis (отдельная DB от Celery) + обязательный requirepass
  в production, SECURE_HSTS_PRELOAD.
- Фикс stored-XSS в админке: format_html вместо mark_safe + f-string.
- Утилиты безопасности/тестов, шифрование полей.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-09 18:03:11 +03:00
lokses 70e5a77b04 Harden portal access and hiring, add RRO portal CRUD.
Remove the is_staff permission bridge, tighten intern credential handling with one-time PDFs and random seed passwords, and let staff manage cash registers from the portal.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 08:54:41 +03:00
lokses 56e2b1c8fe Add configurable pharmacy card tab visibility matrix.
Let admins set per-section access levels so operational data on pharmacy detail is no longer all-or-nothing for every logged-in user.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 20:43:33 +03:00
lokses ae5c1f1848 Add RRO, portal section perms, dislocation presets, and hiring intern flow.
Ship cash-register registry, section-based portal access, configurable dislocation columns, and trial-hire intern accounts with credentials PDF.
2026-08-09 14:58:17 +03:00
lokses 85bd89f762 Чат: сортировка по активности, непрочитанные, кнопка «Написати»
- Порядок каналов/ЛС — по реальному времени последнего поста (тянем per-channel,
  т.к. last_post_at из списка каналов ненадёжен), архивные (delete_at>0) — вниз
- Непрочитанные: счётчик по websocket, бейдж на строке + жирное имя, префикс
  «(N)» в тайтле, браузерное уведомление; сброс при открытии канала
- Кнопка «Написати в чат» на карточке сотрудника → /chat/?dm=<mm_id>,
  чат открывает/создаёт ЛС с этим человеком (идемпотентный /channels/direct)
- Тесты кнопки чата в EmployeeDetailTests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 16:08:53 +03:00
lokses 04b1625fde Безопасность: закрытие 5 открытых находок ревью 25.07
- 2FA: убраны /api/ и /media/ из ALLOWED_PREFIXES — staff-сессия без TOTP
  больше не дотягивается до API/медиа (устройства в /api/ идут без staff-сессии)
- Nextcloud «Обмен»: writable только для staff (не для любого logged-in)
- Nextcloud путь отдела/адрес аптеки: safe_component() санитайзит сегмент
  (сепараторы/управляющие/ведущие точки) в провижининге и в браузере
- Mattermost: shared secret кнопки «Виконано» перенесён из query string в
  context (тело POST) — без утечки в логи/Referer
- Login: throttle на кэше (5 попыток / 5 мин, 429); logout только POST (CSRF),
  logout-ссылки в шаблонах → POST-формы

Тесты обновлены под enforcement 2FA (login_2fa helper) и новые правила.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 15:38:44 +03:00
lokses ed7dcaae3b Nextcloud connector: страница «Документы» подключена к хранилищу
Заменяет статичный макет 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>
2026-07-28 15:02:30 +03:00
lokses 19bc2874aa Nextcloud connector: скелет провижининга Group Folders (Фаза 2)
- ConnectorConfig: тип 'nextcloud' (host/username/token, шифруется)
- NextcloudService: OCS-клиент Group Folders (create/ACL/quota, идемпотентный ensure_folder)
- NextcloudSyncService: отделы → 03_Отделы/* ↔ nc-dept-<код>; аптеки → 02_Аптеки/* ↔ nc-svc
- Сигналы Directory/Pharmacy с гейтом на включённый коннектор (по умолч. no-op)
- Celery-задачи + команда nextcloud_sync (dry-run по умолчанию, --apply)
- NextcloudSyncLog + admin; тесты (пути, гейт, идемпотентность ensure_folder)

Членство юзеров идёт через AD/LDAP, коннектор ведёт только папки+ACL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 11:09:49 +03:00
lokses 4e803c53e0 2FA: обязательная двухфакторная аутентификация (TOTP) для staff
- Модель Employee: totp_secret (шифруется), totp_enabled, totp_backup_codes
- Сервис twofa: генерация секрета/QR, проверка TOTP, резервные коды (sha256)
- TwoFactorMiddleware: enforcement для is_staff на портале и /admin/
- Страницы setup/verify/backup-codes; сброс 2fa_verified при каждом входе
- Админка: колонка статуса 2FA, фильтр, действие «Сбросить 2FA»
- Тесты: enforcement, setup, verify, резервные коды, disable

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 10:41:11 +03:00
lokses aa5a1bd421 i18n: перевод страницы timetrack (ru/uk/en)
Учёт рабочего времени: заголовок, навигация по месяцам, фильтры,
столбцы таблицы, пустое состояние — {% trans %}; метрики (из вью)
переведены через gettext. uk/en.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 10:06:22 +03:00
lokses 38c8e35a51 Security hardening: обязательный ключ шифрования, fail-closed токены, права API
- FIELD_ENCRYPTION_KEY: production требует явный ключ (ImproperlyConfigured
  при пустом), local — fallback на SECRET_KEY с предупреждением (crypto.py)
- MATTERMOST_INTERACTIVE_TOKEN: fail-closed токен для интерактивных кнопок
  Mattermost (bot_service task-done URL + проверка в mattermost views)
- Ужесточение прав API (employees/visit_manager) + тесты
  (employees, mattermost_connector, visit_manager)
- .env.example с описанием переменных; правки шаблонов (index/dislocation/pharmacies)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 12:23:28 +03:00
lokses fcdd5cb662 Админка: кнопка применения для дропдаун-фильтров справочников
Дропдаун-фильтры unfold рендерятся как форма и не применяются сами по
выбору — добавлен list_filter_submit=True (кнопка «Застосувати»), иначе
фильтр «не отрабатывал».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 11:21:15 +03:00
lokses a8faa206f6 Админка: горизонтальные фильтры в справочниках
Фильтры справочников (Directory, Системи доступу) вынесены из боковой
панели наверх в тулбар (unfold list_filter_sheet=False), кастомные фильтры
переведены на unfold DropdownFilter — выпадающие списки вместо списка ссылок.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:25:11 +03:00
lokses 242f0c95e0 Админка: отдельный раздел «Системи доступу» для баз/систем доступа
Системы доступа (1С, почта, CRM…) — записи справочника Directory
(access_system), которые выбираются в заявке на найм. Раньше их можно было
редактировать только внутри общего «Довідники» с фильтром — неочевидно.

- AccessSystem: proxy над Directory (фильтр по access_system), свой раздел
  админки со списком/добавлением; directory_type проставляется автоматически
- SILENCED_SYSTEM_CHECKS=['models.E016'] — гасит ложноположительный E016
  (proxy наследует treenode-индекс по _path; на реальной таблице всё корректно)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 01:12:07 +03:00
lokses a17e982d8c HR: «Посада» у формі найму залежить від типу локації
Активовано закладений механізм Directory.location_types (використовується в
Employee.clean(), але справочник був порожній):

- Міграція core 0005: сид довідника «Тип локации» (office/pharmacy/warehouse) —
  тепер посадам можна призначати типи локацій в адмінці (M2M location_types)
- _hr_portal_context віддає карту hr_post_location_types {post_id: [коди]}
- Форма найму: селект «Посада» фільтрується за обраним типом локації
  (hrHiringFilterPosts). Порожній список типів у посади = доступна скрізь
  (та сама семантика, що в clean()); невідповідну обрану посаду скидає

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 18:20:31 +03:00
lokses 53c852160c Страница учёта рабочего времени на реальных данных
Было: статичный макет timetrack.html (хардкод «10 співробітників»,
пустой tbody, JS не наполнял). Стало — реальные данные из WorkShift:

- timetrack_view агрегирует смены за выбранный месяц по сотрудникам:
  часы (Sum duration), дни (distinct date), незакрытые смены (без ухода),
  среднее/день; сводные метрики; счётчики по типам локаций
- Фильтр по типу локации (всі/офіс/аптеки) и помесячная навигация —
  через HTMX, с сохранением параметров в URL
- Шаблон перестроен в стиле портала (метрики, таблица, пагинация);
  строки ведут на детальную сотрудника; пустое состояние
- Невалидный месяц откатывается на текущий

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:04:44 +03:00
lokses b788bc2a7c Шифрование секретов ConnectorConfig (password/token) в БД
- EncryptedCharField (core/models/fields.py): прозрачное Fernet-шифрование
  на границе с БД, читатели и админка не меняются
- ConnectorConfig.password/token переведены на EncryptedCharField,
  колонки расширены под шифртекст
- Миграция 0004: расширение колонок -> шифрование существующих значений -> смена типа
- FIELD_ENCRYPTION_KEY в settings (default = SECRET_KEY); на проде задавать отдельно ДО migrate

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 15:31:37 +03:00
lokses 5e4528b23f Портал: страницы на реальных данных, детальные страницы, утилиты
- core/views: dashboard/databases/it-support/structure на живых данных;
  детальная сотрудника (/employees/<pk>/) с PII-гейтингом (staff/сам/
  руководитель), детальная аптеки, дислокация, профиль, показания счётчиков
- core/utils: crypto (Fernet-обёртка), pagination; партиалы пагинации и
  AD-вкладок
- шаблоны страниц обновлены под реальные контексты
- тесты (21): смоук всех страниц, PII-доступ сотрудника, дерево справочников

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 17:33:48 +03:00
lokses 81dee5cba2 Интеграции AD/Mattermost: OU-управление, импорт, шифрование токенов
- ad_connector: страницы управления OU и импорта из AD, поле ad_ou_dn
  в Directory, ADSyncLog; расширение sync-сервиса и клиента
- mattermost_connector: personal access token шифруется (Fernet,
  token_service), бот-сервис, команды создания бота и синхронизации;
  публикация постов в каналы. Тесты (19)
- core: ConnectorConfig, Directory (ad_ou_dn), обновления админки

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 17:32:26 +03:00
lokses 78475b58e9 Инфраструктура: Celery, общие утилиты, виджеты, шелл портала
- acore: Celery-приложение (брокер из env, eager без брокера), настройки
  CELERY_*, регистрация всех новых приложений в INSTALLED_APPS, маршруты
- core/utils: render_page (HTMX-фрагмент/полный layout), is_owner/
  is_owner_or_staff; templatetags common_tags (initials, clean_excerpt,
  is_it_staff); UpdateLastSeenMiddleware
- static: people-picker (дерево отделов с аватарками), searchable-select
  (одиночный выбор с поиском), directory-quick-add, it-manager, pagination;
  тема Tailwind v4 пересобрана, лого
- templates: новый шелл index.html (мобильный сайдбар, темы, фон,
  user-dropdown) и login с брендингом

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 17:31:01 +03:00
lokses c3f56f8a3e Portal redesign from template, real-data pages, test suite, Celery config
- templates: new shell from ACORE-template (mobile sidebar + bottom nav,
  themes, wallpaper, user dropdown), Django-ized nav with push-url;
  login rebranding; ACORE-template/ gitignored
- new pages wired to real data: databases (Directory types/counts),
  it-support (Ticket create form + my tickets), dashboard (live counters),
  structure (departments with head heuristic + pharmacy staffing status);
  static mockups for news/tasks/email/chat/purchases/hr-portal/help
- tests: 57 tests — ad_connector (ldap3 MOCK_SYNC client, sync scenarios,
  signals, mapping page), mattermost_connector (sync on mocks, bare-except
  regression), core (pages smoke, tickets, directories, tree rebuild)
- celery: add missing acore/celery.py app + CELERY_* settings (broker from
  env, eager mode without broker locally); wrap signal .delay calls so an
  unreachable broker no longer breaks employee saves

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 22:41:46 +03:00
lokses bfd67241c4 AD office-only scope, mapping page, auto-rebuild of directory tree
- ad_connector: restrict provisioning to office employees
  (user_location_type='office') in sync service, signals and command;
  disable AD account on transfer out of office, re-enable on return
- ad_connector: /ad-mapping/ page (staff only) — match office employees
  to AD accounts with suggestions by email/login/full name, link/unlink/
  create actions, list of unmatched domain accounts; sidebar nav item
- core: auto-rebuild treenode Directory tree (_path/_depth) after
  import-export imports and post_migrate; "rebuild tree" button in
  DirectoryAdmin and rebuild_directory_tree management command

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:48:38 +03:00
lokses faa06b9f82 Security hardening: fix open redirect, API auth, MIME validation, PII exposure
- core/views.py: fix open redirect in login — validate next_url with
  url_has_allowed_host_and_scheme before redirecting
- visit_manager/api/views.py: add explicit permission_classes/
  authentication_classes on all 3 API views; add MIME magic-byte
  validation + Pillow verify for photo uploads; validate employee_id/
  location_id/date query params; restrict photo access to is_staff,
  own record, or direct manager
- employees/serializers.py: split into EmployeeSerializer (public
  fields only) and EmployeeDetailSerializer (PII fields, for HR/admin)
- mattermost_service.py: sanitize sensitive fields (password, token)
  before logging; log only error message not full response body
- settings/base.py: add SESSION/CSRF cookie HttpOnly + SameSite flags;
  set file upload size limits (15MB); remove BasicAuthentication from
  DRF (sends credentials in plaintext)
2026-05-31 18:05:54 +03:00