Skip to content

Commit 833d2ed

Browse files
committed
Use service layer functions in form views
Utilize create_team and disband_team in form views. Update forms to use the service layer functions in the form's save() functions and update the view logic accordingly. Update the form for creating teams to be a Form instead of ModelForm in order to simplify the validations since validation happens in the service layer function and also in the model. Update all the tests accordingly to these changes. Add more tests to the service layer functions. Refs. TS-2426
1 parent bed87e9 commit 833d2ed

File tree

5 files changed

+62
-44
lines changed

5 files changed

+62
-44
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ def create_team(agent: UserType, team_name: str) -> Team:
2020
raise PermissionValidationError("Must be authenticated to create teams")
2121
if getattr(agent, "service_account", None) is not None:
2222
raise PermissionValidationError("Service accounts cannot create teams")
23-
if Team.objects.filter(name=team_name).exists():
23+
if Team.objects.filter(name__iexact=team_name).exists():
2424
raise ValidationError("A team with the provided name already exists")
25-
if Namespace.objects.filter(name=team_name).exists():
25+
if Namespace.objects.filter(name__iexact=team_name).exists():
2626
raise ValidationError("A namespace with the provided name already exists")
2727

2828
team = Team.objects.create(name=team_name)

django/thunderstore/api/cyberstorm/tests/services/test_team_services.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,23 @@ def test_create_team_user_not_active(user):
111111
error_msg = "Must be authenticated to create teams"
112112
with pytest.raises(ValidationError, match=error_msg):
113113
team_services.create_team(agent=user, team_name="new_team")
114+
115+
116+
@pytest.mark.django_db
117+
@pytest.mark.parametrize(
118+
("name1", "name2", "should_fail"),
119+
(
120+
("Team", "team", True),
121+
("Team", "t_eam", False),
122+
("team", "teaM", True),
123+
("team", "team", True),
124+
),
125+
)
126+
def test_create_team_name_conflict(user, name1: str, name2: str, should_fail: bool):
127+
Team.create(name=name1)
128+
if should_fail:
129+
with pytest.raises(ValidationError):
130+
team_services.create_team(agent=user, team_name=name2)
131+
else:
132+
team = team_services.create_team(agent=user, team_name=name2)
133+
assert team.name == name2

django/thunderstore/repository/forms/team.py

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,36 @@
44
from django.contrib.auth import get_user_model
55
from django.core.exceptions import ObjectDoesNotExist, ValidationError
66

7-
from thunderstore.core.exceptions import PermissionValidationError
7+
from thunderstore.api.cyberstorm.services.team import create_team, disband_team
88
from thunderstore.core.types import UserType
9-
from thunderstore.repository.models import (
10-
Namespace,
11-
Team,
12-
TeamMember,
13-
TeamMemberRole,
14-
transaction,
15-
)
9+
from thunderstore.repository.models import Team, TeamMember, TeamMemberRole, transaction
1610
from thunderstore.repository.validators import PackageReferenceComponentValidator
1711

1812
User = get_user_model()
1913

2014

21-
class CreateTeamForm(forms.ModelForm):
15+
class CreateTeamForm(forms.Form):
2216
name = forms.CharField(
2317
validators=[PackageReferenceComponentValidator("Author name")]
2418
)
2519

26-
class Meta:
27-
model = Team
28-
fields = ["name"]
29-
30-
def __init__(self, user: UserType, *args, **kwargs):
20+
def __init__(self, user: UserType, instance: Team = None, *args, **kwargs):
3121
super().__init__(*args, **kwargs)
3222
self.user = user
33-
34-
def clean_name(self):
35-
name = self.cleaned_data["name"]
36-
if Team.objects.filter(name__iexact=name.lower()).exists():
37-
raise ValidationError(f"A team with the provided name already exists")
38-
if Namespace.objects.filter(name__iexact=name.lower()).exists():
39-
raise ValidationError("A namespace with the provided name already exists")
40-
return name
41-
42-
def clean(self):
43-
if not self.user or not self.user.is_authenticated or not self.user.is_active:
44-
raise PermissionValidationError("Must be authenticated to create teams")
45-
if getattr(self.user, "service_account", None) is not None:
46-
raise PermissionValidationError("Service accounts cannot create teams")
47-
return super().clean()
23+
self.instance = instance
4824

4925
@transaction.atomic
5026
def save(self, *args, **kwargs) -> Team:
51-
instance = super().save()
52-
instance.add_member(user=self.user, role=TeamMemberRole.owner)
53-
return instance
27+
if self.errors:
28+
raise ValueError("Form has errors")
29+
30+
try:
31+
team_name = self.cleaned_data["name"]
32+
self.instance = create_team(agent=self.user, team_name=team_name)
33+
except ValidationError as e:
34+
self.add_error(None, e)
35+
36+
return self.instance
5437

5538

5639
class AddTeamMemberForm(forms.ModelForm):
@@ -152,21 +135,24 @@ def __init__(self, user: UserType, *args, **kwargs):
152135
self.user = user
153136

154137
def clean_verification(self):
155-
data = self.cleaned_data["verification"]
156-
if data != self.instance.name:
138+
verification = self.cleaned_data["verification"]
139+
if verification != self.instance.name:
157140
raise forms.ValidationError("Invalid verification")
158-
return data
141+
return verification
159142

160143
def clean(self):
161144
if not self.instance.pk:
162145
raise ValidationError("Missing team instance")
163-
self.instance.ensure_user_can_disband(self.user)
164146
return super().clean()
165147

166-
@transaction.atomic
167148
def save(self, **kwargs):
168-
self.instance.ensure_user_can_disband(self.user)
169-
self.instance.delete()
149+
if self.errors:
150+
raise ValueError("Form has errors")
151+
152+
try:
153+
disband_team(agent=self.user, team=self.instance)
154+
except ValidationError as e:
155+
self.add_error(None, e)
170156

171157

172158
class DonationLinkTeamForm(forms.ModelForm):

django/thunderstore/repository/tests/test_team_forms.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_form_create_team_valid_data(user_type: str) -> None:
3939
data={"name": "TeamName"},
4040
)
4141
if expected_error:
42+
form.save()
4243
assert form.is_valid() is False
4344
assert expected_error in str(repr(form.errors))
4445
else:
@@ -70,6 +71,7 @@ def test_form_create_team_team_name_conflict(
7071
data={"name": name2},
7172
)
7273
if should_fail:
74+
form.save()
7375
assert form.is_valid() is False
7476
assert "A team with the provided name already exists" in str(repr(form.errors))
7577
else:
@@ -102,6 +104,8 @@ def test_form_create_team_team_name_validation(
102104
data={"name": name},
103105
)
104106
if should_fail:
107+
with pytest.raises(ValueError):
108+
form.save()
105109
assert form.is_valid() is False
106110
assert error in str(repr(form.errors))
107111
else:
@@ -452,6 +456,7 @@ def test_form_disband_team_form(
452456
assert form.save() is None
453457
assert Team.objects.filter(pk=team.pk).exists() is False
454458
else:
459+
form.save()
455460
assert form.is_valid() is False
456461
assert form.errors
457462

@@ -470,6 +475,8 @@ def test_form_disband_team_form_invalid_verification(
470475
instance=team,
471476
data={"verification": f"invalid-{team.name}"},
472477
)
478+
with pytest.raises(ValueError):
479+
form.save()
473480
assert form.is_valid() is False
474481
assert "Invalid verification" in str(repr(form.errors))
475482

@@ -488,6 +495,7 @@ def test_form_disband_team_form_packages_exist(
488495
instance=team,
489496
data={"verification": team.name},
490497
)
498+
form.save()
491499
assert form.is_valid() is False
492500
assert "Unable to disband teams with packages" in str(repr(form.errors))
493501

django/thunderstore/repository/views/team_settings.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
CreateServiceAccountForm,
1717
DeleteServiceAccountForm,
1818
)
19+
from thunderstore.api.cyberstorm.services import team as team_service
1920
from thunderstore.core.mixins import RequireAuthenticationMixin
2021
from thunderstore.core.utils import capture_exception
2122
from thunderstore.frontend.views import SettingsViewMixin
@@ -26,7 +27,6 @@
2627
DonationLinkTeamForm,
2728
EditTeamMemberForm,
2829
RemoveTeamMemberForm,
29-
TeamMemberRole,
3030
)
3131
from thunderstore.repository.models import Team, TeamMember, reverse
3232

@@ -152,8 +152,10 @@ def get_context_data(self, **kwargs):
152152

153153
@transaction.atomic
154154
def form_valid(self, form):
155-
instance = form.save()
156-
return redirect(instance.settings_url)
155+
self.object = form.save()
156+
if form.errors:
157+
return self.form_invalid(form)
158+
return redirect(reverse("settings.teams"))
157159

158160

159161
class SettingsTeamDisbandView(TeamDetailView, UserFormKwargs, FormView):
@@ -175,6 +177,8 @@ def get_form_kwargs(self):
175177
@transaction.atomic
176178
def form_valid(self, form):
177179
form.save()
180+
if form.errors:
181+
return self.form_invalid(form)
178182
return redirect(reverse("settings.teams"))
179183

180184

0 commit comments

Comments
 (0)