diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po index 9850b08b075967a7f0cac12240802bcf3f6bb691..63fd807168c207707ff3312c05422969d69f45e9 100644 --- a/src/backoffice/locale/de/LC_MESSAGES/django.po +++ b/src/backoffice/locale/de/LC_MESSAGES/django.po @@ -1447,13 +1447,38 @@ msgstr "Self-organized Session löschen" msgid "SoS__delete__introduction" msgstr "Hiermit wird diese Self-organized Session gelöscht. Wenn du sie nur unsichtbar machen möchtest gibt es weiter oben die Möglichkeit die Self-organized Session zurückzunehmen!" -msgid "Team__name" -msgstr "Name" +# use translation from core +msgid "Team" +msgstr "" + +msgid "Team__create__title" +msgstr "Neues Team erstellen" + +#, python-format +msgid "Team__edit__title %(form.instance.name)s" +msgstr "Team %(form.instance.name)s bearbeiten" + +msgid "team__edit__metadata" +msgstr "Team-Daten" # Use translation from core msgid "Team__require_staff" msgstr "" +# Use translation from core +msgid "Team__require_staff__help" +msgstr "" + +msgid "Team__change_permission_admin" +msgstr "Du kannst die mit dem Team verknüpften Berechtigungen hier bearbeiten: " + +msgid "Team__edit__submit" +msgstr "Speichern" + +# Use translation from core +msgid "Team__name" +msgstr "" + msgid "Team__member_count" msgstr "Mitgliederanzahl" @@ -1995,6 +2020,14 @@ msgstr "%(project_type)s '%(project)s' erstellt" msgid "Project__updated %(project)s %(project_type)s" msgstr "%(project_type)s '%(project)s' aktualisiert" +#, python-format +msgid "Team__create__success %(name)s" +msgstr "Das Team \"%(name)s\" wurde angelegt!" + +#, python-format +msgid "Team__update__success %(name)s" +msgstr "Das Aktualisieren des Teams \"%(name)s\" war erfolgreich!" + msgid "Lock-gone" msgstr "Sperre bestand nicht mehr." diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po index 7ea574c3f4ac432de02cd461e49f284332519412..c9ad2cd568286e263d29f71c81e4ce67890a8d8d 100644 --- a/src/backoffice/locale/en/LC_MESSAGES/django.po +++ b/src/backoffice/locale/en/LC_MESSAGES/django.po @@ -1452,13 +1452,38 @@ msgstr "Delete self-organized session" msgid "SoS__delete__introduction" msgstr "This removes this self-organized session. If you only want to make it invisible, there is an option above to recall the self-organized session above!" -msgid "Team__name" -msgstr "name" +# use translation from core +msgid "Team" +msgstr "" + +msgid "Team__create__title" +msgstr "Create team" + +#, python-format +msgid "Team__edit__title %(form.instance.name)s" +msgstr "Edit the %(form.instance.name)s team" + +msgid "team__edit__metadata" +msgstr "team data" # Use translation from core msgid "Team__require_staff" msgstr "" +# Use translation from core +msgid "Team__require_staff__help" +msgstr "" + +msgid "Team__change_permission_admin" +msgstr "You are allowed to change the teams permissions at: " + +msgid "Team__edit__submit" +msgstr "Save" + +# Use translation from core +msgid "Team__name" +msgstr "" + msgid "Team__member_count" msgstr "members count" @@ -2000,6 +2025,14 @@ msgstr "%(project_type)s '%(project)s' created" msgid "Project__updated %(project)s %(project_type)s" msgstr "%(project_type)s '%(project)s' updated" +#, python-format +msgid "Team__create__success %(name)s" +msgstr "The team \"%(name)s\" was successfully created." + +#, python-format +msgid "Team__update__success %(name)s" +msgstr "The team \"%(name)s\" was successfully updated." + msgid "Lock-gone" msgstr "Lock was gone already." diff --git a/src/backoffice/templates/backoffice/teams/create_edit.html b/src/backoffice/templates/backoffice/teams/create_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..7d3696ca2bc1f28814a2878e630ebbf339270d60 --- /dev/null +++ b/src/backoffice/templates/backoffice/teams/create_edit.html @@ -0,0 +1,60 @@ +{% extends "backoffice/base.html" %} +{% load django_bootstrap5 %} +{% load i18n %} +{% load static %} +{% load rules %} + +{% block title %} + {% if form.create %} + {% trans "create" %} + {% else %} + {{ form.instance.name }} + {% endif %} + | {% trans "Team" %} | {{ conference.name }} +{% endblock title %} +{% block content %} + {% has_perm 'core.change_permissions_team' request.user team as can_change_permissions %} + <form method="post" enctype="multipart/form-data" id="teamForm"> + {% csrf_token %} + <div class="card border-default"> + <div class="card-header bg-default"> + {% if form.create %} + {% trans "Team__create__title" %} + {% else %} + {% blocktranslate %}Team__edit__title {{ form.instance.name }}{% endblocktranslate %} + {% endif %} + </div> + <div class="card-body"> + <p class="fw-bold border-bottom mb-3">{% trans "team__edit__metadata" %}</p> + <div class="row mb-3"> + <div class="col-md-9">{% bootstrap_field form.name %}</div> + {% if form.require_staff %} + <div class="col-md-3">{% bootstrap_field form.require_staff %}</div> + {% else %} + <div class="col-md-3"> + <label for="require_staff">{% trans "Team__require_staff" %}:</label> + <span id="require_staff">{{ form.require_staff|yesno }}</span> + <div class="form-text">{% trans "Team__require_staff__help" %}</div> + </div> + {% endif %} + </div> + + <div class="row mb-3"> + <div class="col-md-6">{% bootstrap_field form.description_de %}</div> + <div class="col-md-6">{% bootstrap_field form.description_en %}</div> + </div> + {% if not form.create and can_change_permissions %} + <div class="row"> + <p class="col-md-12"> + {% trans "Team__change_permission_admin" %} <a href="{% url "admin:core_team_change" team.id %}">test</a> + </p> + </div> + {% endif %} + </div> + {% trans "Team__edit__submit" as button_text %} + <div class="card-footer"> + {% bootstrap_button button_text button_type="submit" button_class="btn-primary float-end" %} + </div> + </div> + </form> +{% endblock content %} diff --git a/src/backoffice/tests/teams/__init__.py b/src/backoffice/tests/teams/__init__.py index db9ed67307ae25bc739570c69e387d421f85e8df..c1553ae61c8f31f48546957f4513494793239976 100644 --- a/src/backoffice/tests/teams/__init__.py +++ b/src/backoffice/tests/teams/__init__.py @@ -1,3 +1,11 @@ -from backoffice.tests.teams.teams import TeamListViewTestCase +from backoffice.tests.teams.teams import ( + TeamCreateViewTestCase, + TeamListViewTestCase, + TeamUpdateViewTestCase, +) -__all__ = ('TeamListViewTestCase',) +__all__ = ( + 'TeamCreateViewTestCase', + 'TeamListViewTestCase', + 'TeamUpdateViewTestCase', +) diff --git a/src/backoffice/tests/teams/teams.py b/src/backoffice/tests/teams/teams.py index ecdfd789e07baaac3d63e3d6f635ab622f2d8870..844c12a40b92a5fd58346a5f82ac97b5e2dde9c6 100644 --- a/src/backoffice/tests/teams/teams.py +++ b/src/backoffice/tests/teams/teams.py @@ -64,3 +64,92 @@ class TeamListViewTestCase(BackOfficeTestCase): for team in self.teams: self.assertContains(response, team) self.assertNotContains(response, _('Team__create__button')) + + +class TeamCreateViewTestCase(BackOfficeTestCase): + def test_team_create_unauthenicated(self): + activate('en') + response = self.client.get(reverse('backoffice:team-create')) + self.assertRedirects(response, reverse('backoffice:login') + '?next=' + reverse('backoffice:team-create')) + + def test_team_create_admin(self): + self.client.force_login(self.admin) + response = self.client.get(reverse('backoffice:team-create')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'backoffice/teams/create_edit.html') + self.assertContains(response, _('create')) + self.assertContains(response, _('Team__create__title')) + + response = self.client.post(reverse('backoffice:team-create'), data={'name': 'team'}) + self.assertTrue(Team.objects.filter(name='team').exists()) + team = Team.objects.get(name='team') + self.assertRedirects(response, reverse('backoffice:team', kwargs={'uuid': team.uuid})) + + def test_team_create_staff(self): + self.client.force_login(self.staff) + response = self.client.get(reverse('backoffice:team-create')) + self.assertEqual(response.status_code, 403) + + def test_team_create_team_member(self): + self.client.force_login(self.user) + response = self.client.get(reverse('backoffice:team-create')) + self.assertEqual(response.status_code, 403) + + +class TeamUpdateViewTestCase(BackOfficeTestCase): + def setUp(self): + super().setUp() + self.user_2 = PlatformUser.objects.create_user( + username='user2', + ) + self.user_2_cm = ConferenceMember.objects.create(conference=self.conf, user=self.user_2) + self.team = Team.objects.create( + name='team', + conference=self.conf, + ) + self.team_member = TeamMember.objects.create(team=self.team, user=self.admin) + self.team_member2 = TeamMember.objects.create(team=self.team, user=self.staff, can_manage=True) + self.team_member3 = TeamMember.objects.create(team=self.team, user=self.user) + + def test_team_update_unauthenicated(self): + activate('en') + response = self.client.get(reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid})) + self.assertRedirects(response, reverse('backoffice:login') + '?next=' + reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid})) + + def test_team_edit_admin(self): + self.client.force_login(self.admin) + response = self.client.get(reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'backoffice/teams/create_edit.html') + self.assertNotContains(response, _('create')) + # TODO: Add test for title + self.assertContains(response, _('Team__edit__submit')) + + response = self.client.post(reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid}), data={'name': 'team'}) + self.assertTrue(Team.objects.filter(name='team').exists()) + team = Team.objects.get(name='team') + self.assertRedirects(response, reverse('backoffice:team', kwargs={'uuid': team.uuid})) + + def test_team_edit_staff(self): + self.client.force_login(self.staff) + response = self.client.get(reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'backoffice/teams/create_edit.html') + self.assertNotContains(response, _('create')) + # TODO: Add test for title + self.assertContains(response, _('Team__edit__submit')) + + response = self.client.post( + reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid}), + data={'name': 'team', 'description_de': 'description_de', 'description_en': 'description_en'}, + ) + self.assertTrue(Team.objects.filter(name='team').exists()) + self.assertRedirects(response, reverse('backoffice:team', kwargs={'uuid': self.team.uuid})) + self.team.refresh_from_db() + self.assertEqual(self.team.description_de, 'description_de') + self.assertEqual(self.team.description_en, 'description_en') + + def test_team_edit_team_member(self): + self.client.force_login(self.user) + response = self.client.get(reverse('backoffice:team-edit', kwargs={'uuid': self.team.uuid})) + self.assertEqual(response.status_code, 403) diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py index cf888bac6680640782dfc5114416ef441b414780..dd93c12017f3e956b3f66a8e4d92919e930eeae9 100644 --- a/src/backoffice/urls.py +++ b/src/backoffice/urls.py @@ -154,6 +154,8 @@ urlpatterns = [ path('sos/new', RedirectView.as_view(pattern_name='backoffice:sos-create')), path('sos/<uuid:pk>/', RedirectView.as_view(pattern_name='backoffice:sos-edit')), path('teams', teams.TeamListView.as_view(), name='teams'), + path('team/create', teams.TeamCreateView.as_view(), name='team-create'), + path('team/<uuid:uuid>/edit', teams.TeamUpdateView.as_view(), name='team-edit'), path('vouchers', vouchers.VouchersView.as_view(), name='vouchers'), path('_boom', misc.BoomView.as_view()), ] diff --git a/src/backoffice/views/teams/__init__.py b/src/backoffice/views/teams/__init__.py index a5dc575b1ec94fa9a4347f50a0dc5c6e30c11ecd..2f56a60e9a184a5b5b53cfa0a9a450a138cc2866 100644 --- a/src/backoffice/views/teams/__init__.py +++ b/src/backoffice/views/teams/__init__.py @@ -1,7 +1,11 @@ from backoffice.views.teams.teams import ( + TeamCreateView, TeamListView, + TeamUpdateView, ) __all__ = [ + 'TeamCreateView', 'TeamListView', + 'TeamUpdateView', ] diff --git a/src/backoffice/views/teams/teams.py b/src/backoffice/views/teams/teams.py index ffcfe4ad2f821391a6ef2ad8f16d7e850fbb4a5e..4c2a0eee2895b07c2d96300ac4f76b2f1d3ee8bc 100644 --- a/src/backoffice/views/teams/teams.py +++ b/src/backoffice/views/teams/teams.py @@ -5,11 +5,15 @@ from django.db.models import BooleanField, Case, Count, When from django.db.models.query import Q, QuerySet from django.urls import reverse from django.utils.translation import gettext as _ -from django.views.generic import ListView +from django.views.generic import FormView, ListView +from django.views.generic.edit import CreateView, UpdateView +from rules.contrib.views import AutoPermissionRequiredMixin +from core.forms import TeamForm from core.models import ConferenceMember, Team +from core.views.mixins import FormMesssageMixin -from backoffice.views.mixins import ConferenceRuleLoginRequiredMixin, guess_active_sidebar_item +from backoffice.views.mixins import ConferenceRuleLoginRequiredMixin, SingleUUIDObjectMixin, guess_active_sidebar_item class TeamNavContextMixin(ConferenceRuleLoginRequiredMixin): @@ -85,3 +89,28 @@ class TeamListView(TeamNavContextMixin, ListView): ).annotate( can_manage=Case(When(self_manage_count__gt=0, then=True), default=False, output_field=BooleanField()), ) + + +class TeamFormMixin(AutoPermissionRequiredMixin, TeamNavContextMixin, FormMesssageMixin, FormView): + model = Team + object_name = 'team' + form_class = TeamForm + template_name = 'backoffice/teams/create_edit.html' + + def get_success_url(self): + return reverse('backoffice:team', kwargs={'uuid': self.object.uuid}) + + def get_form_kwargs(self) -> dict[str, Any]: + return { + **super().get_form_kwargs(), + 'super_user': self.request.user.is_superuser, + 'conference': self.conference, + } + + +class TeamCreateView(TeamFormMixin, CreateView): + success_message = _('Team__create__success %(name)s') + + +class TeamUpdateView(SingleUUIDObjectMixin, TeamFormMixin, UpdateView): + success_message = _('Team__update__success %(name)s') diff --git a/src/hub/settings/test.py b/src/hub/settings/test.py index f2333e6282e79745e14c91decd10497ddc97672d..8fde833fecf917dd67d1df5c5976a16a63ef3a22 100644 --- a/src/hub/settings/test.py +++ b/src/hub/settings/test.py @@ -1,7 +1,7 @@ import os os.environ.setdefault('DJANGO_SECRET_KEY', 'Testing101') - +os.environ.setdefault('SERVE_ADMIN', 'yes') from .default import * # noqa: F401, E402, F403 # pylint: disable=wildcard-import,unused-wildcard-import INTEGRATIONS_BBB = True