Иван Иванов -> i.ivanov (транслит pytils, нижний регистр, коллизия +счётчик).
Раньше slugify('Фамилия.Имя') терял точку и давал ivanovivan. Единый формат
в найме (_generate_username) и в импорте (transliterate_username).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Кнопка «Матрица доступа» на списке групп (unfold actions_list) открывает
сетку: строки — разделы портала, колонки — все группы, галочки просмотра.
Сохранение через apply_full_access_matrix (CUD не трогает — они на карточке
группы). Логика переиспользована из user_groups_portal. Смоук-тесты рендера
и сохранения.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Две сущности (auth.Group + PermissionGroup-профиль) слиты в одну страницу
админки Group: имя, разделы портала (curated), прочие права, описание,
активна, ссылка на матрицу доступа. Отдельный пункт «Группы разрешений»
убран из меню; модель PermissionGroup остаётся профилем под капотом.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hx-post вне формы (кнопка «Синхронизировать чат») слал POST без CSRF —
Forbidden (CSRF token missing). Добавил hx-headers с X-CSRFToken на <body>:
токен уходит со всеми htmx-запросами, работает и при CSRF_COOKIE_HTTPONLY.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Если у бота задан только access-token (без id/username/имени), при сохранении
в админке дёргаем GET users/me этим токеном и заполняем user_id, username,
display_name автоматически.
- MattermostService.identity_for_token(token) — кто владелец токена;
- MattermostBotAdmin.save_model подставляет пустые поля, сообщает результат.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Бот больше не привязан к единственной role (unique). Вместо неё три флага-
галочки: can_provisioning / can_channels / can_tasks — можно совмещать.
get_active(role) ищет активного бота с соответствующей галочкой.
- модель: убран role, добавлены 3 boolean, get_active/caps по флагам;
- миграция 0006: перенос старой role в галочки, затем удаление role;
- админка: чекбоксы «Возможности бота»;
- команда create_mattermost_bot: --role включает нужную галочку (username-based upsert).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
- модель MattermostSyncLog (employee/action/status/message) + read-only админка;
- запись при добавлении в команды/каналы (успех и ошибка) в sync_service;
- пункт «Журнал Mattermost» в меню рядом с прочими журналами.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Навигация покрывает все админки (55 пунктов в 11 группах): Сотрудники,
Найм, Структура компании, Учёт посещений, IT-отдел, Эксплуатация (РРО/
счётчики/энергоактивы), Отчёты, Лента и задачи, База знаний, Mattermost
(вкл. Боты), Интеграции и настройки. Все ссылки проверены на reverse.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Добавлен фильтр по user_location_type (Аптека/Склад/Офис) в TeamSyncSettings
и ChannelSyncSettings — наряду с фильтром по отделам. При включении обоих
фильтров условия объединяются по AND.
- поля filter_by_location_type + location_types (ArrayField, чекбоксы в админке);
- логика add_user_to_teams/channels учитывает тип локации;
- django.contrib.postgres в INSTALLED_APPS (для ArrayField).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Form Word draft for OnlyOffice, publish the file to unlock the month; roster is head-first then by name with Employee responsibility zones.
Co-authored-by: Cursor <cursoragent@cursor.com>
Извлекаем UID регуляркой `UID (\d+)` вместо хрупкого split — прежний код
давал нечисловой/пустой uid (`456 FLAGS (\Seen`), из-за чего открытие письма
падало (UID FETCH с битым аргументом). Записи без UID пропускаем.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- fetch_message валидирует uid (только цифры) → иначе «Лист не знайдено»
вместо malformed UID FETCH (сервер отвечал BAD zero-length content).
- _with_imap ловит imaplib.IMAP4.error/OSError → страница /email/ отдаёт
connection_error, а не 500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
В свежей tzdata (Debian 13 / Python 3.13) старое имя Europe/Kiev удалено,
Django 6 отвергает его (ValueError: Incorrect timezone setting). Переименовано
во всех местах, включая дефолты Mattermost-таймзоны.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ReportDocument (+ миграция 0005): файлы отдела в Nextcloud (06_Отчёты).
- blank_office.py: генерация пустых Word/Excel для новых документов.
- documents.py: доступ/путь/создание, права view/edit по отделу.
- редактор OnlyOffice учится открывать report_doc (view/edit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- pyotp, qrcode — были не указаны, но нужны для 2FA (twofa.py); на чистом
проде без них 2FA бы не поднялась.
- defusedxml, fonttools, pyasn1, typing_extensions — транзитивные (fpdf2/ldap3).
- gunicorn сохранён.
Список сверен с венвом проекта; системный мусор Fedora (pip freeze не того
интерпретатора) сюда не попадает.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Полная первичная установка на боевой сервер (LXC за Traefik, gunicorn,
nginx, PostgreSQL, Redis c requirepass, Celery worker+beat), настройка
интеграций (Mattermost/Nextcloud/OnlyOffice/почта/AD/PNMS-PVMS-MSorter),
бэкапы, обновление и типичные грабли. Дополняет перенос-на-прод.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Выдача/отзыв права на отчёты по всем отделам конкретному сотруднику
из портала управления группами.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
- verified_ds_payload: HS256-проверка входящего JWT; status/url берём только
из верифицированного payload (было — из сырого тела).
- is_allowed_ds_download_url + follow_redirects=False: сохранённый файл
качаем только с хоста Document Server (SSRF-защита).
- document_key по size/modified (WebDAV stat) — DS больше не отдаёт
устаревшую версию из кэша.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Раздел «Справка» (категории/статьи/предложка), правки ad_connector
и обновление тестов feed под обязательную 2FA.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Клиенты и билдеры payload'ов, сервисы и Celery-задачи push identity/данных
во внешние порталы, HTTPS-guard в проде.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Конфиг счётчиков и день/ночь-тарифы, учёт энергосистем (генераторы,
инверторы), доступ к разделу РРО/ПРРО.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Отдельное право на редактирование карточки аптеки, формы, пресеты колонок
дислокации и правки видимости карточки.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Модель/сервисы HR-заявок с заменами, приглашения на установку пароля
(инвайты), обновлённая страница профиля сотрудника и правки 2FA.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Section-based portal access, matrix прав по группам, аккаунтинг-портал,
управление группами пользователей, справочники, дашборд и общий каркас
навигации/стилей.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
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>
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>