Skip to content

Commit e1d1d01

Browse files
committed
Исправлены chat permissions для swagger schema
1 parent b2ff8f6 commit e1d1d01

File tree

2 files changed

+111
-11
lines changed

2 files changed

+111
-11
lines changed

chats/permissions.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,43 @@
66
User = get_user_model()
77

88

9+
def get_lookup_kwarg(request, view, *names):
10+
view_kwargs = getattr(view, "kwargs", {}) or {}
11+
parser_kwargs = (getattr(request, "parser_context", None) or {}).get("kwargs", {})
12+
13+
for name in names:
14+
if name in view_kwargs:
15+
return view_kwargs[name]
16+
if name in parser_kwargs:
17+
return parser_kwargs[name]
18+
return None
19+
20+
21+
def is_project_member(user, project) -> bool:
22+
if not getattr(user, "is_authenticated", False):
23+
return False
24+
25+
if project.leader_id == user.id:
26+
return True
27+
28+
return project.collaborator_set.filter(user_id=user.id).exists()
29+
30+
931
class IsProjectChatMember(BasePermission):
1032
def has_permission(self, request, view) -> bool:
33+
project_id = get_lookup_kwarg(request, view, "id", "pk")
34+
if project_id is None:
35+
return True
36+
1137
try:
12-
project = Project.objects.get(pk=view.kwargs["id"])
13-
except Project.DoesNotExist:
38+
project = Project.objects.only("id", "leader_id").get(pk=project_id)
39+
except (Project.DoesNotExist, TypeError, ValueError):
1440
return False
15-
if request.user in project.get_collaborators_user_list():
16-
return True
17-
return True
41+
42+
return is_project_member(request.user, project)
1843

1944
def has_object_permission(self, request, view, obj):
20-
if request.user in obj.project.get_collaborators_user_list():
21-
return True
22-
return False
45+
return is_project_member(request.user, obj.project)
2346

2447

2548
class IsChatMember(BasePermission):
@@ -28,8 +51,12 @@ class IsChatMember(BasePermission):
2851
"""
2952

3053
def has_permission(self, request, view) -> bool:
31-
kwargs = request.parser_context.get("kwargs")
54+
chat_id = get_lookup_kwarg(request, view, "id")
55+
if chat_id is None:
56+
return True
3257

33-
chat_id: str = kwargs["id"]
58+
user_id = getattr(request.user, "id", None)
59+
if user_id is None:
60+
return False
3461

35-
return str(request.user.id) in chat_id.split("_")
62+
return str(user_id) in str(chat_id).split("_")

chats/tests/test_permissions.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from django.contrib.auth import get_user_model
2+
from django.test import TestCase, override_settings
3+
from rest_framework.test import APIRequestFactory, force_authenticate
4+
5+
from chats.models import ProjectChat
6+
from chats.tests.constants import TEST_USER1, TEST_USER2, TEST_USER3
7+
from chats.views import ProjectChatDetail
8+
from projects.models import Collaborator, Project
9+
10+
11+
@override_settings(ALLOWED_HOSTS=["testserver", "dev.procollab.ru", "127.0.0.1"])
12+
class ChatPermissionsTests(TestCase):
13+
def setUp(self):
14+
super().setUp()
15+
self.factory = APIRequestFactory()
16+
self.leader = get_user_model().objects.create(**TEST_USER1)
17+
self.collaborator = get_user_model().objects.create(**TEST_USER2)
18+
self.outsider = get_user_model().objects.create(**TEST_USER3)
19+
self.project = Project.objects.create(leader=self.leader)
20+
self.chat = ProjectChat.objects.create(project=self.project)
21+
Collaborator.objects.create(
22+
user=self.collaborator,
23+
project=self.project,
24+
role="User",
25+
)
26+
27+
self.staff = get_user_model().objects.create(
28+
email="swagger-staff@test.test",
29+
password="very_strong_password",
30+
first_name="Swagger",
31+
last_name="Staff",
32+
birthday="2000-01-01",
33+
is_staff=True,
34+
is_superuser=True,
35+
is_active=True,
36+
)
37+
self.staff.set_password("very_strong_password")
38+
self.staff.save()
39+
40+
def test_swagger_schema_is_available_for_staff(self):
41+
self.client.force_login(self.staff)
42+
43+
response = self.client.get(
44+
"/swagger/?format=openapi",
45+
secure=True,
46+
HTTP_HOST="dev.procollab.ru",
47+
)
48+
49+
self.assertEqual(response.status_code, 200)
50+
51+
def test_project_chat_detail_is_available_for_leader(self):
52+
request = self.factory.get(f"/chats/projects/{self.chat.id}/")
53+
force_authenticate(request, user=self.leader)
54+
55+
response = ProjectChatDetail.as_view()(request, pk=self.chat.id)
56+
57+
self.assertEqual(response.status_code, 200)
58+
59+
def test_project_chat_detail_is_available_for_collaborator(self):
60+
request = self.factory.get(f"/chats/projects/{self.chat.id}/")
61+
force_authenticate(request, user=self.collaborator)
62+
63+
response = ProjectChatDetail.as_view()(request, pk=self.chat.id)
64+
65+
self.assertEqual(response.status_code, 200)
66+
67+
def test_project_chat_detail_is_forbidden_for_outsider(self):
68+
request = self.factory.get(f"/chats/projects/{self.chat.id}/")
69+
force_authenticate(request, user=self.outsider)
70+
71+
response = ProjectChatDetail.as_view()(request, pk=self.chat.id)
72+
73+
self.assertEqual(response.status_code, 403)

0 commit comments

Comments
 (0)