mirror of
https://github.com/ae-utbm/sith.git
synced 2025-02-22 15:37:14 +00:00
Merge pull request #1017 from ae-utbm/subscription-perms
Subscription perms
This commit is contained in:
commit
3df33261ce
@ -125,6 +125,11 @@ class Command(BaseCommand):
|
||||
unix_name=settings.SITH_MAIN_CLUB["unix_name"],
|
||||
address=settings.SITH_MAIN_CLUB["address"],
|
||||
)
|
||||
main_club.board_group.permissions.add(
|
||||
*Permission.objects.filter(
|
||||
codename__in=["view_subscription", "add_subscription"]
|
||||
)
|
||||
)
|
||||
bar_club = Club.objects.create(
|
||||
id=2,
|
||||
name=settings.SITH_BAR_MANAGER["name"],
|
||||
|
@ -417,29 +417,6 @@ class User(AbstractUser):
|
||||
def is_board_member(self) -> bool:
|
||||
return self.groups.filter(club_board=settings.SITH_MAIN_CLUB_ID).exists()
|
||||
|
||||
@cached_property
|
||||
def can_read_subscription_history(self) -> bool:
|
||||
if self.is_root or self.is_board_member:
|
||||
return True
|
||||
|
||||
from club.models import Club
|
||||
|
||||
for club in Club.objects.filter(
|
||||
id__in=settings.SITH_CAN_READ_SUBSCRIPTION_HISTORY
|
||||
):
|
||||
if club in self.clubs_with_rights:
|
||||
return True
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def can_create_subscription(self) -> bool:
|
||||
return self.is_root or (
|
||||
self.memberships.board()
|
||||
.ongoing()
|
||||
.filter(club_id__in=settings.SITH_CAN_CREATE_SUBSCRIPTIONS)
|
||||
.exists()
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def is_launderette_manager(self):
|
||||
from club.models import Club
|
||||
@ -679,14 +656,6 @@ class AnonymousUser(AuthAnonymousUser):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@property
|
||||
def can_create_subscription(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_read_subscription_history(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def was_subscribed(self):
|
||||
return False
|
||||
|
@ -1,19 +1,40 @@
|
||||
{% 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 object and not object_name %}
|
||||
{% set object_name=object %}
|
||||
{% endif %}
|
||||
|
||||
{% block title %}
|
||||
{% if object %}
|
||||
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
|
||||
{% if object_name %}
|
||||
{% trans name=object_name %}Edit {{ name }}{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}Save{% endtrans %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if object %}
|
||||
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
|
||||
{% if object_name %}
|
||||
<h2>{% trans name=object_name %}Edit {{ name }}{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}Save{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
{% if messages %}
|
||||
<div x-data="{show_alert: true}" class="alert alert-green" x-show="show_alert" x-transition>
|
||||
<span class="alert-main">
|
||||
{% for message in messages %}
|
||||
{% if message.level_tag == "success" %}
|
||||
{{ message }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</span>
|
||||
<span class="clickable" @click="show_alert = false">
|
||||
<i class="fa fa-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p() }}
|
||||
|
@ -166,7 +166,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if profile.was_subscribed and (user == profile or user.can_read_subscription_history)%}
|
||||
{% if profile.was_subscribed and (user == profile or user.has_perm("subscription.view_subscription")) %}
|
||||
<div class="collapse" :class="{'shadow': collapsed}" x-data="{collapsed: false}" x-cloak>
|
||||
<div class="collapse-header clickable" @click="collapsed = !collapsed">
|
||||
<span class="collapse-header-text">
|
||||
@ -197,9 +197,9 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
<div>
|
||||
{% if user.is_root or user.is_board_member %}
|
||||
<form class="form-gifts" action="{{ url('core:user_gift_create', user_id=profile.id) }}" method="post">
|
||||
|
@ -13,7 +13,7 @@
|
||||
<h3>{% trans %}User Tools{% endtrans %}</h3>
|
||||
|
||||
<div class="container">
|
||||
{% if user.can_create_subscription or user.is_root or user.is_board_member %}
|
||||
{% if user.has_perm("subscription.view_userban") or user.is_root or user.is_board_member %}
|
||||
<div>
|
||||
<h4>{% trans %}Sith management{% endtrans %}</h4>
|
||||
<ul>
|
||||
@ -21,16 +21,16 @@
|
||||
<li><a href="{{ url('core:group_list') }}">{% trans %}Groups{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('rootplace:merge') }}">{% trans %}Merge users{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('rootplace:operation_logs') }}">{% trans %}Operation logs{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('rootplace:delete_forum_messages') }}">{% trans %}Delete user's forum messages{% endtrans %}</a></li>
|
||||
<li>
|
||||
<a href="{{ url('rootplace:delete_forum_messages') }}">
|
||||
{% trans %}Delete user's forum messages{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.has_perm("core.view_userban") %}
|
||||
<li><a href="{{ url("rootplace:ban_list") }}">{% trans %}Bans{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.can_create_subscription or user.is_root %}
|
||||
<li><a href="{{ url('subscription:subscription') }}">{% trans %}Subscriptions{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_board_member or user.is_root %}
|
||||
<li><a href="{{ url('subscription:stats') }}">{% trans %}Subscription stats{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('club:club_new') }}">{% trans %}New club{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -42,26 +42,44 @@
|
||||
{% set is_admin_on_a_counter = true %}
|
||||
{% endfor %}
|
||||
|
||||
{% if
|
||||
is_admin_on_a_counter
|
||||
or user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||
%}
|
||||
{% if is_admin_on_a_counter or user.is_root or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID) %}
|
||||
<div>
|
||||
<h4>{% trans %}Counters{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||
%}
|
||||
<li><a href="{{ url('counter:admin_list') }}">{% trans %}General counters management{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:product_list') }}">{% trans %}Products management{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:product_type_list') }}">{% trans %}Product types management{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:cash_summary_list') }}">{% trans %}Cash register summaries{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:invoices_call') }}">{% trans %}Invoices call{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:eticket_list') }}">{% trans %}Etickets{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul>
|
||||
{% if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID) %}
|
||||
<li>
|
||||
<a href="{{ url('counter:admin_list') }}">
|
||||
{% trans %}General counters management{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('counter:product_list') }}">
|
||||
{% trans %}Products management{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('counter:product_type_list') }}">
|
||||
{% trans %}Product types management{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('counter:cash_summary_list') }}">
|
||||
{% trans %}Cash register summaries{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('counter:invoices_call') }}">
|
||||
{% trans %}Invoices call{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url('counter:eticket_list') }}">
|
||||
{% trans %}Etickets{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul>
|
||||
{% for b in settings.SITH_COUNTER_BARS %}
|
||||
{% if user.is_in_group(name=b[1]+" admin") %}
|
||||
{% set c = Counter.objects.filter(id=b[0]).first() %}
|
||||
@ -71,28 +89,26 @@
|
||||
|
||||
<span>
|
||||
<span>
|
||||
<a class="button" href="{{ url('counter:admin', counter_id=b[0]) }}">{% trans %}Edit{% endtrans %}</a>
|
||||
<a class="button" href="{{ url('counter:stats', counter_id=b[0]) }}">{% trans %}Stats{% endtrans %}</a>
|
||||
<a class="button" href="{{ url('counter:admin', counter_id=b[0]) }}">
|
||||
{% trans %}Edit{% endtrans %}
|
||||
</a>
|
||||
<a class="button" href="{{ url('counter:stats', counter_id=b[0]) }}">
|
||||
{% trans %}Stats{% endtrans %}
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or user.memberships.ongoing().filter(role__gte=7).count() > 10
|
||||
%}
|
||||
<div>
|
||||
{% if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<div>
|
||||
<h4>{% trans %}Accounting{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
{% if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) %}
|
||||
<li><a href="{{ url('accounting:refound_account') }}">{% trans %}Refound Account{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('accounting:bank_list') }}">{% trans %}General accounting{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></li>
|
||||
@ -116,15 +132,11 @@ or user.memberships.ongoing().filter(role__gte=7).count() > 10
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if
|
||||
user.is_root
|
||||
or user.is_com_admin
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||
%}
|
||||
<div>
|
||||
{% if user.is_root or user.is_com_admin or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
||||
<div>
|
||||
<h4>{% trans %}Communication{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_com_admin or user.is_root %}
|
||||
@ -144,10 +156,39 @@ or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||
<li><a href="{{ url('sas:moderation') }}">{% trans %}Moderate pictures{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.memberships.filter(end_date=None).all().count() > 0 %}
|
||||
{% if user.has_perm("subscription.add_subscription") or user.has_perm("auth.change_perm") or user.is_root or user.is_board_member %}
|
||||
<div>
|
||||
<h4>{% trans %}Subscriptions{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.has_perm("subscription.add_subscription") %}
|
||||
<li>
|
||||
<a href="{{ url("subscription:subscription") }}">
|
||||
{% trans %}New subscription{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.has_perm("auth.change_permission") %}
|
||||
<li>
|
||||
<a href="{{ url("subscription:perms") }}">
|
||||
{% trans %}Manage permissions{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.is_root or user.is_board_member %}
|
||||
<li>
|
||||
<a href="{{ url("subscription:stats") }}">
|
||||
{% trans %}Subscription stats{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.memberships.filter(end_date=None).all().count() > 0 %}
|
||||
<div>
|
||||
<h4>{% trans %}Club tools{% endtrans %}</h4>
|
||||
<ul>
|
||||
@ -156,22 +197,31 @@ or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
%}
|
||||
<div>
|
||||
{% if user.has_perm("pedagogy.add_uv") or user.has_perm("pedagogy.delete_uvcomment") %}
|
||||
<div>
|
||||
<h4>{% trans %}Pedagogy{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li><a href="{{ url('pedagogy:uv_create') }}">{% trans %}Create UV{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('pedagogy:moderation') }}">{% trans %}Moderate comments{% endtrans %}</a></li>
|
||||
{% if user.has_perm("pedagogy.add_uv") %}
|
||||
<li>
|
||||
<a href="{{ url("pedagogy:uv_create") }}">
|
||||
{% trans %}Create UV{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.has_perm("pedagogy.delete_uvcomment") %}
|
||||
<li>
|
||||
<a href="{{ url("pedagogy:moderation") }}">
|
||||
{% trans %}Moderate comments{% endtrans %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h4>{% trans %}Elections{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li><a href="{{ url('election:list') }}">{% trans %}See available elections{% endtrans %}</a></li>
|
||||
@ -180,14 +230,14 @@ or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
<li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li>
|
||||
{%- endif -%}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<h4>{% trans %}Other tools{% endtrans %}</h4>
|
||||
<ul>
|
||||
<li><a href="{{ url('trombi:user_tools') }}">{% trans %}Trombi tools{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
@ -28,6 +28,7 @@ from captcha.fields import CaptchaField
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.staticfiles.management.commands.collectstatic import (
|
||||
staticfiles_storage,
|
||||
)
|
||||
@ -440,3 +441,28 @@ class GiftForm(forms.ModelForm):
|
||||
id=user_id
|
||||
)
|
||||
self.fields["user"].widget = forms.HiddenInput()
|
||||
|
||||
|
||||
class PermissionGroupsForm(forms.ModelForm):
|
||||
"""Manage the groups that have a specific permission."""
|
||||
|
||||
class Meta:
|
||||
model = Permission
|
||||
fields = []
|
||||
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
Group.objects.all(),
|
||||
label=_("Groups"),
|
||||
widget=AutoCompleteSelectMultipleGroup,
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, instance: Permission, **kwargs):
|
||||
super().__init__(instance=instance, **kwargs)
|
||||
self.fields["groups"].initial = instance.group_set.all()
|
||||
|
||||
def save(self, commit: bool = True): # noqa FTB001
|
||||
instance = super().save(commit=False)
|
||||
if commit:
|
||||
instance.group_set.set(self.cleaned_data["groups"])
|
||||
return instance
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import ListView
|
||||
@ -25,6 +29,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from core.auth.mixins import CanEditMixin
|
||||
from core.models import Group, User
|
||||
from core.views import DetailFormView
|
||||
from core.views.forms import PermissionGroupsForm
|
||||
from core.views.widgets.select import AutoCompleteSelectMultipleUser
|
||||
|
||||
# Forms
|
||||
@ -130,3 +135,62 @@ class GroupDeleteView(CanEditMixin, DeleteView):
|
||||
pk_url_kwarg = "group_id"
|
||||
template_name = "core/delete_confirm.jinja"
|
||||
success_url = reverse_lazy("core:group_list")
|
||||
|
||||
|
||||
class PermissionGroupsUpdateView(
|
||||
PermissionRequiredMixin, SuccessMessageMixin, UpdateView
|
||||
):
|
||||
"""Manage the groups that have a specific permission.
|
||||
|
||||
Notes:
|
||||
This is an `UpdateView`, but unlike typical `UpdateView`,
|
||||
it doesn't accept url arguments to retrieve the object
|
||||
to update.
|
||||
As such, a `PermissionGroupsUpdateView` can only deal with
|
||||
a single hardcoded permission.
|
||||
|
||||
This is not a limitation, but an on-purpose design,
|
||||
mainly for security matters.
|
||||
|
||||
Example:
|
||||
```python
|
||||
class SubscriptionPermissionView(PermissionGroupsUpdateView):
|
||||
permission = "subscription.add_subscription"
|
||||
```
|
||||
"""
|
||||
|
||||
permission_required = "auth.change_permission"
|
||||
template_name = "core/edit.jinja"
|
||||
form_class = PermissionGroupsForm
|
||||
permission = None
|
||||
success_message = _("Groups have been successfully updated.")
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
if not self.permission:
|
||||
raise ImproperlyConfigured(
|
||||
f"{self.__class__.__name__} is missing the permission attribute. "
|
||||
"Please fill it with either a permission string "
|
||||
"or a Permission object."
|
||||
)
|
||||
if isinstance(self.permission, Permission):
|
||||
return self.permission
|
||||
if isinstance(self.permission, str):
|
||||
try:
|
||||
app_label, codename = self.permission.split(".")
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
"Permission name should be in the form "
|
||||
"app_label.permission_codename."
|
||||
) from e
|
||||
return get_object_or_404(
|
||||
Permission, codename=codename, content_type__app_label=app_label
|
||||
)
|
||||
raise TypeError(
|
||||
f"{self.__class__.__name__}.permission "
|
||||
f"must be a string or a permission instance."
|
||||
)
|
||||
|
||||
def get_success_url(self):
|
||||
# if children classes define a success url, return it,
|
||||
# else stay on the same page
|
||||
return self.success_url or self.request.path
|
||||
|
@ -228,3 +228,38 @@ Les groupes de ban existants sont les suivants :
|
||||
- `Banned from buying alcohol` : les utilisateurs interdits de vente d'alcool (non mineurs)
|
||||
- `Banned from counters` : les utilisateurs interdits d'utilisation des comptoirs
|
||||
- `Banned to subscribe` : les utilisateurs interdits de cotisation
|
||||
|
||||
## Groupes liés à une permission
|
||||
|
||||
Certaines actions sur le site demandent une permission en particulier,
|
||||
que l'on veut donner ou retirer n'importe quand.
|
||||
|
||||
Prenons par exemple les cotisations : lors de l'intégration,
|
||||
on veut permettre aux membres du bureau de l'Integ
|
||||
de créer des cotisations, et pareil pour les membres du bureau
|
||||
de la Welcome Week pendant cette dernière.
|
||||
|
||||
Dans ces cas-là, il est pertinent de mettre à disposition
|
||||
des administrateurs du site une page leur permettant
|
||||
de gérer quels groupes ont une permission donnée.
|
||||
Pour ce faire, il existe
|
||||
[PermissionGroupsUpdateView][core.views.PermissionGroupsUpdateView].
|
||||
|
||||
Pour l'utiliser, il suffit de créer une vue qui en hérite
|
||||
et de lui dire quelle est la permission dont on veut gérer
|
||||
les groupes :
|
||||
|
||||
```python
|
||||
from core.views.group import PermissionGroupsUpdateView
|
||||
|
||||
|
||||
class SubscriptionPermissionView(PermissionGroupsUpdateView):
|
||||
permission = "subscription.add_subscription"
|
||||
```
|
||||
|
||||
Configurez l'url de la vue, et c'est tout !
|
||||
La page ainsi générée contiendra un formulaire
|
||||
avec un unique champ permettant de sélectionner des groupes.
|
||||
Par défaut, seuls les utilisateurs avec la permission
|
||||
`auth.change_permission` auront accès à ce formulaire
|
||||
(donc, normalement, uniquement les utilisateurs Root).
|
||||
|
@ -6,7 +6,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-19 18:12+0100\n"
|
||||
"POT-Creation-Date: 2025-02-12 15:55+0100\n"
|
||||
"PO-Revision-Date: 2016-07-18\n"
|
||||
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
|
||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||
@ -2383,11 +2383,10 @@ msgstr "Confirmation"
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: core/templates/core/edit.jinja core/templates/core/file_edit.jinja
|
||||
#: counter/templates/counter/cash_register_summary.jinja
|
||||
#: core/templates/core/edit.jinja
|
||||
#, python-format
|
||||
msgid "Edit %(obj)s"
|
||||
msgstr "Éditer %(obj)s"
|
||||
msgid "Edit %(name)s"
|
||||
msgstr "Éditer %(name)s"
|
||||
|
||||
#: core/templates/core/file.jinja core/templates/core/file_list.jinja
|
||||
msgid "File list"
|
||||
@ -2457,6 +2456,12 @@ msgstr "octets"
|
||||
msgid "Download"
|
||||
msgstr "Télécharger"
|
||||
|
||||
#: core/templates/core/file_edit.jinja
|
||||
#: counter/templates/counter/cash_register_summary.jinja
|
||||
#, python-format
|
||||
msgid "Edit %(obj)s"
|
||||
msgstr "Éditer %(obj)s"
|
||||
|
||||
#: core/templates/core/file_list.jinja
|
||||
msgid "There is no file in this website."
|
||||
msgstr "Il n'y a pas de fichier sur ce site web."
|
||||
@ -2914,7 +2919,7 @@ msgstr "Blouse"
|
||||
msgid "Not subscribed"
|
||||
msgstr "Non cotisant"
|
||||
|
||||
#: core/templates/core/user_detail.jinja
|
||||
#: core/templates/core/user_detail.jinja core/templates/core/user_tools.jinja
|
||||
#: subscription/templates/subscription/subscription.jinja
|
||||
msgid "New subscription"
|
||||
msgstr "Nouvelle cotisation"
|
||||
@ -3146,15 +3151,6 @@ msgstr "Supprimer les messages forum d'un utilisateur"
|
||||
msgid "Bans"
|
||||
msgstr "Bans"
|
||||
|
||||
#: core/templates/core/user_tools.jinja
|
||||
msgid "Subscriptions"
|
||||
msgstr "Cotisations"
|
||||
|
||||
#: core/templates/core/user_tools.jinja
|
||||
#: subscription/templates/subscription/stats.jinja
|
||||
msgid "Subscription stats"
|
||||
msgstr "Statistiques de cotisation"
|
||||
|
||||
#: core/templates/core/user_tools.jinja counter/forms.py
|
||||
#: counter/views/mixins.py
|
||||
msgid "Counters"
|
||||
@ -3227,6 +3223,19 @@ msgstr "Modérer les fichiers"
|
||||
msgid "Moderate pictures"
|
||||
msgstr "Modérer les photos"
|
||||
|
||||
#: core/templates/core/user_tools.jinja
|
||||
msgid "Subscriptions"
|
||||
msgstr "Cotisations"
|
||||
|
||||
#: core/templates/core/user_tools.jinja
|
||||
msgid "Manage permissions"
|
||||
msgstr "Gérer les permissions"
|
||||
|
||||
#: core/templates/core/user_tools.jinja
|
||||
#: subscription/templates/subscription/stats.jinja
|
||||
msgid "Subscription stats"
|
||||
msgstr "Statistiques de cotisation"
|
||||
|
||||
#: core/templates/core/user_tools.jinja pedagogy/templates/pedagogy/guide.jinja
|
||||
msgid "Create UV"
|
||||
msgstr "Créer UV"
|
||||
@ -3355,6 +3364,10 @@ msgstr "Utilisateurs à ajouter au groupe"
|
||||
msgid "Users to remove from group"
|
||||
msgstr "Utilisateurs à retirer du groupe"
|
||||
|
||||
#: core/views/group.py
|
||||
msgid "Groups have been successfully updated."
|
||||
msgstr "Les groupes ont été mis à jour avec succès."
|
||||
|
||||
#: core/views/user.py
|
||||
msgid "We couldn't verify that this email actually exists"
|
||||
msgstr "Nous n'avons pas réussi à vérifier que cette adresse mail existe."
|
||||
@ -5676,6 +5689,10 @@ msgstr "Cotisations par type"
|
||||
msgid "Existing member"
|
||||
msgstr "Membre existant"
|
||||
|
||||
#: subscription/views.py
|
||||
msgid "the groups that can create subscriptions"
|
||||
msgstr "les groupes pouvant créer des cotisations"
|
||||
|
||||
#: trombi/models.py
|
||||
msgid "subscription deadline"
|
||||
msgstr "fin des inscriptions"
|
||||
|
@ -517,14 +517,6 @@ SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER = 1
|
||||
SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS = 2
|
||||
SITH_PRODUCTTYPE_SUBSCRIPTION = 2
|
||||
|
||||
# Defines which club lets its member the ability to make subscriptions
|
||||
# Elements of this list are club's id
|
||||
SITH_CAN_CREATE_SUBSCRIPTIONS = [1]
|
||||
|
||||
# Defines which clubs lets its members the ability to see users subscription history
|
||||
# Elements of this list are club's id
|
||||
SITH_CAN_READ_SUBSCRIPTION_HISTORY = []
|
||||
|
||||
# Number of weeks before the end of a subscription when the subscriber can resubscribe
|
||||
SITH_SUBSCRIPTION_END = 10
|
||||
|
||||
|
@ -5,6 +5,7 @@ from typing import Callable
|
||||
|
||||
import pytest
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import Client
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import localdate
|
||||
@ -108,7 +109,12 @@ def test_page_access(
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_submit_form_existing_user(client: Client, settings: SettingsWrapper):
|
||||
client.force_login(board_user.make())
|
||||
client.force_login(
|
||||
baker.make(
|
||||
User,
|
||||
user_permissions=Permission.objects.filter(codename="add_subscription"),
|
||||
)
|
||||
)
|
||||
user = old_subscriber_user.make()
|
||||
response = client.post(
|
||||
reverse("subscription:fragment-existing-user"),
|
||||
@ -133,7 +139,12 @@ def test_submit_form_existing_user(client: Client, settings: SettingsWrapper):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_submit_form_new_user(client: Client, settings: SettingsWrapper):
|
||||
client.force_login(board_user.make())
|
||||
client.force_login(
|
||||
baker.make(
|
||||
User,
|
||||
user_permissions=Permission.objects.filter(codename="add_subscription"),
|
||||
)
|
||||
)
|
||||
response = client.post(
|
||||
reverse("subscription:fragment-new-user"),
|
||||
{
|
||||
|
43
subscription/tests/test_permissions.py
Normal file
43
subscription/tests/test_permissions.py
Normal file
@ -0,0 +1,43 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from model_bakery import baker
|
||||
from pytest_django.asserts import assertRedirects
|
||||
|
||||
from club.models import Club, Membership
|
||||
from core.baker_recipes import subscriber_user
|
||||
from core.models import User
|
||||
|
||||
|
||||
class TestSubscriptionPermission(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user: User = subscriber_user.make()
|
||||
cls.admin = baker.make(User, is_superuser=True)
|
||||
cls.club = baker.make(Club)
|
||||
baker.make(Membership, user=cls.user, club=cls.club, role=7)
|
||||
|
||||
def test_give_permission(self):
|
||||
self.client.force_login(self.admin)
|
||||
response = self.client.post(
|
||||
reverse("subscription:perms"), {"groups": [self.club.board_group_id]}
|
||||
)
|
||||
assertRedirects(response, reverse("subscription:perms"))
|
||||
assert self.user.has_perm("subscription.add_subscription")
|
||||
|
||||
def test_remove_permission(self):
|
||||
self.client.force_login(self.admin)
|
||||
response = self.client.post(reverse("subscription:perms"), {"groups": []})
|
||||
assertRedirects(response, reverse("subscription:perms"))
|
||||
assert not self.user.has_perm("subscription.add_subscription")
|
||||
|
||||
def test_subscription_page_access(self):
|
||||
self.client.force_login(self.user)
|
||||
response = self.client.get(reverse("subscription:subscription"))
|
||||
assert response.status_code == 403
|
||||
|
||||
self.club.board_group.permissions.add(
|
||||
Permission.objects.get(codename="add_subscription")
|
||||
)
|
||||
response = self.client.get(reverse("subscription:subscription"))
|
||||
assert response.status_code == 200
|
@ -20,6 +20,7 @@ from subscription.views import (
|
||||
CreateSubscriptionNewUserFragment,
|
||||
NewSubscription,
|
||||
SubscriptionCreatedFragment,
|
||||
SubscriptionPermissionView,
|
||||
SubscriptionsStatsView,
|
||||
)
|
||||
|
||||
@ -41,5 +42,10 @@ urlpatterns = [
|
||||
SubscriptionCreatedFragment.as_view(),
|
||||
name="creation-success",
|
||||
),
|
||||
path(
|
||||
"perms/",
|
||||
SubscriptionPermissionView.as_view(),
|
||||
name="perms",
|
||||
),
|
||||
path("stats/", SubscriptionsStatsView.as_view(), name="stats"),
|
||||
]
|
||||
|
@ -14,13 +14,15 @@
|
||||
#
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.timezone import localdate
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import CreateView, DetailView, TemplateView
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from core.views.group import PermissionGroupsUpdateView
|
||||
from counter.apps import PAYMENT_METHOD
|
||||
from subscription.forms import (
|
||||
SelectionDateForm,
|
||||
@ -30,13 +32,9 @@ from subscription.forms import (
|
||||
from subscription.models import Subscription
|
||||
|
||||
|
||||
class CanCreateSubscriptionMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.can_create_subscription
|
||||
|
||||
|
||||
class NewSubscription(CanCreateSubscriptionMixin, TemplateView):
|
||||
class NewSubscription(PermissionRequiredMixin, TemplateView):
|
||||
template_name = "subscription/subscription.jinja"
|
||||
permission_required = "subscription.add_subscription"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(**kwargs) | {
|
||||
@ -49,8 +47,9 @@ class NewSubscription(CanCreateSubscriptionMixin, TemplateView):
|
||||
}
|
||||
|
||||
|
||||
class CreateSubscriptionFragment(CanCreateSubscriptionMixin, CreateView):
|
||||
class CreateSubscriptionFragment(PermissionRequiredMixin, CreateView):
|
||||
template_name = "subscription/fragments/creation_form.jinja"
|
||||
permission_required = "subscription.add_subscription"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(
|
||||
@ -72,13 +71,21 @@ class CreateSubscriptionNewUserFragment(CreateSubscriptionFragment):
|
||||
extra_context = {"post_url": reverse_lazy("subscription:fragment-new-user")}
|
||||
|
||||
|
||||
class SubscriptionCreatedFragment(CanCreateSubscriptionMixin, DetailView):
|
||||
class SubscriptionCreatedFragment(PermissionRequiredMixin, DetailView):
|
||||
template_name = "subscription/fragments/creation_success.jinja"
|
||||
permission_required = "subscription.add_subscription"
|
||||
model = Subscription
|
||||
pk_url_kwarg = "subscription_id"
|
||||
context_object_name = "subscription"
|
||||
|
||||
|
||||
class SubscriptionPermissionView(PermissionGroupsUpdateView):
|
||||
"""Manage the groups that have access to the subscription creation page."""
|
||||
|
||||
permission = "subscription.add_subscription"
|
||||
extra_context = {"object_name": _("the groups that can create subscriptions")}
|
||||
|
||||
|
||||
class SubscriptionsStatsView(FormView):
|
||||
template_name = "subscription/stats.jinja"
|
||||
form_class = SelectionDateForm
|
||||
|
Loading…
x
Reference in New Issue
Block a user