- Добавлена автоматическая отписка от Web Push при выходе
- При входе принудительно переподписываем пользователя
- Очищаем старую подписку из localStorage перед новой
- Это исправляет AbortError из-за старых подписок с другими VAPID ключами
- Add WebPushSubscription model for storing push subscriptions
- Generate VAPID keys for Web Push authentication
- Add API endpoints for push subscribe/unsubscribe
- Create Service Worker (sw.js) for handling push events
- Create JavaScript module for managing push subscriptions
- Integrate send_web_push_notification into NotificationService
- Add Service Worker registration to base.html
- Update requirements.txt with pywebpush package
BREAKING CHANGES:
- Removed OU=Roles from LDAP structure, role groups now created directly in department OU
- Role groups use ROLE_<Name> naming convention (similar to DEP_, POS_)
New features:
- RoleAssignment model: allows assigning roles to ANY employee, not just department members
- New API endpoints: /assign/, /revoke/, /assignments/ on DepartmentRoleViewSet
- Permission system updated: has_dept_perm() checks RoleAssignment first
- Employee profile shows external roles with 'внешняя роль' badge
- Employee list filter includes role-only employees with department_relation field
- Role assignment modal now searches all employees via AJAX
LDAP changes:
- _ensure_role_group(): creates ROLE_<Name> group in department OU
- assign_role(), revoke_role(): manage RoleAssignment + LDAP sync
- rename_role_group(), delete_role_group(): full lifecycle support
- Removed all references to OU=Roles
Migrations:
- 0035: Create RoleAssignment model
- 0036: Data migration from EmployeeDepartment.role
Tests:
- 7 new tests for role assignment (all passing)
Docs:
- 9 detailed reports on architecture, models, API, LDAP, tests
- Полная переделка шаблона request_detail.html с единообразными стилями
- Новая структура: основная карточка (8 колонок) + боковая панель комментариев (4 колонки)
- Единообразные иконки типов заявлений (calendar-check, capsule, umbrella-fill и т.д.)
- Единообразные бейджи статуса и типа как в списке
- Информационные блоки для автора, описания, получателей, одобрившего
- Форма комментариев с правильным стилем message-field--compact
- Emoji picker с поддержкой dropdown-menu поверх контента
- AJAX обработка отправки и удаления комментариев
- Новый CSS файл request-detail.css с адаптивностью
- Добавлена функция _add_type_display() в views.py для отображения типа
Улучшения:
- Единство дизайна со страницей списка заявлений
- Правильное позиционирование emoji picker (fixed positioning)
- Sticky боковая панель с комментариями
- Форма комментария как в ленте (message-field--compact)
- Кнопки одобрения/отклонения с правильными иконками
Исправлено:
- Добавлена правильная структура card-header с аватаром 48x48px
- Добавлены все необходимые детали: получатели, копия, согласующий
- Исправлены стили для badge и card-body
- Добавлена корректная форма комментария с emoji picker и auto-expand
- Подключены правильные JavaScript компоненты
- Исправлен формат дат (d.m.Y H:i)
- Добавлена передача can_process в контексте view
Добавлено:
- Иконки для каждого раздела (получатели, копия, согласующий)
- Ссылки на карточки сотрудников
- Правильные Badge с subtle цветами
- Форма комментария с message-field компонентом
- Approver (тот кто принял решение) не получает уведомление о своем действии
- Исключены employee.id и approver_id из recipients при approve/reject
- Упрощен signal create_request_notifications (убран лишний запрос в БД)
- Теперь передается актуальный request_obj с установленным approver_id
MOBILE FIXES:
- request-list.css: переделан мобильный layout с flexbox вместо grid
- page-header.css: оптимизирован padding/margin для мобильных экранов
- requestListHandler.js:
* Добавлен AbortController с таймаутом (10/15 сек для мобильных)
* Обработка offline/online событий сети
* Информативные сообщения об ошибках (отсутствие интернета, таймаут)
* Адаптивный Intersection Observer (rootMargin 200px для мобильных)
* Лучшая обработка network failures
UI/UX:
- Скрыт счётчик на экранах < 480px
- Контент теперь отображается на всех разрешениях
- Исчезновение спиннера при ошибке сети
- Визуальное различие между ошибками загрузки
NEW FEATURE:
- Добавлен новый тип заявления 'Отгул' (day_off)
- Обновлена миграция 0009_alter_request_type
- Добавлен во все формы создания/редактирования
- Добавлен в фильтры списка
- Форма добавления комментария теперь обрабатывается через AJAX
- Форма удаления комментария с подтверждением
- Форма изменения статуса с подтверждением
- После успешных операций страница перезагружается
- Отображение состояния загрузки (spinner) на кнопках
- Обработка ошибок с alert уведомлениями
- Использованы компоненты card-list и message-field
- Убраны inline стили, используются классы проекта
- Улучшена структура и читаемость
- Добавлен правильный layout с container-fluid
- Комментарии теперь используют card-list-item класс
- Форма комментариев использует message-field компонент
- Заменено c.author_name на c.author.full_name|default:c.author.display_name
- Заменено c.author_id на c.author.id (вложенный объект)
- API возвращает вложенный объект author, а не плоские поля
- Заменено request_obj.employee.username на employee.display_name
- API возвращает full_name и display_name, но не username
- Исправлена ошибка VariableDoesNotExist при рендеринге шаблона
- Добавлен обработчик для смены статуса заявления в JavaScript
- Интегрирована форма смены статуса в шаблон request_detail.html
- Форма видна только администраторам (can_process=True)
- Поддерживаются переходы: pending->approved/rejected, *->cancelled
- Добавлена валидация и подтверждение перед изменением статуса
- Используются API endpoints: /api/v1/requests/{id}/approve/, reject/, cancel/
- Автоматическое обновление содержимого модали после смены статуса
- Отображение статуса обновления (loading, success, error) в UI
- Добавлена функция удаления комментариев в views_front.py
- Добавлена обработка удаления в URL routing
- Расширен JavaScript модуль для работы с добавлением/удалением комментариев
- Добавлена обработка формы добавления комментариев с JSON
- Улучшена обработка ошибок при добавлении комментария
- Добавлена инициализация emoji picker в модали
- Обновлен счетчик комментариев при добавлении/удалении
- Обновлены шаблоны для работы с данными из API
- Добавлена поддержка перезагрузки содержимого модали после каждого действия
Этап 3 разработки включает:
✅ Создан JavaScript модуль requestDetail.js:
- Класс RequestDetailModal для управления модальным окном
- Функция open(requestId) для открытия заявления
- Функция loadData(requestId) для загрузки через AJAX
- Обработка ошибок (404, 403)
- Поддержка добавления комментариев в модали
- initRequestDetailModal() для инициализации на странице список
✅ Добавлено модальное окно в request_list_full.html:
- HTML структура модального окна requestDetailModal
- ID контейнера для содержимого: requestDetailContent
- Bootstrap 5 modal с размером modal-lg
- Scrollable модаль для больших содержимо
✅ Обновлена инициализация скриптов:
- Подключение модуля requestDetail.js
- Инициализация RequestDetailModal при загрузке страницы
- Сохранение экземпляра для использования на странице
✅ Интеграция с кликами:
- Подготовка к интеграции с существующей логикой списка
- Возможность открытия заявления из списка или по прямой ссылке
Готово для следующего этапа 4: Функциональность комментариев
Этап 2 разработки включает:
✅ Создан RequestDetailView класс в views_front.py:
- Наследуется от LoginRequiredMixin, TemplateView
- Загружает данные о заявлении через API (/api/v1/requests/{pk}/)
- Загружает комментарии к заявлению
- Проверяет права доступа (обрабатывает 404, 403)
- Форматирует даты для отображения
✅ Обновлены URLs (urls_front.py):
- Добавлен маршрут: path('<int:pk>/', RequestDetailView.as_view(), name='request_detail')
- Импортирован RequestDetailView
✅ Обновлен шаблон request_detail.html:
- Раскомментированы комментарии (были закрыты)
- Добавлена обработка ошибок (404, 403)
- Оформлено отображение заявления и комментариев
- Включен функционал добавления комментариев
� URLs в notification_signals.py уже правильные (проверено)
Готово для следующего этапа 3: Frontend разработка
Changed avatar cropper aspect ratio from 1:1 to 3:4 (portrait) for better FaceID recognition.
Improved human silhouette overlay synchronization with crop box during all interactions.
Key changes:
Aspect ratio:
- Changed from 1:1 (square) to 3:4 (portrait)
- Output size: 600x800px (instead of 800x800px)
- Better suited for full body positioning (head, shoulders, torso)
SVG overlay improvements:
- Updated viewBox from 400x400 to 300x400 (3:4 proportions)
- Redesigned human silhouette for portrait format
- Added torso outline up to waist level
- Additional guide line for shoulders
- Better proportions for face/head/shoulders alignment
Synchronization enhancements:
- Added cropstart, cropmove, cropend event handlers
- Overlay now follows crop box during all interactions:
✓ Moving the crop box
✓ Resizing the crop box
✓ Zooming the image
✓ Initial positioning
- Real-time position updates using getCropBoxData()
UI/UX updates:
- Updated instructions: 'Совместите тело с зелёным контуром'
- Face should occupy upper third of frame
- Portrait format 3:4 mentioned in requirements
- Changed label from 'Плечи' to 'Пояс' (waist)
- Templates updated with new size requirements (600x800px)
Technical details:
- minCropBoxHeight: 266px (200 * 4/3 for aspect ratio)
- preserveAspectRatio: none (for proper stretching)
- Event handlers ensure overlay follows crop box smoothly
- No performance impact from additional event listeners
Benefits:
✓ Better for FaceID (full body context)
✓ Standard portrait photo format
✓ More professional appearance
✓ Consistent with ID photo standards
✓ Improved overlay visibility and accuracy
- Added dismissal form on employee profile page with permissions
- Shows warning when dismissing (LDAP deactivation notice)
- Inactive employees filtered by default in employee list (active=true)
- Team wheel now shows only active employees
- Auto-submit filter form on status change
- Added redirect to set active=true by default on first visit
Changes:
1. employees_list.html - 'Create Profile' button now only visible to staff/superuser
API requires staff/superuser for POST /employees/ (explicit check in create method)
2. department_list.html - Simplified permission check for 'Create Department' button
Changed from: can_create_departments OR perms.employees.add_department OR is_staff
To: is_staff OR is_superuser OR perms.employees.add_department
API uses AdminOrActionOrModelPerms which checks employees.add_department
3. skill_list.html - 'Add Skill' button now requires authentication
API allows any authenticated user to create skills (IsAuthenticated only)
Before:
- Department creation check was redundant with can_create_departments variable
- Skill creation had no check
After:
- All create buttons properly check permissions matching API requirements
- Consistent with feed and documents modules permission patterns
Changed from non-existent permissions:
- perms.feed.publish_company_post
- perms.feed.publish_department_post
To actual Django model permission:
- perms.feed.add_post
User diagnosis confirmed:
- User has Position 'СММ специалист'
- Position linked to Group 'Дизайн СММ Реклама'
- Group has permissions: add_post, change_post, delete_post, view_post
- PositionRoleBackend correctly grants these permissions
The 'Create Post' button will now appear for users with feed.add_post permission through their position groups.
Previously: 'Create Document' button visible to everyone
Now: Button visible only for:
- Staff users (is_staff), OR
- Users with documents.add_document permission
This prevents regular users from seeing a button they can't use,
improving UX by showing only available actions.
Previously: Only staff users could see 'Create Post' button
Now: Button visible for:
- Staff users (is_staff), OR
- Users with feed.publish_company_post permission, OR
- Users with feed.publish_department_post permission
This allows department managers and content creators to publish
posts without needing full staff status.
- Added Bootstrap modal for enlarged avatar view
- Made avatar image clickable with cursor pointer
- Added modal trigger to both static and dynamically loaded avatars
- Modal displays full-size avatar centered with dark backdrop
- Close button positioned in top-right corner
- Removed badge showing total message count (chat.messages.count)
- Keep only unread messages counter for cleaner UI
- Users can still see unread count which is more important
- Added smart positioning logic to keep menu within viewport bounds
- Menu now adjusts horizontal position if it would overflow right edge
- Menu moves above cursor if it would overflow bottom edge
- Changed position from absolute to fixed for consistent behavior
- Added 10px safety margins from all edges
- Menu is temporarily hidden during position calculation for smooth appearance
- Removed floating action button (FAB) for calendar
- Added calendar icon in navbar next to notification bell
- Calendar button only visible on mobile devices (d-lg-none)
- Fixed issue where FAB could overlap message send button
- Commented out calendar-fab CSS in all relevant files
- Добавлен отдельный контейнер для данных заявлений
- JS работает только с #reqListContent, шапка всегда видна
- Исправлен порядок заявлений (order_by)
- comments_count через annotate
- Исправлен обработчик формы комментария (preventDefault)
- Удаление начального спиннера после загрузки
- Обновлен requestListHandler.js: рендеринг в табличном формате
- Сохранена структура таблицы req-table-header + req-row
- Шаблон: удален SSR-цикл, сохранена шапка таблицы
- Добавлены данные пользователя в dataset (userId, canProcess)
- Включен useAjaxList режим в initRequestListPage
- Удалены старые CSS для req-item (не используются)
- Структура совместима с существующими стилями request-list.css
- Шаблоны используют obj.attachment_url напрямую из API
- Удален templatetag absolute_url (больше не нужен)
- Упрощена проверка наличия вложения
- Создан requestListHandler.js для AJAX загрузки с infinite scroll
- Обновлен requestList.js для поддержки AJAX режима
- Подход аналогичен приложению документов
- Добавлен templatetag absolute_url для преобразования относительных путей
- Обновлены все шаблоны заявлений: request_list_full, request_detail, request_process
- Теперь все ссылки на вложения используют {% absolute_url %} для полных URL
- Добавлен use_url=True для attachment_url в сериализаторе API
- Исправлена проблема с локальными URL вместо доменных
- Добавлен attachment_url для полного URL к прикрепленному файлу
- Исправлен шаблон my_requests.html (удалены лишние теги)
- Теперь API заявлений работает аналогично API документов
- Создан компонент requestListHandler.js для AJAX загрузки
- Упрощен view my_requests - данные загружаются через API
- Обновлен шаблон my_requests.html на AJAX загрузку
- Добавлен поиск по типу заявления и комментарию
- Intersection Observer для автоматической подгрузки
- Фильтрация по статусу заявления
- Удалена серверная пагинация
- Добавлены спиннеры загрузки
- Убран параметр no_search из шапки страницы
- Добавлено поле поиска с placeholder
- Реализована фильтрация по названию и описанию документа
- Поиск работает на клиенте с debounce 300ms
- Фильтрация применяется ко всем загруженным документам
- Настройка обработчика поиска после первой загрузки
- Добавлен импорт initDocumentListHandler в documentList.js
- Инициализация documentListHandler с правильными параметрами
- Считывание scope и ack_status из URL параметров
- Добавление scope в API запрос
- Передача userId и canManage через data-атрибуты
- Автоматическое применение scope при инициализации
- Упрощен DocumentView - не загружает документы с сервера
- Шаблон использует спиннер вместо серверного рендеринга
- Удалена старая пагинация из шаблона
- Все документы загружаются через documentListHandler.js
- Предотвращена двойная загрузка (сервер + клиент)