Skip to content

Commit 015f8b1

Browse files
committed
Implement update team endpoint
* Implement and endpoint in cyberstorm api for updating teams * Support only updating donation_link for now * Implement tests Refs TS-2314
1 parent afbf03e commit 015f8b1

File tree

6 files changed

+175
-0
lines changed

6 files changed

+175
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
CyberstormTeamAddMemberResponseSerializer,
1212
CyberstormTeamMemberSerializer,
1313
CyberstormTeamSerializer,
14+
CyberstormTeamUpdateSerializer,
1415
)
1516

1617
__all__ = [
@@ -25,4 +26,5 @@
2526
"CyberstormTeamMemberSerializer",
2627
"CyberstormTeamSerializer",
2728
"PackagePermissionsSerializer",
29+
"CyberstormTeamUpdateSerializer",
2830
]

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Optional
22

3+
from django.core.validators import URLValidator
34
from rest_framework import serializers
45
from rest_framework.exceptions import ValidationError
56

@@ -67,3 +68,9 @@ def validate(self, attrs):
6768
if getattr(user, "service_account", None) is not None:
6869
raise ValidationError("Service accounts cannot create teams")
6970
return attrs
71+
72+
73+
class CyberstormTeamUpdateSerializer(serializers.Serializer):
74+
donation_link = serializers.CharField(
75+
max_length=1024, validators=[URLValidator(["https"])]
76+
)

django/thunderstore/api/cyberstorm/tests/test_team.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,131 @@ def test_team_member_add_api_view__when_adding_a_member__fails_because_user_is_n
318318
.count()
319319
== 0
320320
)
321+
322+
323+
@pytest.mark.django_db
324+
def test_team_update__donation_link__succeeds(
325+
api_client: APIClient,
326+
user: UserType,
327+
team: Team,
328+
):
329+
TeamMemberFactory(team=team, user=user, role="owner")
330+
api_client.force_authenticate(user)
331+
332+
new_donation_link = "https://example.com"
333+
334+
response = api_client.patch(
335+
f"/api/cyberstorm/team/{team.name}/update/",
336+
json.dumps({"donation_link": new_donation_link}),
337+
content_type="application/json",
338+
)
339+
340+
assert response.status_code == 200
341+
response_json = response.json()
342+
assert response_json["donation_link"] == new_donation_link
343+
assert Team.objects.get(pk=team.pk).donation_link == new_donation_link
344+
345+
346+
@pytest.mark.django_db
347+
def test_team_update__donation_link__fails_because_user_is_not_authenticated(
348+
api_client: APIClient,
349+
team: Team,
350+
):
351+
new_donation_link = "https://example.com"
352+
353+
response = api_client.patch(
354+
f"/api/cyberstorm/team/{team.name}/update/",
355+
json.dumps({"donation_link": new_donation_link}),
356+
content_type="application/json",
357+
)
358+
359+
assert response.status_code == 401
360+
response_json = response.json()
361+
assert response_json["detail"] == "Authentication credentials were not provided."
362+
assert Team.objects.get(pk=team.pk).donation_link is None
363+
364+
365+
@pytest.mark.django_db
366+
def test_team_update__donation_link__fails_validation(
367+
api_client: APIClient,
368+
user: UserType,
369+
team: Team,
370+
):
371+
TeamMemberFactory(team=team, user=user, role="owner")
372+
api_client.force_authenticate(user)
373+
374+
new_bad_donation_link = "example.com"
375+
376+
response = api_client.patch(
377+
f"/api/cyberstorm/team/{team.name}/update/",
378+
json.dumps({"donation_link": new_bad_donation_link}),
379+
content_type="application/json",
380+
)
381+
382+
assert response.status_code == 400
383+
response_json = response.json()
384+
assert "Enter a valid URL." in response_json["donation_link"]
385+
386+
387+
@pytest.mark.django_db
388+
def test_team_update__donation_link__fails_because_user_is_not_owner(
389+
api_client: APIClient,
390+
user: UserType,
391+
team: Team,
392+
):
393+
TeamMemberFactory(team=team, user=user, role="member")
394+
api_client.force_authenticate(user)
395+
396+
new_donation_link = "https://example.com"
397+
398+
response = api_client.patch(
399+
f"/api/cyberstorm/team/{team.name}/update/",
400+
json.dumps({"donation_link": new_donation_link}),
401+
content_type="application/json",
402+
)
403+
404+
assert response.status_code == 403
405+
response_json = response.json()
406+
assert response_json["detail"] == "Must be an owner to edit team info"
407+
assert Team.objects.get(pk=team.pk).donation_link is None
408+
409+
410+
@pytest.mark.django_db
411+
def test_team_update__donation_link__fails_because_team_doesnt_exist(
412+
api_client: APIClient,
413+
user: UserType,
414+
):
415+
api_client.force_authenticate(user)
416+
417+
new_donation_link = "https://example.com"
418+
419+
response = api_client.patch(
420+
"/api/cyberstorm/team/FakeTeam/update/",
421+
json.dumps({"donation_link": new_donation_link}),
422+
content_type="application/json",
423+
)
424+
425+
assert response.status_code == 404
426+
assert response.json()["detail"] == "Not found."
427+
428+
429+
@pytest.mark.django_db
430+
def test_team_update__donation_link__fails_because_user_not_team_member(
431+
api_client: APIClient,
432+
user: UserType,
433+
team: Team,
434+
):
435+
api_client.force_authenticate(user)
436+
437+
new_donation_link = "https://example.com"
438+
439+
response = api_client.patch(
440+
f"/api/cyberstorm/team/{team.name}/update/",
441+
json.dumps({"donation_link": new_donation_link}),
442+
content_type="application/json",
443+
)
444+
445+
expected_response = {"detail": "You do not have permission to access this team."}
446+
447+
assert response.status_code == 403
448+
assert response.json() == expected_response

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
TeamMemberAddAPIView,
2525
TeamMemberListAPIView,
2626
TeamServiceAccountListAPIView,
27+
UpdateTeamAPIView,
2728
)
2829

2930
__all__ = [
@@ -49,4 +50,5 @@
4950
"UpdatePackageListingCategoriesAPIView",
5051
"RejectPackageListingAPIView",
5152
"ApprovePackageListingAPIView",
53+
"UpdateTeamAPIView",
5254
]

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
DestroyAPIView,
77
ListAPIView,
88
RetrieveAPIView,
9+
UpdateAPIView,
910
get_object_or_404,
1011
)
1112
from rest_framework.permissions import IsAuthenticated
@@ -21,6 +22,7 @@
2122
CyberstormTeamAddMemberResponseSerializer,
2223
CyberstormTeamMemberSerializer,
2324
CyberstormTeamSerializer,
25+
CyberstormTeamUpdateSerializer,
2426
)
2527
from thunderstore.api.ordering import StrictOrderingFilter
2628
from thunderstore.api.utils import (
@@ -155,3 +157,31 @@ def check_permissions(self, request):
155157
)
156158
def delete(self, request, *args, **kwargs):
157159
return super().delete(request, *args, **kwargs)
160+
161+
162+
class UpdateTeamAPIView(TeamPermissionsMixin, UpdateAPIView):
163+
queryset = Team.objects.filter(is_active=True)
164+
lookup_url_kwarg = "team_name"
165+
lookup_field = "name"
166+
serializer_class = CyberstormTeamUpdateSerializer
167+
http_method_names = ["patch"]
168+
169+
def check_permissions(self, request):
170+
super().check_permissions(request)
171+
team = self.get_object()
172+
team.ensure_user_can_edit_info(self.request.user)
173+
174+
def perform_update(self, serializer):
175+
instance = serializer.instance
176+
instance.donation_link = serializer.validated_data["donation_link"]
177+
instance.save()
178+
179+
@conditional_swagger_auto_schema(
180+
operation_id="cyberstorm.team.update",
181+
tags=["cyberstorm"],
182+
request_body=CyberstormTeamUpdateSerializer,
183+
responses={status.HTTP_200_OK: serializer_class},
184+
)
185+
def patch(self, request, *args, **kwargs):
186+
kwargs["partial"] = True
187+
return super().update(request, *args, **kwargs)

django/thunderstore/api/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
TeamMemberListAPIView,
2424
TeamServiceAccountListAPIView,
2525
UpdatePackageListingCategoriesAPIView,
26+
UpdateTeamAPIView,
2627
)
2728

2829
cyberstorm_urls = [
@@ -126,6 +127,11 @@
126127
TeamAPIView.as_view(),
127128
name="cyberstorm.team",
128129
),
130+
path(
131+
"team/<str:team_name>/update/",
132+
UpdateTeamAPIView.as_view(),
133+
name="cyberstorm.team.update",
134+
),
129135
path(
130136
"team/<str:team_name>/disband/",
131137
DisbandTeamAPIView.as_view(),

0 commit comments

Comments
 (0)