163 Commits

Author SHA1 Message Date
4a139180f7 feat: Auto-unsubscribe push on logout, force resubscribe on login
- Добавлена автоматическая отписка от Web Push при выходе
- При входе принудительно переподписываем пользователя
- Очищаем старую подписку из localStorage перед новой
- Это исправляет AbortError из-за старых подписок с другими VAPID ключами
2026-01-06 08:11:24 +03:00
788a245cc9 feat: implement Web Push notifications for offline browser notifications
- 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
2026-01-05 14:10:42 +03:00
8c546e59fb - 2026-01-05 10:59:07 +03:00
d5b5437c60 fix: password reset emails now use HTML template for Gmail compatibility 2026-01-05 10:47:56 +03:00
026bc46816 feat(department-roles): complete LDAP architecture redesign with RoleAssignment model
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
2025-12-30 10:35:34 +03:00
36f756988b fix(requests): улучшены названия фильтров дат и исправлена логика фильтрации 2025-12-29 15:42:00 +03:00
8ebe241174 feat(requests): добавлены фильтры по сотруднику и периоду дат 2025-12-29 15:32:27 +03:00
0b959f33e0 refactor(requests): заменён фильтр 'Область' на nav-pills как в документах 2025-12-29 15:25:18 +03:00
f6a1315d76 feat(requests): текст темы в списке заявлений теперь ссылка на страницу деталей 2025-12-29 14:47:13 +03:00
0890d02efc refactor: переделать страницу деталей заявления с нуля со стилями из списка
- Полная переделка шаблона 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)
- Кнопки одобрения/отклонения с правильными иконками
2025-12-29 14:27:47 +03:00
dd219d4752 Исправлена view request_detail
- Добавлены comments в контекст
- Добавлен prefetch recipients и cc_users в DETAIL_REQUEST_QS
- Теперь все данные передаются правильно
2025-12-29 12:31:37 +03:00
be21b9ca4a Полностью переработана страница деталей заявления
Исправлено:
- Добавлена правильная структура card-header с аватаром 48x48px
- Добавлены все необходимые детали: получатели, копия, согласующий
- Исправлены стили для badge и card-body
- Добавлена корректная форма комментария с emoji picker и auto-expand
- Подключены правильные JavaScript компоненты
- Исправлен формат дат (d.m.Y H:i)
- Добавлена передача can_process в контексте view

Добавлено:
- Иконки для каждого раздела (получатели, копия, согласующий)
- Ссылки на карточки сотрудников
- Правильные Badge с subtle цветами
- Форма комментария с message-field компонентом
2025-12-29 12:25:42 +03:00
1349ebce35 fix(requests): временно отключена кнопка 'Отозвать'
URL request_cancel не подключен в urls_front.py
Закомментирована кнопка до добавления функционала
2025-12-29 12:00:52 +03:00
532098499b fix(requests): исправлен namespace для URL request_cancel
Изменено: requests:request_cancel → requests_app:request_cancel
Исправлена ошибка NoReverseMatch при открытии страницы заявления
2025-12-29 11:59:03 +03:00
087cff7901 fix: исключен approver из получателей уведомлений о решении
- Approver (тот кто принял решение) не получает уведомление о своем действии
- Исключены employee.id и approver_id из recipients при approve/reject
- Упрощен signal create_request_notifications (убран лишний запрос в БД)
- Теперь передается актуальный request_obj с установленным approver_id
2025-12-29 11:02:39 +03:00
3941b5c963 fix: уточнен селектор формы решения в request_process.html 2025-12-29 10:15:45 +03:00
849545b11c feat: AJAX обработка формы решения на странице заявления без перезагрузки 2025-12-29 10:01:32 +03:00
eb70384928 � Мобильная оптимизация и новый тип заявления 'Отгул'
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
- Добавлен во все формы создания/редактирования
- Добавлен в фильтры списка
2025-12-29 10:00:32 +03:00
4d03d027f4 fix: добавлена JavaScript обработка форм на странице заявления
- Форма добавления комментария теперь обрабатывается через AJAX
- Форма удаления комментария с подтверждением
- Форма изменения статуса с подтверждением
- После успешных операций страница перезагружается
- Отображение состояния загрузки (spinner) на кнопках
- Обработка ошибок с alert уведомлениями
2025-12-29 09:28:47 +03:00
434de5c344 fix: приведен шаблон request_detail к стилям проекта
- Использованы компоненты card-list и message-field
- Убраны inline стили, используются классы проекта
- Улучшена структура и читаемость
- Добавлен правильный layout с container-fluid
- Комментарии теперь используют card-list-item класс
- Форма комментариев использует message-field компонент
2025-12-29 09:24:30 +03:00
ee4184953b fix: заменены все request_obj.pk на request_obj.id
- API возвращает 'id', а не 'pk'
- Исправлены все 3 URL: request_cancel, request_comment_delete, request_comment_add
2025-12-29 09:20:53 +03:00
7ff425b707 fix: исправлен namespace в URL шаблона request_detail
- Заменено 'requests_app:' на 'requests:' во всех URL
- В urls_front.py app_name = 'requests', не 'requests_app'
- Исправлена ошибка NoReverseMatch
2025-12-29 09:19:14 +03:00
6621d933e1 fix: исправлен доступ к author в комментариях
- Заменено c.author_name на c.author.full_name|default:c.author.display_name
- Заменено c.author_id на c.author.id (вложенный объект)
- API возвращает вложенный объект author, а не плоские поля
2025-12-29 09:17:50 +03:00
7bd93d99c7 fix: исправлена ошибка доступа к полю username в шаблоне
- Заменено request_obj.employee.username на employee.display_name
- API возвращает full_name и display_name, но не username
- Исправлена ошибка VariableDoesNotExist при рендеринге шаблона
2025-12-29 09:16:48 +03:00
240f734c92 feat: requests detail view - stage 5: функциональность изменения статуса
- Добавлен обработчик для смены статуса заявления в JavaScript
- Интегрирована форма смены статуса в шаблон request_detail.html
- Форма видна только администраторам (can_process=True)
- Поддерживаются переходы: pending->approved/rejected, *->cancelled
- Добавлена валидация и подтверждение перед изменением статуса
- Используются API endpoints: /api/v1/requests/{id}/approve/, reject/, cancel/
- Автоматическое обновление содержимого модали после смены статуса
- Отображение статуса обновления (loading, success, error) в UI
2025-12-26 16:27:09 +03:00
48a96f495e feat: requests detail view - stage 4: функциональность комментариев
- Добавлена функция удаления комментариев в views_front.py
- Добавлена обработка удаления в URL routing
- Расширен JavaScript модуль для работы с добавлением/удалением комментариев
- Добавлена обработка формы добавления комментариев с JSON
- Улучшена обработка ошибок при добавлении комментария
- Добавлена инициализация emoji picker в модали
- Обновлен счетчик комментариев при добавлении/удалении
- Обновлены шаблоны для работы с данными из API
- Добавлена поддержка перезагрузки содержимого модали после каждого действия
2025-12-26 16:25:18 +03:00
003860f892 feat: requests detail view - stage 3: frontend разработка
Этап 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: Функциональность комментариев
2025-12-26 16:03:25 +03:00
f19862ec6b feat: requests detail view - stage 2: backend разработка
Этап 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 разработка
2025-12-26 15:59:16 +03:00
28feac732e feat(avatar): change crop ratio to 3:4 portrait and improve overlay sync
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
2025-12-18 10:15:00 +03:00
53f1eb8096 feat(avatar): implement avatar cropper with FaceID requirements
Implemented avatar cropping component for FaceID system integration.

Features:
- Image cropper using Cropper.js library
- FaceID requirements validation (70-80% face coverage, 600x600px min)
- Square crop area (1:1 aspect ratio)
- Output: 800x800px JPEG at 92% quality
- Real-time size indicator
- Integrated in 2 places: registration + profile editor

Components:
- avatarCropperHandler.js: Main cropper module with AvatarCropper class
- Modal UI with Bootstrap 5
- FaceID instructions and guidelines
- File validation (size, format, dimensions)

Integration:
- auth/register.html: Registration form with cropper
- employees/employee_form_personal.html: Profile editor with cropper
- employees/employee_form_scripts.html: Scripts updated

Technical details:
- CDN: Cropper.js v1.6.1
- Min input size: 600x600px
- Max file size: 10 MB
- Formats: JPG, PNG, GIF
- Output format: JPEG (optimized for face recognition)

Validation:
✓ File format validation
✓ File size validation (10 MB max)
✓ Image dimensions validation (600x600px min)
✓ Real-time crop size indicator
✓ Error handling with user-friendly messages

UI/UX:
- Modal window with instructions
- Live preview of cropped image
- Size indicator (green/red based on requirements)
- Clear FaceID guidelines for users
- Responsive layout
2025-12-18 09:56:50 +03:00
9d47fc0c5c feat: add employee dismissal UI and filter inactive employees
- 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
2025-12-17 09:14:34 +03:00
5ad51550c0 fix: add permission checks for create buttons in employee module templates
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
2025-12-08 14:24:40 +03:00
7388f596a6 fix: correct permission check in feed_list.html template
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.
2025-12-08 14:14:58 +03:00
a1bd72979d feat: show create document button only for authorized users
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.
2025-12-08 13:09:55 +03:00
f05f00b8f8 feat: show create post button for users with publish permissions
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.
2025-12-08 13:05:12 +03:00
1f811fde2a feat: add avatar zoom modal on click
- 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
2025-12-08 11:07:45 +03:00
d631a436d1 refactor: remove total messages counter from chat list
- 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
2025-12-08 08:36:56 +03:00
54a3e46b3d fix: prevent calendar context menu from going off-screen
- 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
2025-12-05 17:01:33 +03:00
3e5b6917f0 feat: move calendar button from FAB to navbar
- 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
2025-12-05 16:59:23 +03:00
592a799cc7 test: add my_requests.html and IP restriction test scripts 2025-12-05 16:18:45 +03:00
c364d0635a fix(requests): сохраняем шапку таблицы при ajax загрузке, исправлен порядок, счетчик комментариев, preventDefault для Enter
- Добавлен отдельный контейнер для данных заявлений
- JS работает только с #reqListContent, шапка всегда видна
- Исправлен порядок заявлений (order_by)
- comments_count через annotate
- Исправлен обработчик формы комментария (preventDefault)
- Удаление начального спиннера после загрузки
2025-12-05 15:59:21 +03:00
19757d2f98 feat: полная AJAX-загрузка списка заявлений с infinite scroll
- Обновлен requestListHandler.js: рендеринг в табличном формате
- Сохранена структура таблицы req-table-header + req-row
- Шаблон: удален SSR-цикл, сохранена шапка таблицы
- Добавлены данные пользователя в dataset (userId, canProcess)
- Включен useAjaxList режим в initRequestListPage
- Удалены старые CSS для req-item (не используются)
- Структура совместима с существующими стилями request-list.css
2025-12-05 15:00:36 +03:00
5d1fd340fb refactor: использование attachment_url из API + AJAX компонент для заявлений
- Шаблоны используют obj.attachment_url напрямую из API
- Удален templatetag absolute_url (больше не нужен)
- Упрощена проверка наличия вложения
- Создан requestListHandler.js для AJAX загрузки с infinite scroll
- Обновлен requestList.js для поддержки AJAX режима
- Подход аналогичен приложению документов
2025-12-05 14:53:52 +03:00
32f8800165 refactor: удалены неиспользуемые файлы заявлений
- Удалены шаблоны: my_requests.html, all_requests.html (старые)
- Удален JS компонент: requestListHandler.js (неиспользуемый)
- Обновлены views: my_requests() и all_requests() теперь редиректят на requests:request_list
- Обновлены все редиректы с requests_app:my_requests на requests:request_list
- Основная страница заявлений: /requests/ (request_list_full.html)
2025-12-05 14:33:15 +03:00
897fdb587a fix: использование абсолютных URL для вложений в заявлениях
- Добавлен templatetag absolute_url для преобразования относительных путей
- Обновлены все шаблоны заявлений: request_list_full, request_detail, request_process
- Теперь все ссылки на вложения используют {% absolute_url %} для полных URL
- Добавлен use_url=True для attachment_url в сериализаторе API
- Исправлена проблема с локальными URL вместо доменных
2025-12-05 14:25:55 +03:00
462ebdb41f fix: добавлено поле attachment_url в RequestReadSerializer
- Добавлен attachment_url для полного URL к прикрепленному файлу
- Исправлен шаблон my_requests.html (удалены лишние теги)
- Теперь API заявлений работает аналогично API документов
2025-12-05 13:42:59 +03:00
4822eee65e feat: добавлена бесконечная прокрутка для заявлений
- Создан компонент requestListHandler.js для AJAX загрузки
- Упрощен view my_requests - данные загружаются через API
- Обновлен шаблон my_requests.html на AJAX загрузку
- Добавлен поиск по типу заявления и комментарию
- Intersection Observer для автоматической подгрузки
- Фильтрация по статусу заявления
- Удалена серверная пагинация
- Добавлены спиннеры загрузки
2025-12-05 13:31:55 +03:00
bc51d7c326 feat: добавлен поиск документов по названию и описанию
- Убран параметр no_search из шапки страницы
- Добавлено поле поиска с placeholder
- Реализована фильтрация по названию и описанию документа
- Поиск работает на клиенте с debounce 300ms
- Фильтрация применяется ко всем загруженным документам
- Настройка обработчика поиска после первой загрузки
2025-12-05 13:19:04 +03:00
e1acebdb34 fix: добавлена инициализация AJAX загрузки документов
- Добавлен импорт initDocumentListHandler в documentList.js
- Инициализация documentListHandler с правильными параметрами
- Считывание scope и ack_status из URL параметров
- Добавление scope в API запрос
- Передача userId и canManage через data-атрибуты
- Автоматическое применение scope при инициализации
2025-12-05 13:13:43 +03:00
74dd738e12 refactor: переход на AJAX загрузку документов
- Упрощен DocumentView - не загружает документы с сервера
- Шаблон использует спиннер вместо серверного рендеринга
- Удалена старая пагинация из шаблона
- Все документы загружаются через documentListHandler.js
- Предотвращена двойная загрузка (сервер + клиент)
2025-12-05 13:07:57 +03:00