- Создана заглушка для calendarEventDragDrop.js с экспортом initCalendarEventDragDrop - Закомментирован импорт несуществующего database.js в emoji-picker/index.js - Исправлена ошибка 'does not provide an export named initCalendarEventDragDrop' - Исправлена ошибка 404 для emoji-picker/database.js
301 lines
11 KiB
Python
301 lines
11 KiB
Python
"""
|
||
Тесты для проверки прав доступа к календарям.
|
||
|
||
Проверяет исправление бага, где обычные пользователи не могли
|
||
создавать события в глобальных календарях с правом can_edit.
|
||
"""
|
||
|
||
from datetime import date
|
||
|
||
import pytest
|
||
from calendar_app.models import Calendar, CalendarSubscription, CalendarVisibility
|
||
from django.contrib.auth import get_user_model
|
||
from rest_framework import status
|
||
from rest_framework.test import APIClient
|
||
|
||
User = get_user_model()
|
||
|
||
|
||
@pytest.fixture
|
||
def api_client():
|
||
"""API клиент."""
|
||
return APIClient()
|
||
|
||
|
||
@pytest.fixture
|
||
def admin_user(db):
|
||
"""Создаёт администратора."""
|
||
return User.objects.create_superuser(
|
||
username="admin", email="admin@test.com", password="admin123"
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def regular_user(db):
|
||
"""Создаёт обычного пользователя."""
|
||
return User.objects.create_user(
|
||
username="user",
|
||
email="user@test.com",
|
||
password="user123",
|
||
phone_number="+79001234567",
|
||
send_activation_email=False,
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def global_calendar(db, admin_user):
|
||
"""Создаёт глобальный календарь."""
|
||
return Calendar.objects.create(
|
||
title="Общий календарь",
|
||
description="Календарь для всех",
|
||
visibility=CalendarVisibility.PUBLIC,
|
||
default_can_edit=False, # По умолчанию не могут редактировать
|
||
created_by=admin_user,
|
||
)
|
||
|
||
|
||
@pytest.mark.django_db
|
||
class TestGlobalCalendarPermissions:
|
||
"""Тесты прав доступа для глобальных календарей."""
|
||
|
||
def test_admin_can_create_event_in_global_calendar(
|
||
self, api_client, admin_user, global_calendar
|
||
):
|
||
"""Админ может создавать события в глобальном календаре."""
|
||
api_client.force_authenticate(user=admin_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"calendar_id": global_calendar.id,
|
||
"title": "Встреча админов",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["title"] == "Встреча админов"
|
||
|
||
def test_regular_user_cannot_create_without_permission(
|
||
self, api_client, regular_user, global_calendar
|
||
):
|
||
"""Обычный пользователь НЕ может создавать без прав."""
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"calendar_id": global_calendar.id,
|
||
"title": "Попытка создать",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||
|
||
def test_regular_user_can_create_with_subscription(
|
||
self, api_client, regular_user, global_calendar
|
||
):
|
||
"""Обычный пользователь МОЖЕТ создавать с подпиской can_edit=True."""
|
||
# Создаём подписку с правом редактирования
|
||
CalendarSubscription.objects.create(
|
||
calendar=global_calendar, user=regular_user, can_edit=True
|
||
)
|
||
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"calendar_id": global_calendar.id,
|
||
"title": "Событие пользователя",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["title"] == "Событие пользователя"
|
||
|
||
def test_regular_user_cannot_create_with_readonly_subscription(
|
||
self, api_client, regular_user, global_calendar
|
||
):
|
||
"""Пользователь НЕ может создавать с подпиской can_edit=False."""
|
||
# Создаём подписку БЕЗ права редактирования
|
||
CalendarSubscription.objects.create(
|
||
calendar=global_calendar, user=regular_user, can_edit=False
|
||
)
|
||
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"calendar_id": global_calendar.id,
|
||
"title": "Попытка создать",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||
|
||
def test_regular_user_can_create_when_default_can_edit_true(
|
||
self, api_client, regular_user, admin_user
|
||
):
|
||
"""Пользователь МОЖЕТ создавать если default_can_edit=True."""
|
||
# Создаём календарь с default_can_edit=True
|
||
calendar = Calendar.objects.create(
|
||
title="Открытый календарь",
|
||
visibility=CalendarVisibility.PUBLIC,
|
||
default_can_edit=True, # ✅ Все могут редактировать
|
||
created_by=admin_user,
|
||
)
|
||
|
||
# Подписываем пользователя (обязательно для доступа)
|
||
CalendarSubscription.objects.create(
|
||
calendar=calendar, user=regular_user, can_edit=True
|
||
)
|
||
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"calendar_id": calendar.id,
|
||
"title": "Открытое событие",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["title"] == "Открытое событие"
|
||
|
||
|
||
@pytest.mark.django_db
|
||
class TestLegacyCalendarPermissions:
|
||
"""Тесты обратной совместимости с legacy календарями."""
|
||
|
||
def test_regular_user_cannot_create_in_company_calendar(
|
||
self, api_client, regular_user
|
||
):
|
||
"""Обычный пользователь НЕ может создавать в календаре компании (legacy)."""
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
# Без calendar_id, department_id, employee_id = календарь компании
|
||
"title": "Попытка создать",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||
|
||
def test_admin_can_create_in_company_calendar(self, api_client, admin_user):
|
||
"""Админ МОЖЕТ создавать в календаре компании (legacy)."""
|
||
api_client.force_authenticate(user=admin_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"title": "Собрание компании",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["title"] == "Собрание компании"
|
||
|
||
def test_user_can_create_in_personal_calendar(self, api_client, regular_user):
|
||
"""Пользователь МОЖЕТ создавать в своём личном календаре."""
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.post(
|
||
"/api/v1/calendar/events/",
|
||
{
|
||
"employee_id": regular_user.id,
|
||
"title": "Личное событие",
|
||
"start_date": "2026-03-01",
|
||
"all_day": True,
|
||
},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["title"] == "Личное событие"
|
||
|
||
|
||
@pytest.mark.django_db
|
||
class TestEventUpdateDeletePermissions:
|
||
"""Тесты прав на обновление и удаление событий."""
|
||
|
||
def test_user_can_update_own_event_in_global_calendar(
|
||
self, api_client, regular_user, global_calendar
|
||
):
|
||
"""Пользователь МОЖЕТ обновлять своё событие если есть права."""
|
||
from calendar_app.models import CalendarEvent
|
||
|
||
# Даём права
|
||
CalendarSubscription.objects.create(
|
||
calendar=global_calendar, user=regular_user, can_edit=True
|
||
)
|
||
|
||
# Создаём событие
|
||
event = CalendarEvent.objects.create(
|
||
calendar=global_calendar,
|
||
title="Моё событие",
|
||
start_date=date(2026, 3, 1),
|
||
all_day=True,
|
||
created_by=regular_user,
|
||
)
|
||
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.patch(
|
||
f"/api/v1/calendar/events/{event.id}/",
|
||
{"title": "Обновлённое событие"},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_200_OK
|
||
assert response.data["title"] == "Обновлённое событие"
|
||
|
||
def test_user_cannot_update_without_permission(
|
||
self, api_client, regular_user, global_calendar, admin_user
|
||
):
|
||
"""Пользователь НЕ может обновлять без прав."""
|
||
from calendar_app.models import CalendarEvent
|
||
|
||
# Создаём событие БЕЗ прав у пользователя
|
||
event = CalendarEvent.objects.create(
|
||
calendar=global_calendar,
|
||
title="Событие админа",
|
||
start_date=date(2026, 3, 1),
|
||
all_day=True,
|
||
created_by=admin_user,
|
||
)
|
||
|
||
api_client.force_authenticate(user=regular_user)
|
||
|
||
response = api_client.patch(
|
||
f"/api/v1/calendar/events/{event.id}/",
|
||
{"title": "Попытка обновить"},
|
||
format="json",
|
||
)
|
||
|
||
assert response.status_code == status.HTTP_403_FORBIDDEN
|