mirror of
https://github.com/ae-utbm/sith.git
synced 2026-04-16 16:28:24 +00:00
feat: page to create club roles
This commit is contained in:
@@ -321,9 +321,6 @@ class ClubRoleForm(forms.ModelForm):
|
|||||||
"is_active": forms.CheckboxInput(attrs={"class": "switch"}),
|
"is_active": forms.CheckboxInput(attrs={"class": "switch"}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, label_suffix="", **kwargs):
|
|
||||||
super().__init__(*args, label_suffix=label_suffix, **kwargs)
|
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
cleaned_data = super().clean()
|
||||||
if "ORDER" in cleaned_data:
|
if "ORDER" in cleaned_data:
|
||||||
@@ -331,6 +328,31 @@ class ClubRoleForm(forms.ModelForm):
|
|||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class ClubRoleCreateForm(forms.ModelForm):
|
||||||
|
"""Form to create a club role.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
For UX purposes, users are not meant to fill `is_presidency`
|
||||||
|
and `is_board`, so those values are required by the form constructor
|
||||||
|
in order to initialize the instance properly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
error_css_class = "error"
|
||||||
|
required_css_class = "required"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ClubRole
|
||||||
|
fields = ["name", "description"]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, *args, club: Club, is_presidency: bool, is_board: bool, **kwargs
|
||||||
|
):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.instance.club = club
|
||||||
|
self.instance.is_presidency = is_presidency
|
||||||
|
self.instance.is_board = is_board
|
||||||
|
|
||||||
|
|
||||||
class ClubRoleBaseFormSet(forms.BaseInlineFormSet):
|
class ClubRoleBaseFormSet(forms.BaseInlineFormSet):
|
||||||
ordering_widget = forms.HiddenInput()
|
ordering_widget = forms.HiddenInput()
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,14 @@
|
|||||||
{{ form.management_form }}
|
{{ form.management_form }}
|
||||||
{{ form.non_form_errors() }}
|
{{ form.non_form_errors() }}
|
||||||
<h3>{% trans %}Presidency{% endtrans %}</h3>
|
<h3>{% trans %}Presidency{% endtrans %}</h3>
|
||||||
<div x-sort="reorder($item, { isBoard: true, isPresidency: true })" x-sort:group="roles">
|
<a class="btn btn-blue" href="{{ url("club:new_role_president", club_id=club.id) }}">
|
||||||
|
<i class="fa fa-plus"></i> {% trans %}add role{% endtrans %}
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
x-sort="reorder($item, { isBoard: true, isPresidency: true })"
|
||||||
|
x-sort:group="roles"
|
||||||
|
x-ref="presidencyFormSet"
|
||||||
|
>
|
||||||
{% for subform in form %}
|
{% for subform in form %}
|
||||||
{% if subform.is_presidency.value() %}
|
{% if subform.is_presidency.value() %}
|
||||||
{{ display_subform(subform) }}
|
{{ display_subform(subform) }}
|
||||||
@@ -62,7 +69,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<h3>{% trans %}Board{% endtrans %}</h3>
|
<h3>{% trans %}Board{% endtrans %}</h3>
|
||||||
<div x-sort="reorder($item, { isBoard: true, isPresidency: false })" x-sort:group="roles">
|
<a class="btn btn-blue" href="{{ url("club:new_role_board", club_id=club.id) }}">
|
||||||
|
<i class="fa fa-plus"></i> {% trans %}add role{% endtrans %}
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
x-sort="reorder($item, { isBoard: true, isPresidency: false })"
|
||||||
|
x-sort:group="roles"
|
||||||
|
x-ref="boardFormSet"
|
||||||
|
>
|
||||||
{% for subform in form %}
|
{% for subform in form %}
|
||||||
{% if subform.is_board.value() and not subform.is_presidency.value() %}
|
{% if subform.is_board.value() and not subform.is_presidency.value() %}
|
||||||
{{ display_subform(subform) }}
|
{{ display_subform(subform) }}
|
||||||
@@ -70,7 +84,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<h3>{% trans %}Members{% endtrans %}</h3>
|
<h3>{% trans %}Members{% endtrans %}</h3>
|
||||||
<div x-sort="reorder($item, { isBoard: false, isPresidency: false })" x-sort:group="roles">
|
<a class="btn btn-blue" href="{{ url("club:new_role_member", club_id=club.id) }}">
|
||||||
|
<i class="fa fa-plus"></i> {% trans %}add role{% endtrans %}
|
||||||
|
</a>
|
||||||
|
<div
|
||||||
|
x-sort="reorder($item, { isBoard: false, isPresidency: false })"
|
||||||
|
x-sort:group="roles"
|
||||||
|
x-ref="memberFormSet"
|
||||||
|
>
|
||||||
{% for subform in form %}
|
{% for subform in form %}
|
||||||
{% if not subform.is_board.value() %}
|
{% if not subform.is_board.value() %}
|
||||||
{{ display_subform(subform) }}
|
{{ display_subform(subform) }}
|
||||||
|
|||||||
18
club/urls.py
18
club/urls.py
@@ -35,6 +35,9 @@ from club.views import (
|
|||||||
ClubPageEditView,
|
ClubPageEditView,
|
||||||
ClubPageHistView,
|
ClubPageHistView,
|
||||||
ClubRevView,
|
ClubRevView,
|
||||||
|
ClubRoleBoardCreateView,
|
||||||
|
ClubRoleMemberCreateView,
|
||||||
|
ClubRolePresidencyCreateView,
|
||||||
ClubRoleUpdateView,
|
ClubRoleUpdateView,
|
||||||
ClubSellingCSVView,
|
ClubSellingCSVView,
|
||||||
ClubSellingView,
|
ClubSellingView,
|
||||||
@@ -73,6 +76,21 @@ urlpatterns = [
|
|||||||
name="club_old_members",
|
name="club_old_members",
|
||||||
),
|
),
|
||||||
path("<int:club_id>/role/", ClubRoleUpdateView.as_view(), name="club_roles"),
|
path("<int:club_id>/role/", ClubRoleUpdateView.as_view(), name="club_roles"),
|
||||||
|
path(
|
||||||
|
"<int:club_id>/role/new/president/",
|
||||||
|
ClubRolePresidencyCreateView.as_view(),
|
||||||
|
name="new_role_president",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"<int:club_id>/role/new/board/",
|
||||||
|
ClubRoleBoardCreateView.as_view(),
|
||||||
|
name="new_role_board",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"<int:club_id>/role/new/member/",
|
||||||
|
ClubRoleMemberCreateView.as_view(),
|
||||||
|
name="new_role_member",
|
||||||
|
),
|
||||||
path("<int:club_id>/sellings/", ClubSellingView.as_view(), name="club_sellings"),
|
path("<int:club_id>/sellings/", ClubSellingView.as_view(), name="club_sellings"),
|
||||||
path(
|
path(
|
||||||
"<int:club_id>/sellings/csv/", ClubSellingCSVView.as_view(), name="sellings_csv"
|
"<int:club_id>/sellings/csv/", ClubSellingCSVView.as_view(), name="sellings_csv"
|
||||||
|
|||||||
@@ -54,12 +54,13 @@ from club.forms import (
|
|||||||
ClubAdminEditForm,
|
ClubAdminEditForm,
|
||||||
ClubEditForm,
|
ClubEditForm,
|
||||||
ClubOldMemberForm,
|
ClubOldMemberForm,
|
||||||
|
ClubRoleCreateForm,
|
||||||
ClubRoleFormSet,
|
ClubRoleFormSet,
|
||||||
JoinClubForm,
|
JoinClubForm,
|
||||||
MailingForm,
|
MailingForm,
|
||||||
SellingsForm,
|
SellingsForm,
|
||||||
)
|
)
|
||||||
from club.models import Club, Mailing, MailingSubscription, Membership
|
from club.models import Club, ClubRole, Mailing, MailingSubscription, Membership
|
||||||
from com.models import Poster
|
from com.models import Poster
|
||||||
from com.views import (
|
from com.views import (
|
||||||
PosterCreateBaseView,
|
PosterCreateBaseView,
|
||||||
@@ -400,10 +401,91 @@ class ClubRoleUpdateView(
|
|||||||
user=self.request.user, role__is_presidency=True
|
user=self.request.user, role__is_presidency=True
|
||||||
).exists()
|
).exists()
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
return super().get_form_kwargs() | {"form_kwargs": {"label_suffix": ""}}
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return self.request.path
|
return self.request.path
|
||||||
|
|
||||||
|
|
||||||
|
class ClubRoleBaseCreateView(UserPassesTestMixin, SuccessMessageMixin, CreateView):
|
||||||
|
"""View to create a new Club Role, using [][club.forms.ClubRoleCreateForm].
|
||||||
|
|
||||||
|
This view isn't meant to be called directly, but rather subclassed for each
|
||||||
|
type of role that can exist :
|
||||||
|
|
||||||
|
- `[ClubRolePresidencyCreateView][club.views.ClubRolePresidencyCreateView]`
|
||||||
|
to create a presidency role
|
||||||
|
- `[ClubRoleBoardCreateView][club.views.ClubRoleBoardCreateView]`
|
||||||
|
to create a board role
|
||||||
|
- `[ClubRoleMemberCreateView][club.views.ClubRoleMemberCreateView]`
|
||||||
|
to create a member role
|
||||||
|
|
||||||
|
Each subclass have to override the following variables :
|
||||||
|
|
||||||
|
- `is_presidency` and `is_board`, indicating what type of role
|
||||||
|
the view creates.
|
||||||
|
- `role_description`, which is the title of the page, indication
|
||||||
|
the user what kind of role is being created.
|
||||||
|
|
||||||
|
This way, we are making sure the correct type of role will
|
||||||
|
be created, without bothering the user with the implementation details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
form_class = ClubRoleCreateForm
|
||||||
|
model = ClubRole
|
||||||
|
template_name = "core/create.jinja"
|
||||||
|
success_message = _("Role %(name)s created")
|
||||||
|
role_description = ""
|
||||||
|
is_presidency: bool
|
||||||
|
is_board: bool
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def club(self):
|
||||||
|
return get_object_or_404(Club, id=self.kwargs["club_id"])
|
||||||
|
|
||||||
|
def test_func(self):
|
||||||
|
return self.request.user.is_authenticated and (
|
||||||
|
self.request.user.has_perm("club.add_clubrole")
|
||||||
|
or self.club.members.filter(
|
||||||
|
user=self.request.user, role__is_presidency=True
|
||||||
|
).exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
return super().get_form_kwargs() | {
|
||||||
|
"club": self.club,
|
||||||
|
"is_presidency": self.is_presidency,
|
||||||
|
"is_board": self.is_board,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
return super().get_context_data(**kwargs) | {
|
||||||
|
"object_name": self.role_description
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse("club:club_roles", kwargs={"club_id": self.club.id})
|
||||||
|
|
||||||
|
|
||||||
|
class ClubRolePresidencyCreateView(ClubRoleBaseCreateView):
|
||||||
|
is_presidency = True
|
||||||
|
is_board = True
|
||||||
|
role_description = _("club role \u2013 presidency")
|
||||||
|
|
||||||
|
|
||||||
|
class ClubRoleBoardCreateView(ClubRoleBaseCreateView):
|
||||||
|
is_presidency = False
|
||||||
|
is_board = True
|
||||||
|
role_description = _("club role \u2013 board")
|
||||||
|
|
||||||
|
|
||||||
|
class ClubRoleMemberCreateView(ClubRoleBaseCreateView):
|
||||||
|
is_presidency = False
|
||||||
|
is_board = False
|
||||||
|
role_description = _("club role \u2013 member")
|
||||||
|
|
||||||
|
|
||||||
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailFormView):
|
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailFormView):
|
||||||
"""Sales of a club."""
|
"""Sales of a club."""
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
{% extends "core/base.jinja" %}
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
|
{# if the template context has the `object_name` variable,
|
||||||
|
then this one will be used in the page title,
|
||||||
|
instead of the result of `str(object)` #}
|
||||||
|
{% if not object_name %}
|
||||||
|
{% set object_name=form.instance.__class__._meta.verbose_name %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}
|
{% trans name=object_name %}Create {{ name }}{% endtrans %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{% trans name=form.instance.__class__._meta.verbose_name %}Create {{ name }}{% endtrans %}</h2>
|
<h2>{% trans name=object_name %}Create {{ name }}{% endtrans %}</h2>
|
||||||
<form action="" method="post" enctype="multipart/form-data">
|
<form action="" method="post" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p() }}
|
{{ form.as_p() }}
|
||||||
|
|||||||
Reference in New Issue
Block a user