Skip to content

Commit 0c7eaad

Browse files
committed
Implement delete team member endpoint
* Implement endpoint in cyberstorm api for deleting team members * Implement tests Refs. TS-2315
1 parent afbf03e commit 0c7eaad

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import pytest
2+
from rest_framework.test import APIClient
3+
4+
from thunderstore.core.types import UserType
5+
from thunderstore.repository.factories import TeamFactory, TeamMemberFactory
6+
from thunderstore.repository.models.team import Team
7+
8+
9+
def get_remove_team_member_url(team_name: str, team_member: str) -> str:
10+
return f"/api/cyberstorm/team/{team_name}/member/{team_member}/remove/"
11+
12+
13+
def make_request(api_client: APIClient, team_name: str, team_member: str):
14+
return api_client.delete(
15+
get_remove_team_member_url(team_name, team_member),
16+
content_type="application/json",
17+
)
18+
19+
20+
@pytest.mark.django_db
21+
def test_remove_team_member_success(api_client: APIClient, user: UserType, team: Team):
22+
TeamMemberFactory(team=team, user=user, role="owner")
23+
api_client.force_authenticate(user)
24+
25+
just_a_member = TeamMemberFactory(team=team, role="member")
26+
response = make_request(api_client, team.name, just_a_member.user.username)
27+
28+
assert response.status_code == 204
29+
30+
31+
@pytest.mark.django_db
32+
def test_remove_member_fail_because_user_is_not_a_member_in_team(
33+
api_client: APIClient,
34+
user: UserType,
35+
team: Team,
36+
):
37+
TeamMemberFactory(team=team, user=user, role="owner")
38+
api_client.force_authenticate(user)
39+
40+
another_team = TeamFactory()
41+
member_in_another_team = TeamMemberFactory(team=another_team, role="owner")
42+
43+
response = make_request(api_client, team.name, member_in_another_team.user.username)
44+
45+
assert response.status_code == 404
46+
assert response.json() == {"detail": "Not found."}
47+
48+
49+
@pytest.mark.django_db
50+
def test_remove__fails_because_team_does_not_exist(
51+
api_client: APIClient,
52+
user: UserType,
53+
):
54+
api_client.force_authenticate(user)
55+
56+
response = make_request(api_client, "nonexistent", user.username)
57+
58+
assert response.status_code == 404
59+
assert response.json() == {"detail": "Not found."}
60+
61+
62+
@pytest.mark.django_db
63+
def test_remove_fail_because_user_is_not_authenticated(
64+
api_client: APIClient,
65+
user: UserType,
66+
team: Team,
67+
):
68+
TeamMemberFactory(team=team, user=user, role="owner")
69+
just_a_member = TeamMemberFactory(team=team, role="member")
70+
71+
response = make_request(api_client, team.name, just_a_member.user.username)
72+
expected_response = {"detail": "Authentication credentials were not provided."}
73+
74+
assert response.status_code == 401
75+
assert response.json() == expected_response
76+
77+
78+
@pytest.mark.django_db
79+
def test_remove_fail_no_permission_to_access_team(
80+
api_client: APIClient, user: UserType, team: Team
81+
):
82+
api_client.force_authenticate(user)
83+
owner = TeamMemberFactory(team=team, role="owner")
84+
85+
response = make_request(api_client, team.name, owner.user.username)
86+
expected_response = {"detail": "You do not have permission to access this team."}
87+
88+
assert response.status_code == 403
89+
assert response.json() == expected_response
90+
91+
92+
@pytest.mark.django_db
93+
def test_remove_fail_because_last_owner(
94+
api_client: APIClient, user: UserType, team: Team
95+
):
96+
TeamMemberFactory(team=team, user=user, role="owner")
97+
api_client.force_authenticate(user)
98+
99+
response = make_request(api_client, team.name, user.username)
100+
expected_response = {"non_field_errors": ["Cannot remove last owner from team"]}
101+
102+
assert response.status_code == 400
103+
assert response.json() == expected_response

django/thunderstore/api/cyberstorm/views/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .package_version_list import PackageVersionListAPIView
2020
from .team import (
2121
DisbandTeamAPIView,
22+
RemoveTeamMemberAPIView,
2223
TeamAPIView,
2324
TeamCreateAPIView,
2425
TeamMemberAddAPIView,
@@ -49,4 +50,5 @@
4950
"UpdatePackageListingCategoriesAPIView",
5051
"RejectPackageListingAPIView",
5152
"ApprovePackageListingAPIView",
53+
"RemoveTeamMemberAPIView",
5254
]

django/thunderstore/api/cyberstorm/views/team.py

+30
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,33 @@ def check_permissions(self, request):
155155
)
156156
def delete(self, request, *args, **kwargs):
157157
return super().delete(request, *args, **kwargs)
158+
159+
160+
class RemoveTeamMemberAPIView(TeamPermissionsMixin, DestroyAPIView):
161+
queryset = TeamMember.objects.real_users()
162+
163+
def check_permissions(self, request):
164+
super().check_permissions(request)
165+
team_member = self.get_object()
166+
167+
if team_member.user != request.user:
168+
team_member.team.ensure_user_can_manage_members(request.user)
169+
team_member.team.ensure_member_can_be_removed(team_member)
170+
171+
def get_object(self):
172+
team_member = self.kwargs.get("team_member")
173+
team_name = self.kwargs.get("team_name")
174+
175+
return get_object_or_404(
176+
self.queryset,
177+
team__name=team_name,
178+
user__username=team_member,
179+
)
180+
181+
@conditional_swagger_auto_schema(
182+
operation_id="cyberstorm.team.member.remove",
183+
tags=["cyberstorm"],
184+
responses={status.HTTP_204_NO_CONTENT: ""},
185+
)
186+
def delete(self, request, *args, **kwargs):
187+
return super().delete(request, *args, **kwargs)

django/thunderstore/api/urls.py

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
PackageVersionReadmeAPIView,
1818
RatePackageAPIView,
1919
RejectPackageListingAPIView,
20+
RemoveTeamMemberAPIView,
2021
TeamAPIView,
2122
TeamCreateAPIView,
2223
TeamMemberAddAPIView,
@@ -141,6 +142,11 @@
141142
TeamMemberAddAPIView.as_view(),
142143
name="cyberstorm.team.member.add",
143144
),
145+
path(
146+
"team/<str:team_name>/member/<str:team_member>/remove/",
147+
RemoveTeamMemberAPIView.as_view(),
148+
name="cyberstorm.team.member.remove",
149+
),
144150
path(
145151
"team/<str:team_id>/service-account/",
146152
TeamServiceAccountListAPIView.as_view(),

0 commit comments

Comments
 (0)