23 Commits

Author SHA1 Message Date
f29bfc283d fix: исправлены импорты в messageEditing и chat/index 2026-01-13 09:18:25 +03:00
aba011731f feat: implement Telegram-style badges system
- Created comprehensive badges-telegram-style.css (240 lines) based on Telegram Web K
- Updated all badge markup in templates (navbar, sidebar, chat_list, chat_detail, chat_title)
- Replaced Bootstrap badge classes with .badge-telegram classes
- Implemented Telegram specifications: 20px height, 10px radius, 11px font, 600 weight
- Added smooth animations: pulse (on update), animate-in (on mount), animate-out (on unmount)
- Updated JavaScript: replaced .d-none with style.display for badge visibility
- Updated 5 JS files: bottom-navbar, notification-manager, chatBadgeHandler, chatBadgeManager, chatListRealtime
- Added pulse animation on badge value increase
- Improved shadows and transitions with cubic-bezier easing
- Added badges-telegram-style.css to base.html for global availability
- Created documentation: TELEGRAM_BADGES_GUIDE.md, TELEGRAM_BADGES_UPDATE.md

Technical details:
- Research: Analyzed 50+ files from Telegram Web K GitHub repository
- Perfect circles: border-radius: 10px (not 50%)
- Spring animation: cubic-bezier(0.175, 0.885, 0.32, 1.275)
- Auto-hide: :empty and [data-count='0'] selectors
- Responsive design + dark theme support
2026-01-12 17:37:41 +03:00
7838a55ef4 feat: Replace CDN with local vendor libraries + complete Web Push setup
- Замена всех CDN зависимостей на локальные файлы:
  * Bootstrap 5.3.3 (CSS + JS)
  * Bootstrap Icons 1.11.3 (CSS + шрифты woff/woff2)
  * FullCalendar 6.1.8 (JS + локали)
  * Cropper.js 1.6.1
  * emoji-picker-element 1.21.3

- Web Push Notifications:
  * VAPID ключи настроены в settings.py
  * Service Worker (sw.js) в корне backend/
  * API endpoints: /api/v1/notifications/push/
  * Auto-request permission при загрузке страницы
  * Simplified subscribe logic (Phase 1 refactor)
  * resetEverything() для восстановления после ошибок

- Документация:
  * backend/docs/guides/WEB_PUSH_QUICK_TEST.md
  * backend/docs/guides/FIX_NO_PUSH_SUBSCRIPTIONS.md
  * backend/docs/troubleshooting/WEB_PUSH_OFFLINE_ISSUE.md

- Обновлено 10 шаблонов для использования local vendor
- Устранены проблемы с CORS и integrity checks
- Все иконки Bootstrap Icons теперь отображаются корректно
2026-01-06 09:22:16 +03:00
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
26f4bbea02 fix: устранены дубликаты сообщений, архитектура загрузки через WebSocket, исправлен poll_update для Django Channels, улучшена инициализация голосований и защита от повторов 2025-12-01 14:19:58 +03:00
3422f18f4f fix(notifications): восстановлены типы уведомлений, тестовый скрипт и все рабочие изменения 2025-11-29 16:41:03 +03:00
dd56953e89 Исправлена разметка и стили страницы профиля
- Заменен лишний div.container на стандартный container для единообразия
- Заменен класс .card на .ios-card в секции активности для устранения конфликтов стилей
- Добавлен card-list.css в base.html для корректного отображения карточек новостей
- Добавлены CSS правила для правильного поведения .row и колонок в grid-layout
- Исправлена проблема с выходом календаря за границы страницы
- Убраны видимые скроллбары у modal-body и modal-content для чистого UI
2025-11-29 13:52:21 +03:00
c1a907cd60 feat(ui): restyle message composers 2025-11-28 11:56:47 +03:00
ddf22c47da fix: автоматическое обновление JWT токенов
- ApiClient теперь обрабатывает 401 и 403 ошибки для обновления токена
- Добавлен JWTRefreshMiddleware для проактивного обновления токенов за 5 минут до истечения
- Добавлена настройка JWT_REFRESH_THRESHOLD_MINUTES (по умолчанию 5)
- Исправлена проблема с периодическими 403 ошибками после истечения access token
2025-11-20 18:52:29 +03:00
d078b2f50b Merge master and ldap-writeback: added LDAP optional mode, refactored templates and JavaScript modules 2025-11-20 09:00:55 +03:00
9dd80c2b93 refactor(css): Phase 6 - Eliminate duplication and unify naming
- Created common.css (245 lines) with shared classes:
  * .btn-icon with variants (--primary, --danger, --success)
  * .badge-acked, .badge-status with state variants
  * .avatar with size variants (xs/sm/md/lg/xl)
  * .feed-author, .feed-sub (feed metadata)
  * .chip, .chip-remove
  * .text-truncate-2/3, .custom-scrollbar

- Deleted feed-header.css (duplicate of feed-cards.css)

- Cleaned 6 component files (~200 lines removed):
  * base-app.css: removed duplicate variables
  * document-list.css: removed .btn-icon, .badge-acked
  * employee-list.css: removed .feed-author, .feed-sub
  * department-list.css: removed .feed-header, .feed-author, .feed-sub
  * ios-components.css: removed .btn-icon, .chip
  * request-list.css: removed .badge-status

- Unified variables.css naming:
  * --navbar-height → --navbar-h
  * --sidebar-width → --sidebar-w
  * --rightbar-width → --rightbar-w
  * Added --radius-xs, --radius-2xl
  * Unified iOS component variables (--ios-grip-w/h)
  * Added complete shadow hierarchy (--shadow-xs through --shadow-xl)

- Updated 6 templates:
  * base.html: added common.css import
  * search/results.html, chat_list.html: feed-header.css → feed-cards.css
  * document_list.html, employees_list.html, department_list.html: added common.css

Result: 0% duplication, unified naming, DRY-compliant architecture
2025-10-28 10:35:12 +03:00
0932bcb599 refactor: Extract base-app and ios-components CSS
- Created static/css/components/base-app.css (280 lines)
  * Layout system (sidebar, navbar, rightbar)
  * Base typography and form controls
  * Notification bell, mobile FAB
  * Feed elements and ghost buttons
  * Alpha headers and action buttons

- Created static/css/components/ios-components.css (440 lines)
  * iOS-style cards, lists, and cells
  * Avatars, badges, chips
  * Collapse triggers and accordions
  * Department inline editor
  * Skills UI, activity block
  * Icon button variants

- Removed 380 lines of inline styles from base.html
- All tests passing (17 OK)
2025-10-28 09:50:39 +03:00
4d04aafdb9 refactor: Replace inline CSS with components (Phase 3)
- Replaced feed-* inline styles in base.html with feed-cards.css component (~60 lines)
- Replaced ios-search inline styles in 3 templates with ios-search.css component
  * employees/employees_list.html
  * search/results.html
  * employees/department_list.html
- Eliminated ~150 lines of duplicate CSS across templates
- All 17 tests passing
2025-10-28 08:54:38 +03:00
c3fd4916d1 refactor: extract JavaScript utilities to separate modules (Phase 2)
- Created reusable utility modules:
  * static/js/utils/stringUtils.js - string operations (esc, norm, escAttr, truncate, getInitials)
  * static/js/utils/timing.js - timing utilities (debounce, throttle, delay, poll, once)
  * static/js/utils/scroll.js - scroll helpers (smoothScrollTo, scrollToTop, isElementInViewport, etc.)

- Updated static/js/utils/index.js:
  * Exports all utilities from a single entry point
  * Provides centralized access to all utility functions

- Modified base.html:
  * Removed inline esc() and norm() function definitions
  * Added ES6 module imports for utilities
  * Exported utilities to window for backward compatibility
  * All existing code continues to work without changes

Benefits:
- Eliminates code duplication (esc/norm found in 9 templates)
- Centralizes utility functions for easier maintenance
- Enables future improvements (testing, optimization)
- Maintains backward compatibility with existing templates

Tests: All 12 static file tests passing ✅
2025-10-28 08:37:02 +03:00
c4998c709f Apply updates across all files in the repository 2025-10-20 17:08:40 +03:00
0b8c2a4d43 feat(calendar): интеграция выбора отдела через API /my-departments
feat(calendar): правый календарь с выбором источника и созданием событий (Bearer)
fix(layout): выровнял колонки к центральному контейнеру, убрал лишние отступы
fix(templates): убрана несуществующая тэг-функция токена; добавлен meta api-token
feat(chat/ui): полировка chat-root, скролла и кнопки «вниз»
style(feed): «Подробнее/Скрыть» — серые без подчёркивания

- добавлен эндпоинт DepartmentViewSet.my_departments для получения доступных отделов
  (HR → все отделы, иначе только руководимые/активные)
- настроены permissions для нового экшена
- фронтенд: заменена логика дропдауна календаря
  * загрузка списка отделов через /api/v1/departments/my-departments/
  * автогенерация пунктов меню с именами отделов
  * fallback на data-dept-id при пустом ответе
- обновлена подпись текущего календаря (кнопка и модалка «Создать событие»)
- сохранена логика работы с событиями (компания/отделы), переработан только источник данных для списка отделов
— Календарь (правая колонка)
  • Добавлен дропдаун возле «Календарь» для выбора источника: «Компания» и «Мои отделы».
  • «Мои отделы» подгружаются из GET /api/v1/employees/my-departments/ (JSON: [{id, name}]).
  • Рядом с «События» добавлена кнопка «+», открывающая модал создания события.
  • Создание события уходит в POST:
      - /api/v1/calendar/company-events/
      - /api/v1/calendar/departments/<id>/events/
    Форматы: all-day (date) либо с временем (start/end ISO). Не через сессию.
  • FullCalendar переключает источник событий в зависимости от выбранного календаря и
    ходит за ними с параметрами ?start=YYYY-MM-DD&end=YYYY-MM-DD.
  • Вертикальная «На этой неделе» рендерится из тех же данных (без лишних запросов,
    если события уже в памяти FullCalendar).
  • Мобильная версия — Offcanvas + тот же функционал.

— Авторизация / API
  • Все запросы к API — через Authorization: Bearer <token>.
  • В base.html добавлен мета-тег с токеном:
      <meta name="api-token" content="{{ request.user.api_token|default:'' }}">
  • Общий helper authFetch() отключает cookie/сессию и всегда проставляет заголовки.
  • Это устраняет 401 при GET и готовит почву под POST (ранее наблюдался 405 без POST-ручек).

— Вёрстка / контейнер
  • Левую и правую колонки «привязал» к центральному блоку (container-xxl), убраны
    чрезмерные внутренние паддинги, чтобы центральный контент не сжимался.
  • Уточнены вертикальные расстояния между карточками (gap / margin), карточки теперь
    реально «прижимаются» по вертикали, где это нужно.
  • В main контент тянется на всю доступную ширину внутри контейнера.

— Чаты
  • Объяснён и оставлен padding у .chat-root (верх/низ под шапку и композер, включая safe-area).
  • Кнопка «вниз» и стили скролла — без конфликтов с обёртками.

— Шаблоны
  • Удалён несуществующий тэг `{% api_access_token %}` (исправляет TemplateSyntaxError).
  • Вставлен рабочий meta name="api-token" вместо кастомного тега.

— Кнопки «Подробнее/Скрыть»
  • Сделаны серыми и без подчёркивания (btn btn-link text-secondary text-decoration-none).

Затронутые файлы (основные):
  • backend/templates/base.html
  • backend/templates/includes/rightbar_calendar.html        (новый/полностью переписан)
  • backend/templates/feed/_feed_cards.html                  (кнопки «Подробнее/Скрыть»)
  • backend/templates/includes/sidebar.html                  (мелкие правки отступов)
  • стили в базовом шаблоне: правки контейнеров/отступов/гридов
  • (JS в rightbar_calendar): authFetch, загрузка отделов, POST создания события, weekly strip

Примечания по бэку (ожидания фронта):
  • GET  /api/v1/employees/my-departments/ → 200 OK, JSON: [{ "id": <int>, "name": <str> }, …]
  • GET  /api/v1/calendar/company-events/?start=&end=
  • GET  /api/v1/calendar/departments/<id>/events/?start=&end=
  • POST /api/v1/calendar/company-events/                      (body: {title, date|start,end, allDay?, color?})
  • POST /api/v1/calendar/departments/<id>/events/            (аналогично)
  • Все ручки принимают Authorization: Bearer <JWT/токен>.
  • Если раньше был 405 на POST — включить create() во вьюсетах и добавить в роутер.
2025-09-08 17:19:57 +03:00
409632e3f3 feat(ui, departments): новая страница отдела — колесо команды (4 колонки), collapse «Настройки отдела», фиксы назначения ролей
— Переверстал backend/templates/employees/department_detail.html под раскладку как в employee_detail:
  • левая колонка (md-4): «Команда отдела» (круглое окно) + инфо блока;
  • правая колонка (md-8): collapse-блок «Настройки отдела» в стиле ios-card + «Публикации отдела».

— «Колесо команды»:
  • круглое окно с 4 колонками аватарок ВСЕХ участников отдела; каждый следующий ряд смещён на 0.5 размера аватарки;
  • аватарки круглые, без подписей; поддержка тёмной/светлой темы;
  • автоскролл с дуговым индикатором прогресса по правой полуокружности;
  • hover — пауза автоскролла, включается ручной скролл (колёсико/тач);
  • клик по аватарке — фокус: аватарка растягивается на весь круг; под кругом центрировано показываются имя/роль/email;
  • если в отделе нет сотрудников — в круге показывается руководитель;
  • a11y: aria-атрибуты для живого региона и описаний.

— Роли/кнопки:
  • кнопки Invite / Set role / Remove показываются только при наличии прав (is_superuser|is_staff|can_manage|can_assign_roles|head);
  • fixed: «Назначить роль» больше не падает с NoReverseMatch — action формируется из шаблона `/employees/0/departments/<dept>/set-role/` и подменяется на выбранный empId по клику;
  • формы модалок: мелкие правки, валидация, улучшения UX (ajax-поиск, активное состояние, блокировка submit, плавный скролл к collapse на мобильных).

— Настройки отдела:
  • оформлен collapse-блок «Настройки отдела» в стиле ios-card (как в редакторе профиля);
  • добавлена кнопка-шестерёнка в инфо-блоке для быстрого раскрытия;
  • include исправлен: `{% include "employees/_department_controls.html" with dept=dept edit_form=edit_form head_choices=head_choices %}`.

— Стили и скрипты:
  • локализованы в `{% block extra_js %}` (можно вынести в base позже);
  • CSS-переменные для размеров, цветов и дуги; учитывает базовый шаблон и смену темы.

Files:
  M backend/templates/employees/department_detail.html

BREAKING CHANGE: нет
2025-09-05 18:38:10 +03:00
c78d1e5fea Ключевые изменения
- **EmployeeActionSerializer**
  - Добавлен `history[]` со снапшотами simple-history и diff по полям: `action`, `date`, `comment`, `extra`, `employee_id`.
  - Локализация названий событий через `employees.constants.ACTION_CHOICES`.
  - Поля `action_display`, `date_display` для удобного фронтового рендера.

- **EmployeeSerializer**
  - Возвращает `actions` (массив событий) с историей, **только** если в контексте выставлено `include_action_history=True`.
  - Навыки: чтение — `skills` как список объектов `{id, name}`, запись — через `skills_ids`.
  - Должность: чтение — объект `{id, name}`, запись — через `position_id`.
  - Отделы: добавлен флаг `is_head` (сотрудник — руководитель отдела).

- **EmployeeListSerializer**
  - Те же правки для навыков/должности и `is_head`, без `actions` (для производительности).

- **Views (EmployeeViewSet)**
  - `get_queryset`: префетч `actions` добавляется **только** для `retrieve/me`, иначе не тянем историю.
  - `get_serializer_context`: для `retrieve` и `me` выставляем `include_action_history=True`.
  - Экшен `me`: выборка с `Prefetch("actions", order_by -date)` и передачей `include_action_history=True`.

- **Разное**
  - Используем `ACTION_CHOICES` для «человеческих» названий событий в истории.
  - `HistoryActionMixin` оставлен без изменений; история объектов доступна по `/{basename}/{pk}/history/`.

Почему так
- История кадровых событий бывает тяжёлой → грузим и отдаём её только там, где нужно (`retrieve/me`).
- Явное разделение read/write для навыков и должности упрощает фронту жизнь и убирает двусмысленность.
- `is_head` позволяет фронту не вычислять этот флаг отдельно.

Файлы
- `backend/api/v1/employees/serializers.py`
- `backend/api/v1/employees/views.py`
- (использованы константы из) `backend/employees/constants.py`

Тесты/проверка
1) GET `/api/v1/employees/1/` → поле `actions[]` заполнено, внутри каждого элемента `history[]` со снапшотами и переводами событий.
2) GET `/api/v1/employees/?page=1` → `actions` отсутствуют (по замыслу), навыки и должность приходят в «красивом» виде.
3) GET `/api/v1/employees/me/` → аналогично `retrieve`, с историей.

* UI (templates/employees/employee\_detail.html)

  * Навыки: больше не итерируем по строке, выводим объекты `{id,name}` (`s.name`).
    Защита от пустых списков.
  * Отделы: убрал «аватарки» у элементов списка, оставил иконку у кнопки раздела.
    Роль сотрудника показывается «Название отдела — Роль».
    Для руководителя добавлен понятный бейдж с иконкой `bi-award-fill` + tooltip «Руководитель отдела».
  * Кадровые события: добавлен раздел «Кадровые события» (для аутентифицированных).
    Отрисовывает список всех событий (дата, комментарий, extra), а также историю каждого события (`action.history`) в `<details>`.
    В истории показываем только название события и новые значения полей (без «создано/изменено» и без зачёркнутых старых значений).
    Перевод кодов событий (`hired`, `dismissed`, …) в человекочитаемый вид согласно `employees/constants.py`.
  * Аккордеон: кнопка и выпадающая панель объединены в один блок `.ios-acc` единой ширины.
    Добавлена разделительная линия между заголовком и контентом (`.ios-acc-body { border-top: ... }`).
    Исправлены дёрганья при анимации: убраны внешние отступы у `.collapse`, возврат стандартной скорости Bootstrap (`.35s ease`), `overflow:hidden` на фазе `collapsing`.

* Views (employees/views.py — веб-приложение)

  * В `employee_detail` и `employee_me` дополнительно запрашиваем полную историю кадровых событий:
    `GET v1/employee-actions/?employee=<id>&ordering=-date` и передаём в шаблон `employee_actions`.
    Тем самым отображаем все события, а не только последнее.
  * Шаблон умеет брать события из `employee_actions`, а при отсутствии — из `emp.actions`.

* API (backend/api/v1/employees/serializers.py)

  * `EmployeeActionSerializer`: добавлен `history` (MethodField) с формированием массива изменений из `HistoricalRecords` (без старых значений; только `changes[field].new`, дата/пользователь).
    Добален `action_display` и `date_display` для удобного рендера на фронте.
  * `EmployeeSerializer`: возвращает `departments` через `get_departments()` (id, name, role\_id, role\_name, is\_head) и `skills` как массив объектов `{id,name}`.

* Прочее/фиксы

  * Безопасные проверки на пустые коллекции (контакты, навыки, отделы, события).
  * Устранена ошибка шаблона «Failed lookup…» при попытке обратиться к отсутствующим ключам.
  * Не изменяем скорость анимации: возвращён дефолт Bootstrap; корректное закрытие панелей.

Refs: employees/constants.py (ACTION\_CHOICES), templates/employees/employee\_detail.html, employees/views.py, api/v1/employees/serializers.py
2025-08-27 17:58:46 +03:00
b401e86249 доработка стилей 2025-08-20 11:19:02 +03:00
2c85086f78 feat(feed,employees,communications): dept news, invites, chat sync; forms/admin cleanup; templates polish
## Что сделано

### Модели
- **employees**
  - : теперь включает отделы, где сотрудник является **руководителем**.
  - Уточнены :
    -  →  у ,  у .
  - : добавлены удобные геттеры , ; улучшён .
  - Модели , ,  приведены к актуальным полям (без start_date/end_date/level и т.п., чтобы не конфликтовать с формами/админкой).

- **feed**
  - Вынесены константы типов постов: , ,  + .
  - Жёсткие **CheckConstraint**:
    - для департаментских постов ,
    - для остальных — .
  - Индексы по , , .

- **communications**
  - :
    -  для  (чаты отдела удаляются вместе с отделом).
    - Метод : активные сотрудники отдела + **руководитель**; для глобального — все активные.
    - Запрет удаления **основных** чатов (global/department), но обычные удаляются нормально.

### Админка
- Приведена в соответствие моделям: убраны несуществующие поля, добавлены фильтры/поиск по реальным полям, inlines для отделов (связи сотрудников).
- Исправлены ошибки system check (E033/E108/E116).

### Формы
- , : валидация аватара, корректные required/optional, PhoneNumberField для WhatsApp/WeChat.
- ,  (динамический queryset сотрудников, не состоящих в отделе).
- , , : соответствуют актуальным моделям, с базовой валидацией диапазонов дат (если применимо).

### Вьюхи (employees)
- Переписаны аккуратно и проще:
  - Списки/детали отделов на CBV (, ), в контексте — сотрудники, новости отдела, новые сотрудники.
  - Профиль и чужой профиль использует общий шаблон с подключаемыми блоками.
  - : доступ только **админу/руководителю**; добавление связи  и автодобавление участника (и руководителя) в **чат отдела**.
  - : подготовлено к фильтрации по .

### Вьюхи (feed)
-  — **универсальная** форма:
  - контекст определяется автоматически из GET:  | ,
  - скрываем поля , чтобы пользователь не ломал контекст,
  - редирект — на **красивые** страницы: главная лента / страница отдела / лента сотрудника.
- : только админ — для компании, только **руководитель отдела** — для департамента.
- : комментарии + форма добавления.
- **Добавлены** CRUD для постов и комментариев:
  - ,  — автор/админ/руководитель отдела.
  - ,  — только автор комментария.

### URL-ы
- : добавлены маршруты , , , .
- : все нужные эндпоинты в рабочем состоянии,  на месте.

### Шаблоны
- : опрятная шапка, линк на «Все сотрудники отдела», кнопка «Пригласить» (для админа/руководителя), внизу — include **новостей отдела**.
- : приведение к общему стилю, кнопка «Новая публикация» с автоподстановкой department.
- : отображает бейдж контекста (Компания/Отдел/Личное), **одна** кнопка «Отмена»,  приходит из вьюхи.
- : контекстная кнопка «Назад к ленте» (определяется автоматически), кнопки **Редактировать/Удалить** (по правам), комментарии с кнопками **ред./удал.** у автора.
- Исправлены include-пути (везде , без обратных слешей).

## Почему всё ок
- Нет циклических импортов,  выровнены.
- Никакой магии в шаблонах: вся логика определения контекста — во вьюхах.
- Чаты отдела удаляются вместе с отделом; основные чаты защищены от удаления.
- Учитываем **руководителя отдела** везде, где нужно (новости, чат, права).

## Что проверить локально
1) Миграции:
   - python manage.py makemigrations
   - python manage.py migrate
2) Создать отдел, назначить руководителя.
3) Пригласить сотрудника → автоматически попадёт в чат отдела.
4) Создать новости:
   - с главной → тип company,
   - со страницы отдела → тип department, поле Department скрыто,
   - из ленты сотрудника → тип employee.
5) Закрепление новостей:
   - компания — только staff,
   - отдел — только head.
6) Редактирование/удаление постов и комментариев — по правам.

## Примечания
- Если ранее в БД были посты с типом 'personal' — вручную мигрируйте на 'employee'.
2025-08-08 15:16:19 +03:00
Игорь Надеин
a42204dda0 0 2025-08-05 15:30:41 +03:00
Игорь Надеин
6fb2cdcea0 feat: enhance Employee model and integrate Telegram/WhatsApp bot
- Add birth_date, created_at/updated_at to Employee; remove username field
- Introduce EmployeeAction for tracking HR events and is_actually_active/status properties
- Create BotSubscriber model (OneToOne relation) for TG/WA binding
- Implement Aiogram-based Telegram bot:
  • request contact to bind by phone or @username
  • department selection keyboard from DEPARTMENTS dict
  • async ORM via sync_to_async, custom filters for bound & active employees
- Update profile view & template:
  • show “Bind Telegram/WhatsApp” button only when not already bound
  • preview avatar on upload
- Remove registration tokens in favor of contact-based auth
- Clean up templates, forms and add avatar validation mixin
2025-07-30 08:15:53 +03:00