Root cause identified: - Template checked non-existent permissions (publish_company_post, publish_department_post) - Django only creates 4 default permissions: add, change, delete, view - User actually HAD feed.add_post permission from Position→Group chain Solution: - Changed template check to use feed.add_post (real permission) - Confirmed PositionRoleBackend works correctly (13/13 tests passed) - User can now see 'Create Post' button Production diagnostic confirmed user has permissions through position: Position 'СММ специалист' → Group 'Дизайн СММ Реклама' → Permissions include feed.add_post
762 lines
29 KiB
Markdown
762 lines
29 KiB
Markdown
# Тестирование Прав Доступа Через Должности (Position Permissions)
|
||
|
||
## ✅ РЕШЕНИЕ НАЙДЕНО И ПРИМЕНЕНО
|
||
|
||
**Дата:** 8 декабря 2025
|
||
**Статус:** ✅ Исправлено и протестировано
|
||
|
||
### Корневая Причина
|
||
|
||
В шаблоне `feed/feed_list.html` проверялись **несуществующие** права:
|
||
```django
|
||
{% if user.is_staff or perms.feed.publish_company_post or perms.feed.publish_department_post %}
|
||
```
|
||
|
||
Эти права **никогда не создавались** в Django! Правильное право для создания постов:
|
||
```django
|
||
{% if user.is_staff or perms.feed.add_post %}
|
||
```
|
||
|
||
### Диагностика Production
|
||
|
||
Запущен отладочный скрипт для пользователя `maze3290@gmail.com`:
|
||
|
||
```python
|
||
User: maze3290@gmail.com
|
||
Position: СММ специалист
|
||
Position Groups: ['Дизайн СММ Реклама']
|
||
Group Permissions: ['add_post', 'change_post', 'delete_post', 'view_post', ...]
|
||
|
||
User Permissions (via PositionRoleBackend):
|
||
{'feed.add_post', 'feed.change_post', 'feed.delete_post', ...}
|
||
|
||
Has feed.publish_company_post: False # ❌ Несуществующее право!
|
||
Has feed.add_post: True # ✅ Реальное право!
|
||
```
|
||
|
||
**Вывод:** PositionRoleBackend работает правильно, проблема была в шаблоне!
|
||
|
||
### Исправление
|
||
|
||
**Файл:** `backend/templates/feed/feed_list.html` (строка 19)
|
||
|
||
```diff
|
||
- {% if user.is_staff or perms.feed.publish_company_post or perms.feed.publish_department_post %}
|
||
+ {% if user.is_staff or perms.feed.add_post %}
|
||
```
|
||
|
||
### Коммиты
|
||
|
||
1. `769f2ed` - test: add comprehensive position permissions tests
|
||
2. `66406d9` - fix: add is_active check to PositionRoleBackend
|
||
3. `4a6b92f` - docs: add production debugging guide
|
||
4. `6162d9f` - **fix: correct permission check in feed_list.html** ← РЕШЕНИЕ
|
||
|
||
---
|
||
|
||
## Описание Проблемы (Оригинал)
|
||
|
||
### Исходная Жалоба Пользователя
|
||
> "Ты говорил, что пользователь с должностью получает все права которые есть у групп в этой должности, но по факту кнопка создания публикаций не появляется"
|
||
|
||
**Ожидаемое поведение:**
|
||
- Пользователь имеет должность (Position)
|
||
- Должность связана с группами (Position.groups)
|
||
- Группы имеют права (Group.permissions)
|
||
- Пользователь должен получить все права из групп своей должности
|
||
|
||
**Фактическое поведение:**
|
||
- UI кнопки не появляются (например, "Создать публикацию")
|
||
- Пользователи с должностями не могут выполнять действия, несмотря на наличие прав в группах
|
||
|
||
## Архитектура Системы Прав
|
||
|
||
### Цепочка Наследования
|
||
```
|
||
Position → Position.groups (ManyToMany) → Group.permissions (ManyToMany) → Permission
|
||
↓
|
||
Employee.position (ForeignKey)
|
||
↓
|
||
User (связан через OneToOne)
|
||
```
|
||
|
||
### Реализация Backend
|
||
|
||
**Файл:** `backend/eusrr_backend/auth_backends.py`
|
||
|
||
```python
|
||
class PositionRoleBackend(BaseBackend):
|
||
"""
|
||
Custom authentication backend that grants permissions based on
|
||
Position.groups relationships.
|
||
"""
|
||
|
||
def get_all_permissions(self, user_obj, obj=None):
|
||
if not user_obj.is_active or user_obj.is_anonymous:
|
||
return set()
|
||
|
||
# Получаем права из должности
|
||
if hasattr(user_obj, 'employee') and user_obj.employee.position:
|
||
pos = user_obj.employee.position
|
||
return set(
|
||
Permission.objects.filter(
|
||
group__positions=pos
|
||
).select_related('content_type').values_list(
|
||
'content_type__app_label',
|
||
'codename'
|
||
)
|
||
)
|
||
|
||
return set()
|
||
```
|
||
|
||
**Конфигурация:** `settings.py` (строка 329)
|
||
```python
|
||
AUTHENTICATION_BACKENDS = [
|
||
'django.contrib.auth.backends.ModelBackend',
|
||
'eusrr_backend.auth_backends.LDAPAuthBackend',
|
||
'eusrr_backend.auth_backends.LDAPGroupAuthBackend',
|
||
'eusrr_backend.auth_backends.PositionRoleBackend', # ← Наш backend
|
||
]
|
||
```
|
||
|
||
### Модели
|
||
|
||
**Файл:** `backend/employees/models.py`
|
||
|
||
```python
|
||
class Position(models.Model):
|
||
"""Должность сотрудника"""
|
||
name = models.CharField(max_length=100, unique=True)
|
||
groups = models.ManyToManyField(
|
||
Group,
|
||
related_name='positions',
|
||
blank=True
|
||
)
|
||
|
||
class Employee(models.Model):
|
||
"""Сотрудник"""
|
||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||
position = models.ForeignKey(
|
||
Position,
|
||
on_delete=models.SET_NULL,
|
||
null=True,
|
||
blank=True
|
||
)
|
||
```
|
||
|
||
## Тестовая Стратегия
|
||
|
||
### Цель Тестов
|
||
Определить, является ли проблема:
|
||
1. **Логической ошибкой** в `PositionRoleBackend` → Тесты упадут
|
||
2. **Проблемой конфигурации** (кэширование, LDAP sync, deployment) → Тесты пройдут
|
||
|
||
### Структура Тестов
|
||
|
||
**Файл:** `backend/tests/employees/test_position_permissions.py`
|
||
|
||
#### Базовые Тесты (TestPositionPermissions)
|
||
```python
|
||
class TestPositionPermissions:
|
||
"""Основная функциональность"""
|
||
|
||
✅ test_user_without_position_has_no_permissions
|
||
Проверяет: Пользователь без должности = нет прав
|
||
|
||
❌ test_user_with_position_gets_permissions
|
||
Проверяет: Position с Group → User получает права
|
||
|
||
❌ test_position_change_updates_permissions
|
||
Проверяет: Смена должности → права обновляются
|
||
|
||
❌ test_remove_position_removes_permissions
|
||
Проверяет: Удаление должности → права убираются
|
||
|
||
❌ test_multiple_users_same_position
|
||
Проверяет: Несколько user с одной Position → одинаковые права
|
||
|
||
❌ test_staff_user_keeps_permissions
|
||
Проверяет: Staff users сохраняют is_staff права
|
||
|
||
✅ test_position_group_permissions_are_additive
|
||
Проверяет: Несколько групп → права складываются
|
||
|
||
❌ test_get_all_permissions_includes_position_perms
|
||
Проверяет: get_all_permissions() возвращает права должности
|
||
```
|
||
|
||
#### Граничные Случаи (TestPositionPermissionsEdgeCases)
|
||
```python
|
||
class TestPositionPermissionsEdgeCases:
|
||
"""Edge cases и особые ситуации"""
|
||
|
||
✅ test_position_without_groups_grants_no_permissions
|
||
Проверяет: Position без groups = нет прав
|
||
|
||
❌ test_inactive_user_has_no_permissions
|
||
Проверяет: Неактивный user = нет прав (даже с Position)
|
||
|
||
❌ test_direct_user_permissions_and_position_permissions
|
||
Проверяет: Прямые права user + права Position = аддитивны
|
||
```
|
||
|
||
#### Интеграционные Тесты (TestPositionPermissionsIntegration)
|
||
```python
|
||
class TestPositionPermissionsIntegration:
|
||
"""Интеграция с реальными моделями"""
|
||
|
||
❌ test_feed_publish_permission_via_position
|
||
Проверяет: Право "feed.publish_company_post" работает
|
||
|
||
❌ test_document_add_permission_via_position
|
||
Проверяет: Право "documents.add_document" работает
|
||
```
|
||
|
||
### Текущие Результаты
|
||
```
|
||
============== test session starts ==============
|
||
collected 13 items
|
||
|
||
✅ PASSED: 3 tests
|
||
❌ ERRORS: 10 tests
|
||
|
||
Passing Tests:
|
||
- test_user_without_position_has_no_permissions
|
||
- test_position_group_permissions_are_additive
|
||
- test_position_without_groups_grants_no_permissions
|
||
|
||
Failing Tests:
|
||
- All tests with IntegrityError or fixture issues
|
||
```
|
||
|
||
## Обнаруженные Проблемы в Тестах
|
||
|
||
### Проблема 1: IntegrityError на Permission Creation
|
||
**Ошибка:**
|
||
```
|
||
IntegrityError: UNIQUE constraint failed: auth_permission.content_type_id, auth_permission.codename
|
||
```
|
||
|
||
**Причина:**
|
||
Использование `Permission.objects.get_or_create()` в фикстурах приводит к попыткам создать дубликаты.
|
||
|
||
**Решение:**
|
||
Изменить паттерн создания:
|
||
|
||
```python
|
||
# ❌ Старый код
|
||
perm, _ = Permission.objects.get_or_create(
|
||
codename='publish_company_post',
|
||
content_type=feed_content_type,
|
||
defaults={'name': 'Can publish company post'}
|
||
)
|
||
|
||
# ✅ Новый код
|
||
perm = Permission.objects.filter(
|
||
codename='publish_company_post',
|
||
content_type=feed_content_type
|
||
).first()
|
||
|
||
if not perm:
|
||
perm = Permission.objects.create(
|
||
codename='publish_company_post',
|
||
content_type=feed_content_type,
|
||
name='Can publish company post'
|
||
)
|
||
```
|
||
|
||
**Статус:** Исправлено в 3 местах:
|
||
- ✅ Фикстура `group_with_publish_perm` (строки 44-62)
|
||
- ✅ Фикстура `group_with_document_perm` (строки 64-82)
|
||
- ✅ Тест `test_position_group_permissions_are_additive` (строки 244-269)
|
||
|
||
### Проблема 2: Fixture Visibility Between Test Classes
|
||
**Ошибка:**
|
||
```
|
||
fixture 'engineer_position' not found
|
||
fixture 'feed_content_type' not found
|
||
fixture 'documents_content_type' not found
|
||
```
|
||
|
||
**Причина:**
|
||
Фикстуры определены в `TestPositionPermissions` как методы класса, но дочерние классы `TestPositionPermissionsEdgeCases` и `TestPositionPermissionsIntegration` не имеют к ним доступа.
|
||
|
||
**Возможные решения:**
|
||
1. Перенести фикстуры на уровень модуля (вне классов)
|
||
2. Использовать `@pytest.fixture(scope="module")`
|
||
3. Использовать наследование классов
|
||
4. Создать фикстуры в `conftest.py`
|
||
|
||
**Статус:** ❌ Не исправлено
|
||
|
||
### Проблема 3: Permission Objects Already Exist in Database
|
||
**Ошибка:**
|
||
При запуске тестов Django уже имеет базовые права из миграций.
|
||
|
||
**Решение:**
|
||
Использовать `.filter().first()` вместо `.create()` для всех Permission объектов.
|
||
|
||
**Статус:** ✅ Частично исправлено (нужна проверка всех 13 тестов)
|
||
|
||
## План Исправления
|
||
|
||
### Шаг 1: Рефакторинг Фикстур ✅ IN PROGRESS
|
||
- [x] Заменить `get_or_create` на `filter().first()` + conditional create
|
||
- [x] Применить в `group_with_publish_perm`
|
||
- [x] Применить в `group_with_document_perm`
|
||
- [x] Применить в `test_position_group_permissions_are_additive`
|
||
- [ ] Перенести фикстуры на module level
|
||
|
||
### Шаг 2: Запуск Тестов
|
||
```bash
|
||
cd /c/Users/Игорь/Dev/EUSRR/backend
|
||
pytest tests/employees/test_position_permissions.py -v --tb=short
|
||
```
|
||
|
||
**Ожидаемый результат после исправлений:**
|
||
- Все 13 тестов должны запуститься (не ERROR)
|
||
- Проверим, сколько PASS vs FAIL
|
||
|
||
### Шаг 3: Анализ Результатов
|
||
|
||
#### Сценарий А: Все тесты PASS ✅
|
||
**Вывод:** Логика `PositionRoleBackend` корректна
|
||
|
||
**Действия:**
|
||
1. Проверить production конфигурацию:
|
||
- `AUTHENTICATION_BACKENDS` order
|
||
- Кэширование прав (Django cache)
|
||
- LDAP синхронизация групп
|
||
|
||
2. Проверить данные в БД:
|
||
```python
|
||
# Django shell
|
||
user = User.objects.get(username='...')
|
||
print(user.employee.position)
|
||
print(user.employee.position.groups.all())
|
||
print(user.get_all_permissions()) # Должны быть права из Position
|
||
```
|
||
|
||
3. Проверить middleware и template context
|
||
|
||
#### Сценарий Б: Некоторые тесты FAIL ❌
|
||
**Вывод:** Есть проблема в логике `PositionRoleBackend`
|
||
|
||
**Действия:**
|
||
1. Проанализировать failing assertions
|
||
2. Исправить `get_all_permissions()` или `has_perm()`
|
||
3. Убедиться что query `Permission.objects.filter(group__positions=pos)` корректен
|
||
4. Проверить returns в формате "app_label.codename"
|
||
|
||
## Проверка UI Visibility
|
||
|
||
### Текущая Реализация
|
||
|
||
**Файл:** `backend/templates/feed/feed_list.html` (строка 19)
|
||
```html
|
||
{% if user.is_staff or perms.feed.publish_company_post or perms.feed.publish_department_post %}
|
||
<button class="btn btn-primary">Создать публикацию</button>
|
||
{% endif %}
|
||
```
|
||
|
||
**Файл:** `backend/templates/documents/document_list.html` (строки 17-21)
|
||
```html
|
||
{% if user.is_staff or perms.documents.add_document %}
|
||
<a href="{% url 'documents:document_create' %}" class="btn btn-primary">
|
||
Добавить документ
|
||
</a>
|
||
{% endif %}
|
||
```
|
||
|
||
### Логика Проверки в Templates
|
||
|
||
Django использует `perms.app_label.codename` в шаблонах:
|
||
1. Вызывает `user.has_perm('app_label.codename')`
|
||
2. Проходит по всем AUTHENTICATION_BACKENDS
|
||
3. Если хотя бы один backend вернёт `True` → permission granted
|
||
|
||
**Требования:**
|
||
- `PositionRoleBackend.has_perm()` должен вернуть `True`
|
||
- `PositionRoleBackend.get_all_permissions()` должен включать это право
|
||
- Формат: tuple `('app_label', 'codename')` или строка `'app_label.codename'`
|
||
|
||
## Отладочные Команды
|
||
|
||
### Django Shell Testing
|
||
```python
|
||
from django.contrib.auth.models import User, Permission, Group
|
||
from django.contrib.contenttypes.models import ContentType
|
||
from employees.models import Employee, Position
|
||
|
||
# Получить пользователя
|
||
user = User.objects.get(username='test_user')
|
||
|
||
# Проверить должность
|
||
print(f"Position: {user.employee.position}")
|
||
print(f"Position Groups: {user.employee.position.groups.all()}")
|
||
|
||
# Проверить права через backend
|
||
from eusrr_backend.auth_backends import PositionRoleBackend
|
||
backend = PositionRoleBackend()
|
||
all_perms = backend.get_all_permissions(user)
|
||
print(f"All Permissions: {all_perms}")
|
||
|
||
# Проверить has_perm
|
||
has_perm = backend.has_perm(user, 'feed.publish_company_post')
|
||
print(f"Has feed.publish_company_post: {has_perm}")
|
||
|
||
# Проверить через Django API
|
||
has_perm_django = user.has_perm('feed.publish_company_post')
|
||
print(f"User.has_perm('feed.publish_company_post'): {has_perm_django}")
|
||
```
|
||
|
||
### SQL Query Debugging
|
||
```python
|
||
from django.db import connection
|
||
from django.test.utils import CaptureQueriesContext
|
||
|
||
with CaptureQueriesContext(connection) as queries:
|
||
perms = backend.get_all_permissions(user)
|
||
|
||
for q in queries:
|
||
print(q['sql'])
|
||
```
|
||
|
||
### LDAP Group Sync Check
|
||
```python
|
||
from employees.ldap.services import PositionService
|
||
|
||
pos = Position.objects.get(name='Engineer')
|
||
dn = PositionService._ensure_position_group(pos)
|
||
print(f"LDAP Group DN: {dn}")
|
||
```
|
||
|
||
## Ожидаемая SQL Query
|
||
|
||
При вызове `get_all_permissions()` должен выполниться query:
|
||
|
||
```sql
|
||
SELECT DISTINCT
|
||
django_content_type.app_label,
|
||
auth_permission.codename
|
||
FROM auth_permission
|
||
INNER JOIN django_content_type
|
||
ON auth_permission.content_type_id = django_content_type.id
|
||
INNER JOIN auth_group_permissions
|
||
ON auth_permission.id = auth_group_permissions.permission_id
|
||
INNER JOIN auth_group
|
||
ON auth_group_permissions.group_id = auth_group.id
|
||
INNER JOIN employees_position_groups
|
||
ON auth_group.id = employees_position_groups.group_id
|
||
WHERE employees_position_groups.position_id = ?
|
||
```
|
||
|
||
## Контрольный Чеклист
|
||
|
||
### Pre-Test Checklist
|
||
- [x] Создан файл `tests/employees/test_position_permissions.py`
|
||
- [x] 13 тестов покрывают все сценарии
|
||
- [x] Фикстуры используют `.filter().first()` для Permission
|
||
- [ ] Фикстуры доступны во всех test классах
|
||
- [ ] Тесты запускаются без ERROR
|
||
|
||
### Post-Test Checklist (если тесты проходят)
|
||
- [ ] Проверить `user.get_all_permissions()` в production shell
|
||
- [ ] Проверить `user.has_perm('feed.publish_company_post')` в production
|
||
- [ ] Проверить что `Position.groups` содержит нужные группы
|
||
- [ ] Проверить что `Group.permissions` содержит нужные права
|
||
- [ ] Проверить порядок AUTHENTICATION_BACKENDS
|
||
- [ ] Очистить Django permission cache
|
||
- [ ] Перезапустить сервер
|
||
|
||
### Post-Test Checklist (если тесты не проходят)
|
||
- [ ] Проанализировать failing assertions
|
||
- [ ] Исправить логику в `PositionRoleBackend.get_all_permissions()`
|
||
- [ ] Исправить логику в `PositionRoleBackend.has_perm()`
|
||
- [ ] Убедиться что query возвращает правильный формат
|
||
- [ ] Проверить related_name в моделях
|
||
- [ ] Перезапустить тесты
|
||
|
||
## Следующие Шаги
|
||
|
||
1. **Сейчас:** Исправить fixture visibility (перенести на module level)
|
||
2. **Потом:** Запустить pytest с verbose output
|
||
3. **Далее:** Проанализировать PASS/FAIL результаты
|
||
4. **Финал:** Исправить production или backend в зависимости от результатов
|
||
|
||
## Дополнительная Информация
|
||
|
||
### Связанные Файлы
|
||
- `backend/eusrr_backend/auth_backends.py` - PositionRoleBackend
|
||
- `backend/employees/models.py` - Position, Employee
|
||
- `backend/templates/feed/feed_list.html` - UI для публикаций
|
||
- `backend/templates/documents/document_list.html` - UI для документов
|
||
- `backend/tests/employees/test_position_permissions.py` - Тесты
|
||
|
||
### Связанные Коммиты
|
||
- `769f2ed` - test: add comprehensive position permissions tests
|
||
|
||
### Известные Ограничения
|
||
- Права кэшируются Django (может требовать перезапуска)
|
||
- LDAP синхронизация может задерживаться
|
||
- Staff users всегда имеют все права (is_staff=True)
|
||
|
||
---
|
||
|
||
**Документ создан:** 2025-01-XX
|
||
**Последнее обновление:** ✅ ВСЕ ТЕСТЫ ПРОШЛИ (13/13 PASSED)
|
||
**Статус:** ✅ Готово к production тестированию
|
||
|
||
## ВАЖНО: Что Делать Дальше
|
||
|
||
### ✅ Что Мы Выяснили
|
||
|
||
**Тесты показали, что логика `PositionRoleBackend` работает ПРАВИЛЬНО!**
|
||
|
||
- ✅ Пользователи с должностями получают права из групп
|
||
- ✅ Права обновляются при смене должности
|
||
- ✅ Права удаляются при снятии должности
|
||
- ✅ `has_perm()` и `get_all_permissions()` работают корректно
|
||
- ✅ Добавлена проверка `is_active` (исправили баг)
|
||
|
||
### 🔍 Где Искать Проблему
|
||
|
||
Если кнопки **всё ещё не появляются** в production, проблема НЕ в коде, а в:
|
||
|
||
1. **Кэширование прав Django**
|
||
- Django кэширует права в `_perm_cache` и `_user_perm_cache`
|
||
- После изменения должности нужен перелогин или очистка кэша
|
||
|
||
2. **LDAP синхронизация групп**
|
||
- Проверить что `Position.groups` содержит правильные группы
|
||
- Проверить что `Group.permissions` содержит нужные права
|
||
|
||
3. **Порядок AUTHENTICATION_BACKENDS**
|
||
- `PositionRoleBackend` должен быть в списке (сейчас на 4 месте ✅)
|
||
- Возможно другие backend'ы блокируют его работу
|
||
|
||
### 📋 Чеклист Отладки Production
|
||
|
||
#### Шаг 1: Проверить Права в Django Shell
|
||
|
||
```python
|
||
from django.contrib.auth import get_user_model
|
||
User = get_user_model()
|
||
|
||
# Замените на реального пользователя
|
||
user = User.objects.get(username='имя_пользователя')
|
||
|
||
print(f"1. Position: {user.position}")
|
||
print(f"2. Position Groups: {user.position.groups.all() if user.position else 'NO POSITION'}")
|
||
|
||
if user.position:
|
||
for group in user.position.groups.all():
|
||
print(f" - Group: {group.name}")
|
||
print(f" Permissions: {list(group.permissions.values_list('codename', flat=True))}")
|
||
|
||
print(f"\n3. User Permissions:")
|
||
print(f" All Permissions: {user.get_all_permissions()}")
|
||
print(f" Has feed.publish_company_post: {user.has_perm('feed.publish_company_post')}")
|
||
print(f" Has documents.add_document: {user.has_perm('documents.add_document')}")
|
||
```
|
||
|
||
**Ожидаемый результат:**
|
||
- `Position` должен быть не `None`
|
||
- `Position.groups` должны содержать группы
|
||
- `Group.permissions` должны включать нужные права
|
||
- `user.get_all_permissions()` должен возвращать права из должности
|
||
- `user.has_perm('feed.publish_company_post')` должен быть `True`
|
||
|
||
#### Шаг 2: Проверить Базу Данных
|
||
|
||
```sql
|
||
-- Проверить связь User → Employee → Position
|
||
SELECT u.username, e.id, p.name
|
||
FROM auth_user u
|
||
JOIN employees_employee e ON e.user_id = u.id
|
||
LEFT JOIN employees_position p ON e.position_id = p.id
|
||
WHERE u.username = 'имя_пользователя';
|
||
|
||
-- Проверить связь Position → Groups
|
||
SELECT p.name AS position, g.name AS group_name
|
||
FROM employees_position p
|
||
JOIN employees_position_groups pg ON pg.position_id = p.id
|
||
JOIN auth_group g ON pg.group_id = g.id
|
||
WHERE p.id = <position_id>;
|
||
|
||
-- Проверить связь Group → Permissions
|
||
SELECT g.name AS group_name, p.codename
|
||
FROM auth_group g
|
||
JOIN auth_group_permissions gp ON gp.group_id = g.id
|
||
JOIN auth_permission p ON gp.permission_id = p.id
|
||
WHERE g.id IN (
|
||
SELECT group_id FROM employees_position_groups
|
||
WHERE position_id = <position_id>
|
||
);
|
||
```
|
||
|
||
#### Шаг 3: Очистить Кэш Прав
|
||
|
||
```python
|
||
from django.contrib.auth import get_user_model
|
||
User = get_user_model()
|
||
|
||
user = User.objects.get(username='имя_пользователя')
|
||
|
||
# Очистить кэши прав
|
||
if hasattr(user, '_perm_cache'):
|
||
delattr(user, '_perm_cache')
|
||
if hasattr(user, '_user_perm_cache'):
|
||
delattr(user, '_user_perm_cache')
|
||
|
||
# Или просто получить fresh instance
|
||
user = User.objects.get(id=user.id)
|
||
|
||
# Проверить снова
|
||
print(user.has_perm('feed.publish_company_post'))
|
||
```
|
||
|
||
#### Шаг 4: Проверить Template Context
|
||
|
||
В шаблоне `feed/feed_list.html`:
|
||
```django
|
||
{# DEBUG: Покажите права пользователя #}
|
||
{% if user.is_authenticated %}
|
||
<p>User: {{ user.username }}</p>
|
||
<p>Position: {{ user.position }}</p>
|
||
<p>Has publish_company_post: {{ perms.feed.publish_company_post }}</p>
|
||
<p>Has publish_department_post: {{ perms.feed.publish_department_post }}</p>
|
||
<p>Is Staff: {{ user.is_staff }}</p>
|
||
{% endif %}
|
||
```
|
||
|
||
#### Шаг 5: Проверить Middleware
|
||
|
||
В `settings.py` убедитесь что есть:
|
||
```python
|
||
MIDDLEWARE = [
|
||
...
|
||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||
...
|
||
]
|
||
```
|
||
|
||
#### Шаг 6: Перезапустить Сервер
|
||
|
||
```bash
|
||
# Остановить
|
||
Ctrl+C
|
||
|
||
# Очистить кэш (если используется Redis/Memcached)
|
||
python manage.py shell
|
||
>>> from django.core.cache import cache
|
||
>>> cache.clear()
|
||
>>> exit()
|
||
|
||
# Запустить снова
|
||
python manage.py runserver
|
||
```
|
||
|
||
#### Шаг 7: Перелогинить Пользователя
|
||
|
||
- Попросите пользователя выйти из системы
|
||
- Войти заново
|
||
- Проверить видимость кнопок
|
||
|
||
### 🐛 Возможные Проблемы
|
||
|
||
#### Проблема 1: Position.groups пустые
|
||
|
||
**Симптом:** `user.position.groups.all()` возвращает пустой список
|
||
|
||
**Решение:**
|
||
```python
|
||
from employees.models import Position
|
||
from django.contrib.auth.models import Group
|
||
|
||
# Найти или создать группу
|
||
pub_group = Group.objects.get(name="publishers")
|
||
|
||
# Назначить группу должности
|
||
position = Position.objects.get(name="Инженер")
|
||
position.groups.add(pub_group)
|
||
```
|
||
|
||
#### Проблема 2: Group.permissions пустые
|
||
|
||
**Симптом:** `group.permissions.all()` возвращает пустой список
|
||
|
||
**Решение:**
|
||
```python
|
||
from django.contrib.auth.models import Group, Permission
|
||
from django.contrib.contenttypes.models import ContentType
|
||
|
||
# Найти Content Type
|
||
ct = ContentType.objects.get(app_label="feed", model="post")
|
||
|
||
# Найти или создать Permission
|
||
perm = Permission.objects.filter(
|
||
codename="publish_company_post",
|
||
content_type=ct
|
||
).first()
|
||
|
||
if not perm:
|
||
perm = Permission.objects.create(
|
||
codename="publish_company_post",
|
||
name="Can publish company post",
|
||
content_type=ct
|
||
)
|
||
|
||
# Добавить в группу
|
||
pub_group = Group.objects.get(name="publishers")
|
||
pub_group.permissions.add(perm)
|
||
```
|
||
|
||
#### Проблема 3: LDAP не синхронизирует группы
|
||
|
||
**Симптом:** В LDAP нет группы `POS_Инженер`
|
||
|
||
**Решение:**
|
||
```python
|
||
from employees.models import Position
|
||
from employees.ldap.services import PositionService
|
||
|
||
position = Position.objects.get(name="Инженер")
|
||
dn = PositionService._ensure_position_group(position)
|
||
print(f"LDAP Group DN: {dn}")
|
||
```
|
||
|
||
### <20> Итоговая Таблица Результатов Тестов
|
||
|
||
| Тест | Статус | Что проверяет |
|
||
|------|--------|---------------|
|
||
| test_user_without_position_has_no_permissions | ✅ PASS | Без должности = нет прав |
|
||
| test_user_with_position_gets_permissions | ✅ PASS | С должностью = права есть |
|
||
| test_position_change_updates_permissions | ✅ PASS | Смена должности обновляет права |
|
||
| test_remove_position_removes_permissions | ✅ PASS | Удаление должности убирает права |
|
||
| test_multiple_users_with_same_position | ✅ PASS | Несколько user одна должность |
|
||
| test_superuser_has_all_permissions | ✅ PASS | Superuser имеет все права |
|
||
| test_position_group_permissions_are_additive | ✅ PASS | Несколько групп складываются |
|
||
| test_get_all_permissions_includes_position_perms | ✅ PASS | get_all_permissions() работает |
|
||
| test_position_without_groups_grants_no_permissions | ✅ PASS | Должность без групп = нет прав |
|
||
| test_inactive_user_has_no_permissions | ✅ PASS | Неактивный user = нет прав |
|
||
| test_position_permissions_with_direct_user_permissions | ✅ PASS | Прямые + должность аддитивны |
|
||
| test_feed_permissions_through_position | ✅ PASS | Реальные feed права работают |
|
||
| test_documents_permissions_through_position | ✅ PASS | Реальные document права работают |
|
||
|
||
### 🎯 Рекомендации
|
||
|
||
1. **Запустить отладочный скрипт** (Шаг 1) чтобы увидеть текущее состояние
|
||
2. **Проверить LDAP синхронизацию** группы для должности
|
||
3. **Очистить кэш** и перелогинить пользователя
|
||
4. **Если проблема остаётся:** Показать вывод отладочного скрипта
|
||
|
||
**Результат должен быть:** Кнопки появляются у пользователей с нужными должностями! 🎉
|
||
|
||
---
|
||
|
||
**Документ создан:** 2025-01-XX
|
||
**Последнее обновление:** ✅ ВСЕ ТЕСТЫ ПРОШЛИ (13/13 PASSED)
|
||
**Статус:** ✅ Готово к production тестированию
|