mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-31 07:49:57 +01:00 
			
		
		
		
	Comment code
This commit is contained in:
		| @@ -250,12 +250,18 @@ class Membership(models.Model): | ||||
|     ) | ||||
|  | ||||
|     def valid(self): | ||||
|         """ | ||||
|         A membership is valid if today is between the start and the end date. | ||||
|         """ | ||||
|         if self.date_end is not None: | ||||
|             return self.date_start.toordinal() <= datetime.datetime.now().toordinal() < self.date_end.toordinal() | ||||
|         else: | ||||
|             return self.date_start.toordinal() <= datetime.datetime.now().toordinal() | ||||
|  | ||||
|     def save(self, *args, **kwargs): | ||||
|         """ | ||||
|         Calculate fee and end date before saving the membership and creating the transaction if needed. | ||||
|         """ | ||||
|         if self.club.parent_club is not None: | ||||
|             if not Membership.objects.filter(user=self.user, club=self.club.parent_club).exists(): | ||||
|                 raise ValidationError(_('User is not a member of the parent club') + ' ' + self.club.parent_club.name) | ||||
| @@ -287,6 +293,9 @@ class Membership(models.Model): | ||||
|         self.make_transaction() | ||||
|  | ||||
|     def make_transaction(self): | ||||
|         """ | ||||
|         Create Membership transaction associated to this membership. | ||||
|         """ | ||||
|         if not self.fee or MembershipTransaction.objects.filter(membership=self).exists(): | ||||
|             return | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,9 @@ from .models import Club, Membership | ||||
|  | ||||
|  | ||||
| class ClubTable(tables.Table): | ||||
|     """ | ||||
|     List all clubs. | ||||
|     """ | ||||
|     class Meta: | ||||
|         attrs = { | ||||
|             'class': 'table table-condensed table-striped table-hover' | ||||
| @@ -30,6 +33,9 @@ class ClubTable(tables.Table): | ||||
|  | ||||
|  | ||||
| class UserTable(tables.Table): | ||||
|     """ | ||||
|     List all users. | ||||
|     """ | ||||
|     section = tables.Column(accessor='profile.section') | ||||
|  | ||||
|     balance = tables.Column(accessor='note.balance', verbose_name=_("Balance")) | ||||
| @@ -51,6 +57,9 @@ class UserTable(tables.Table): | ||||
|  | ||||
|  | ||||
| class MembershipTable(tables.Table): | ||||
|     """ | ||||
|     List all memberships. | ||||
|     """ | ||||
|     roles = tables.Column( | ||||
|         attrs={ | ||||
|             "td": { | ||||
| @@ -59,7 +68,17 @@ class MembershipTable(tables.Table): | ||||
|         } | ||||
|     ) | ||||
|  | ||||
|     def render_user(self, value): | ||||
|         # If the user has the right, link the displayed user with the page of its detail. | ||||
|         s = value.username | ||||
|         if PermissionBackend.check_perm(get_current_authenticated_user(), "auth.view_user", value): | ||||
|             s = format_html("<a href={url}>{name}</a>", | ||||
|                             url=reverse_lazy('member:user_detail', kwargs={"pk": value.pk}), name=s) | ||||
|  | ||||
|         return s | ||||
|  | ||||
|     def render_club(self, value): | ||||
|         # If the user has the right, link the displayed club with the page of its detail. | ||||
|         s = value.name | ||||
|         if PermissionBackend.check_perm(get_current_authenticated_user(), "member.view_club", value): | ||||
|             s = format_html("<a href={url}>{name}</a>", | ||||
| @@ -94,6 +113,7 @@ class MembershipTable(tables.Table): | ||||
|         return t | ||||
|  | ||||
|     def render_roles(self, record): | ||||
|         # If the user has the right to manage the roles, display the link to manage them | ||||
|         roles = record.roles.all() | ||||
|         s = ", ".join(str(role) for role in roles) | ||||
|         if PermissionBackend.check_perm(get_current_authenticated_user(), "member.change_membership_roles", record): | ||||
|   | ||||
| @@ -30,6 +30,9 @@ from .tables import ClubTable, UserTable, MembershipTable | ||||
|  | ||||
|  | ||||
| class CustomLoginView(LoginView): | ||||
|     """ | ||||
|     Login view, where the user can select its permission mask. | ||||
|     """ | ||||
|     form_class = CustomAuthenticationForm | ||||
|  | ||||
|     def form_valid(self, form): | ||||
| @@ -38,6 +41,9 @@ class CustomLoginView(LoginView): | ||||
|  | ||||
|  | ||||
| class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     Update the user information. | ||||
|     """ | ||||
|     model = User | ||||
|     fields = ['first_name', 'last_name', 'username', 'email'] | ||||
|     template_name = 'member/profile_update.html' | ||||
| @@ -93,6 +99,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|             user.save() | ||||
|  | ||||
|             if olduser.email != user.email: | ||||
|                 # If the user changed her/his email, then it is unvalidated and a confirmation link is sent. | ||||
|                 user.profile.email_confirmed = False | ||||
|                 user.profile.send_email_validation_link() | ||||
|  | ||||
| @@ -132,13 +139,16 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|  | ||||
| class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|     """ | ||||
|     Affiche la liste des utilisateurs, avec une fonction de recherche statique | ||||
|     Display user list, with a search bar | ||||
|     """ | ||||
|     model = User | ||||
|     table_class = UserTable | ||||
|     template_name = 'member/user_list.html' | ||||
|  | ||||
|     def get_queryset(self, **kwargs): | ||||
|         """ | ||||
|         Filter the user list with the given pattern. | ||||
|         """ | ||||
|         qs = super().get_queryset().filter(profile__registration_valid=True) | ||||
|         if "search" in self.request.GET: | ||||
|             pattern = self.request.GET["search"] | ||||
| @@ -150,6 +160,7 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|                 Q(first_name__iregex=pattern) | ||||
|                 | Q(last_name__iregex=pattern) | ||||
|                 | Q(profile__section__iregex=pattern) | ||||
|                 | Q(profile__username__iregex="^" + pattern) | ||||
|                 | Q(note__alias__name__iregex="^" + pattern) | ||||
|                 | Q(note__alias__normalized_name__iregex=Alias.normalize("^" + pattern)) | ||||
|             ) | ||||
| @@ -167,6 +178,9 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|  | ||||
|  | ||||
| class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
|     View and manage user aliases. | ||||
|     """ | ||||
|     model = User | ||||
|     template_name = 'member/profile_alias.html' | ||||
|     context_object_name = 'user_object' | ||||
| @@ -179,6 +193,9 @@ class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|  | ||||
|  | ||||
| class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, DetailView): | ||||
|     """ | ||||
|     Update profile picture of the user note. | ||||
|     """ | ||||
|     form_class = ImageForm | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
| @@ -278,6 +295,9 @@ class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|  | ||||
|  | ||||
| class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
|     Display details of a club | ||||
|     """ | ||||
|     model = Club | ||||
|     context_object_name = "club" | ||||
|  | ||||
| @@ -298,6 +318,7 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|  | ||||
|         context['member_list'] = MembershipTable(data=club_member) | ||||
|  | ||||
|         # Check if the user has the right to create a membership, to display the button. | ||||
|         empty_membership = Membership( | ||||
|             club=club, | ||||
|             user=User.objects.first(), | ||||
| @@ -312,6 +333,9 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|  | ||||
|  | ||||
| class ClubAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
|     Manage aliases of a club. | ||||
|     """ | ||||
|     model = Club | ||||
|     template_name = 'member/club_alias.html' | ||||
|     context_object_name = 'club' | ||||
| @@ -324,6 +348,9 @@ class ClubAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|  | ||||
|  | ||||
| class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     Update the information of a club. | ||||
|     """ | ||||
|     model = Club | ||||
|     context_object_name = "club" | ||||
|     form_class = ClubForm | ||||
| @@ -334,6 +361,9 @@ class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|  | ||||
|  | ||||
| class ClubPictureUpdateView(PictureUpdateView): | ||||
|     """ | ||||
|     Update the profile picture of a club. | ||||
|     """ | ||||
|     model = Club | ||||
|     template_name = 'member/club_picture_update.html' | ||||
|     context_object_name = 'club' | ||||
| @@ -343,6 +373,9 @@ class ClubPictureUpdateView(PictureUpdateView): | ||||
|  | ||||
|  | ||||
| class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|     """ | ||||
|     Add a membership to a club. | ||||
|     """ | ||||
|     model = Membership | ||||
|     form_class = MembershipForm | ||||
|     template_name = 'member/add_members.html' | ||||
| @@ -352,10 +385,12 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|         form = context['form'] | ||||
|  | ||||
|         if "club_pk" in self.kwargs: | ||||
|             # We create a new membership. | ||||
|             club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\ | ||||
|                 .get(pk=self.kwargs["club_pk"]) | ||||
|             form.fields['credit_amount'].initial = club.membership_fee_paid | ||||
|  | ||||
|             # If the concerned club is the BDE, then we add the option that Société générale pays the membership. | ||||
|             if club.name != "BDE": | ||||
|                 del form.fields['soge'] | ||||
|             else: | ||||
| @@ -366,6 +401,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|                 fee += kfet.membership_fee_paid | ||||
|                 context["total_fee"] = "{:.02f}".format(fee / 100, ) | ||||
|         else: | ||||
|             # This is a renewal. Fields can be pre-completed. | ||||
|             old_membership = self.get_queryset().get(pk=self.kwargs["pk"]) | ||||
|             club = old_membership.club | ||||
|             user = old_membership.user | ||||
| @@ -378,6 +414,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|             form.fields['last_name'].initial = user.last_name | ||||
|             form.fields['first_name'].initial = user.first_name | ||||
|  | ||||
|             # If this is a renewal of a BDE membership, Société générale can pays, if it is not yet done | ||||
|             if club.name != "BDE" or user.profile.soge: | ||||
|                 del form.fields['soge'] | ||||
|             else: | ||||
| @@ -393,6 +430,10 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|         return context | ||||
|  | ||||
|     def form_valid(self, form): | ||||
|         """ | ||||
|         Create membership, check that all is good, make transactions | ||||
|         """ | ||||
|         # Get the club that is concerned by the membership | ||||
|         if "club_pk" in self.kwargs: | ||||
|             club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view")) \ | ||||
|                 .get(pk=self.kwargs["club_pk"]) | ||||
| @@ -404,6 +445,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|  | ||||
|         form.instance.club = club | ||||
|  | ||||
|         # Get form data | ||||
|         credit_type = form.cleaned_data["credit_type"] | ||||
|         credit_amount = form.cleaned_data["credit_amount"] | ||||
|         last_name = form.cleaned_data["last_name"] | ||||
| @@ -411,6 +453,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|         bank = form.cleaned_data["bank"] | ||||
|         soge = form.cleaned_data["soge"] and not user.profile.soge and club.name == "BDE" | ||||
|  | ||||
|         # If Société générale pays, then we auto-fill some data | ||||
|         if soge: | ||||
|             credit_type = NoteSpecial.objects.get(special_type="Virement bancaire") | ||||
|             bde = club | ||||
| @@ -466,6 +509,9 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|                            .format(form.instance.club.membership_start)) | ||||
|             return super().form_invalid(form) | ||||
|  | ||||
|         # Now, all is fine, the membership can be created. | ||||
|  | ||||
|         # Credit note before the membership is created. | ||||
|         if credit_amount > 0: | ||||
|             if not last_name or not first_name or (not bank and credit_type.special_type == "Chèque"): | ||||
|                 if not last_name: | ||||
| @@ -488,6 +534,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|                 valid=True, | ||||
|             ) | ||||
|  | ||||
|         # If Société générale pays, then we store the information: the bank can't pay twice to a same person. | ||||
|         if soge: | ||||
|             user.profile.soge = True | ||||
|             user.profile.save() | ||||
| @@ -495,6 +542,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|             kfet = Club.objects.get(name="Kfet") | ||||
|             kfet_fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid | ||||
|  | ||||
|             # Get current membership, to get the end date | ||||
|             old_membership = Membership.objects.filter( | ||||
|                 club__name="Kfet", | ||||
|                 user=user, | ||||
| @@ -522,6 +570,9 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|  | ||||
|  | ||||
| class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     Manage the roles of a user in a club | ||||
|     """ | ||||
|     model = Membership | ||||
|     form_class = MembershipForm | ||||
|     template_name = 'member/add_members.html' | ||||
| @@ -534,6 +585,7 @@ class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|  | ||||
|     def get_form(self, form_class=None): | ||||
|         form = super().get_form(form_class) | ||||
|         # We don't create a full membership, we only update one field | ||||
|         form.fields['user'].disabled = True | ||||
|         del form.fields['date_start'] | ||||
|         del form.fields['credit_type'] | ||||
|   | ||||
| @@ -45,6 +45,7 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl | ||||
|             .filter(PermissionBackend.filter_queryset(self.request.user, NoteSpecial, "view"))\ | ||||
|             .order_by("special_type").all() | ||||
|  | ||||
|         # Add a shortcut for entry page for open activities | ||||
|         if "activity" in settings.INSTALLED_APPS: | ||||
|             from activity.models import Activity | ||||
|             context["activities_open"] = Activity.objects.filter(open=True).filter( | ||||
| @@ -56,7 +57,7 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl | ||||
|  | ||||
| class TransactionTemplateCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): | ||||
|     """ | ||||
|     Create TransactionTemplate | ||||
|     Create Transaction template | ||||
|     """ | ||||
|     model = TransactionTemplate | ||||
|     form_class = TransactionTemplateForm | ||||
| @@ -65,7 +66,7 @@ class TransactionTemplateCreateView(ProtectQuerysetMixin, LoginRequiredMixin, Cr | ||||
|  | ||||
| class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|     """ | ||||
|     List TransactionsTemplates | ||||
|     List Transaction templates | ||||
|     """ | ||||
|     model = TransactionTemplate | ||||
|     table_class = ButtonTable | ||||
| @@ -73,6 +74,7 @@ class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, Sing | ||||
|  | ||||
| class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     Update Transaction template | ||||
|     """ | ||||
|     model = TransactionTemplate | ||||
|     form_class = TransactionTemplateForm | ||||
|   | ||||
| @@ -10,6 +10,9 @@ from note_kfet.inputs import AmountInput | ||||
|  | ||||
|  | ||||
| class SignUpForm(UserCreationForm): | ||||
|     """ | ||||
|     Pre-register users with all information | ||||
|     """ | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.fields['username'].widget.attrs.pop("autofocus", None) | ||||
| @@ -25,6 +28,9 @@ class SignUpForm(UserCreationForm): | ||||
|  | ||||
|  | ||||
| class ValidationForm(forms.Form): | ||||
|     """ | ||||
|     Validate the inscription of the new users and pay memberships. | ||||
|     """ | ||||
|     soge = forms.BooleanField( | ||||
|         label=_("Inscription paid by Société Générale"), | ||||
|         required=False, | ||||
| @@ -66,6 +72,7 @@ class ValidationForm(forms.Form): | ||||
|         initial=True, | ||||
|     ) | ||||
|  | ||||
|     # The user can join the Kfet club at the inscription | ||||
|     join_Kfet = forms.BooleanField( | ||||
|         label=_("Join Kfet Club"), | ||||
|         required=False, | ||||
|   | ||||
| @@ -6,6 +6,9 @@ from django.contrib.auth.models import User | ||||
|  | ||||
|  | ||||
| class FutureUserTable(tables.Table): | ||||
|     """ | ||||
|     Display the list of pre-registered users | ||||
|     """ | ||||
|     phone_number = tables.Column(accessor='profile.phone_number') | ||||
|  | ||||
|     section = tables.Column(accessor='profile.section') | ||||
|   | ||||
| @@ -5,13 +5,12 @@ from django.conf import settings | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.contrib.auth.models import User | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.db.models import Q | ||||
| from django.shortcuts import resolve_url, redirect | ||||
| from django.urls import reverse_lazy | ||||
| from django.utils.decorators import method_decorator | ||||
| from django.utils.http import urlsafe_base64_decode | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.views import View | ||||
| from django.views.decorators.csrf import csrf_protect | ||||
| from django.views.generic import CreateView, TemplateView, DetailView, FormView | ||||
| from django_tables2 import SingleTableView | ||||
| from member.forms import ProfileForm | ||||
| @@ -46,11 +45,13 @@ class UserCreateView(CreateView): | ||||
|         """ | ||||
|         If the form is valid, then the user is created with is_active set to False | ||||
|         so that the user cannot log in until the email has been validated. | ||||
|         The user must also wait that someone validate her/his account. | ||||
|         """ | ||||
|         profile_form = ProfileForm(data=self.request.POST) | ||||
|         if not profile_form.is_valid(): | ||||
|             return self.form_invalid(form) | ||||
|  | ||||
|         # Save the user and the profile | ||||
|         user = form.save(commit=False) | ||||
|         user.is_active = False | ||||
|         profile_form.instance.user = user | ||||
| @@ -67,16 +68,15 @@ class UserCreateView(CreateView): | ||||
|  | ||||
|  | ||||
| class UserValidateView(TemplateView): | ||||
|     """ | ||||
|     A view to validate the email address. | ||||
|     """ | ||||
|     title = _("Email validation") | ||||
|     template_name = 'registration/email_validation_complete.html' | ||||
|  | ||||
|     @method_decorator(csrf_protect) | ||||
|     def dispatch(self, *args, **kwargs): | ||||
|     def get(self, *args, **kwargs): | ||||
|         """ | ||||
|         The dispatch method looks at the request to determine whether it is a GET, POST, etc, | ||||
|         and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed | ||||
|         if not. We chose to check the token in the dispatch method to mimic PasswordReset from | ||||
|         django.contrib.auth | ||||
|         With a given token and user id (in params), validate the email address. | ||||
|         """ | ||||
|         assert 'uidb64' in kwargs and 'token' in kwargs | ||||
|  | ||||
| @@ -84,18 +84,23 @@ class UserValidateView(TemplateView): | ||||
|         user = self.get_user(kwargs['uidb64']) | ||||
|         token = kwargs['token'] | ||||
|  | ||||
|         # Validate the token | ||||
|         if user is not None and email_validation_token.check_token(user, token): | ||||
|             self.validlink = True | ||||
|             # The user must wait that someone validates the account before the user can be active and login. | ||||
|             user.is_active = user.profile.registration_valid | ||||
|             user.profile.email_confirmed = True | ||||
|             user.save() | ||||
|             user.profile.save() | ||||
|             return super().dispatch(*args, **kwargs) | ||||
|         else: | ||||
|             # Display the "Account Activation unsuccessful" page. | ||||
|             # Display the "Email validation unsuccessful" page. | ||||
|             return self.render_to_response(self.get_context_data()) | ||||
|  | ||||
|     def get_user(self, uidb64): | ||||
|         """ | ||||
|         Get user from the base64-encoded string. | ||||
|         """ | ||||
|         try: | ||||
|             # urlsafe_base64_decode() decodes to bytestring | ||||
|             uid = urlsafe_base64_decode(uidb64).decode() | ||||
| @@ -118,16 +123,19 @@ class UserValidateView(TemplateView): | ||||
|  | ||||
|  | ||||
| class UserValidationEmailSentView(TemplateView): | ||||
|     """ | ||||
|     Display the information that the validation link has been sent. | ||||
|     """ | ||||
|     template_name = 'registration/email_validation_email_sent.html' | ||||
|     title = _('Email validation email sent') | ||||
|  | ||||
|  | ||||
| class UserResendValidationEmailView(LoginRequiredMixin, ProtectQuerysetMixin, DetailView): | ||||
|     """ | ||||
|     Rensend the email validation link. | ||||
|     """ | ||||
|     model = User | ||||
|  | ||||
|     def get_queryset(self, **kwargs): | ||||
|         return super().get_queryset(**kwargs).filter(profile__email_confirmed=False) | ||||
|  | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         user = self.get_object() | ||||
|  | ||||
| @@ -139,14 +147,35 @@ class UserResendValidationEmailView(LoginRequiredMixin, ProtectQuerysetMixin, De | ||||
|  | ||||
| class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|     """ | ||||
|     Affiche la liste des utilisateurs, avec une fonction de recherche statique | ||||
|     Display pre-registered users, with a search bar | ||||
|     """ | ||||
|     model = User | ||||
|     table_class = FutureUserTable | ||||
|     template_name = 'registration/future_user_list.html' | ||||
|  | ||||
|     def get_queryset(self, **kwargs): | ||||
|         return super().get_queryset().filter(profile__registration_valid=False) | ||||
|         """ | ||||
|         Filter the table with the given parameter. | ||||
|         :param kwargs: | ||||
|         :return: | ||||
|         """ | ||||
|         qs = super().get_queryset().filter(profile__registration_valid=False) | ||||
|         if "search" in self.request.GET: | ||||
|             pattern = self.request.GET["search"] | ||||
|  | ||||
|             if not pattern: | ||||
|                 return qs.none() | ||||
|  | ||||
|             qs = qs.filter( | ||||
|                 Q(first_name__iregex=pattern) | ||||
|                 | Q(last_name__iregex=pattern) | ||||
|                 | Q(profile__section__iregex=pattern) | ||||
|                 | Q(username__iregex="^" + pattern) | ||||
|             ) | ||||
|         else: | ||||
|             qs = qs.none() | ||||
|  | ||||
|         return qs[:20] | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         context = super().get_context_data(**kwargs) | ||||
| @@ -158,7 +187,7 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi | ||||
|  | ||||
| class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, FormView): | ||||
|     """ | ||||
|     Affiche les informations sur un utilisateur, sa note, ses clubs... | ||||
|     Display information about a pre-registered user, in order to complete the registration. | ||||
|     """ | ||||
|     model = User | ||||
|     form_class = ValidationForm | ||||
| @@ -194,6 +223,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|     def form_valid(self, form): | ||||
|         user = self.object = self.get_object() | ||||
|  | ||||
|         # Get form data | ||||
|         soge = form.cleaned_data["soge"] | ||||
|         credit_type = form.cleaned_data["credit_type"] | ||||
|         credit_amount = form.cleaned_data["credit_amount"] | ||||
| @@ -204,6 +234,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|         join_Kfet = form.cleaned_data["join_Kfet"] | ||||
|  | ||||
|         if soge: | ||||
|             # If Société Générale pays the inscription, the user joins the two clubs | ||||
|             join_BDE = True | ||||
|             join_Kfet = True | ||||
|  | ||||
| @@ -218,6 +249,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|             fee += kfet_fee | ||||
|  | ||||
|         if soge: | ||||
|             # Fill payment information if Société Générale pays the inscription | ||||
|             credit_type = NoteSpecial.objects.get(special_type="Virement bancaire") | ||||
|             credit_amount = fee | ||||
|             bank = "Société générale" | ||||
| @@ -226,6 +258,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|             form.add_error('join_Kfet', _("You must join BDE club before joining Kfet club.")) | ||||
|  | ||||
|         if fee > credit_amount: | ||||
|             # Check if the user credits enough money | ||||
|             form.add_error('credit_type', | ||||
|                            _("The entered amount is not enough for the memberships, should be at least {}") | ||||
|                            .format(pretty_money(fee))) | ||||
| @@ -241,14 +274,18 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|                     form.add_error('bank', _("This field is required.")) | ||||
|                 return self.form_invalid(form) | ||||
|  | ||||
|         # Save the user and finally validate the registration | ||||
|         # Saving the user creates the associated note | ||||
|         ret = super().form_valid(form) | ||||
|         user.is_active = user.profile.email_confirmed | ||||
|         user.profile.registration_valid = True | ||||
|         # Store if Société générale paid for next years | ||||
|         user.profile.soge = soge | ||||
|         user.save() | ||||
|         user.profile.save() | ||||
|  | ||||
|         if credit_type is not None and credit_amount > 0: | ||||
|             # Credit the note | ||||
|             SpecialTransaction.objects.create( | ||||
|                 source=credit_type, | ||||
|                 destination=user.note, | ||||
| @@ -262,6 +299,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|             ) | ||||
|  | ||||
|         if join_BDE: | ||||
|             # Create membership for the user to the BDE starting today | ||||
|             membership = Membership.objects.create( | ||||
|                 club=bde, | ||||
|                 user=user, | ||||
| @@ -271,6 +309,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|             membership.save() | ||||
|  | ||||
|         if join_Kfet: | ||||
|             # Create membership for the user to the Kfet starting today | ||||
|             membership = Membership.objects.create( | ||||
|                 club=kfet, | ||||
|                 user=user, | ||||
| @@ -287,10 +326,13 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, | ||||
|  | ||||
| class FutureUserInvalidateView(ProtectQuerysetMixin, LoginRequiredMixin, View): | ||||
|     """ | ||||
|     Affiche les informations sur un utilisateur, sa note, ses clubs... | ||||
|     Delete a pre-registered user. | ||||
|     """ | ||||
|  | ||||
|     def dispatch(self, request, *args, **kwargs): | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         """ | ||||
|         Delete the pre-registered user which id is given in the URL. | ||||
|         """ | ||||
|         user = User.objects.filter(profile__registration_valid=False)\ | ||||
|             .filter(PermissionBackend.filter_queryset(request.user, User, "change", "is_valid"))\ | ||||
|             .get(pk=self.kwargs["pk"]) | ||||
|   | ||||
| @@ -1267,7 +1267,7 @@ msgid "New user" | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/registration/future_user_list.html:17 | ||||
| msgid "There is no pending user." | ||||
| msgid "There is no pending user with this pattern." | ||||
| msgstr "" | ||||
|  | ||||
| #: templates/registration/logged_out.html:8 | ||||
|   | ||||
| @@ -1274,8 +1274,8 @@ msgid "New user" | ||||
| msgstr "Nouvel utilisateur" | ||||
|  | ||||
| #: templates/registration/future_user_list.html:17 | ||||
| msgid "There is no pending user." | ||||
| msgstr "Il n'y a pas d'inscription en attente." | ||||
| msgid "There is no pending user with this pattern." | ||||
| msgstr "Il n'y a pas d'inscription en attente avec cette entrée." | ||||
|  | ||||
| #: templates/registration/logged_out.html:8 | ||||
| msgid "Thanks for spending some quality time with the Web site today." | ||||
|   | ||||
| @@ -28,7 +28,6 @@ function reset() { | ||||
| } | ||||
|  | ||||
| $(document).ready(function() { | ||||
|     console.log(42); | ||||
|     autoCompleteNote("source_note", "source_alias_matched", "source_note_list", sources, sources_notes_display, | ||||
|         "source_alias", "source_note", "user_note", "profile_pic"); | ||||
|     autoCompleteNote("dest_note", "dest_alias_matched", "dest_note_list", dests, dests_notes_display, | ||||
| @@ -72,7 +71,6 @@ $(document).ready(function() { | ||||
|     $("label[for='type_credit']").attr('class', 'btn btn-sm btn-outline-primary'); | ||||
|     $("label[for='type_debit']").attr('class', 'btn btn-sm btn-outline-primary'); | ||||
|  | ||||
|     console.log("#type_" + location.hash.substr(1)); | ||||
|     if (location.hash) | ||||
|         $("#type_" + location.hash.substr(1)).click(); | ||||
|     else | ||||
|   | ||||
| @@ -118,7 +118,6 @@ | ||||
|     }); | ||||
|  | ||||
|     $("#validate_activity").click(function () { | ||||
|         console.log(42); | ||||
|         $.ajax({ | ||||
|             url: "/api/activity/activity/{{ activity.pk }}/", | ||||
|             type: "PATCH", | ||||
|   | ||||
| @@ -36,7 +36,6 @@ function getInfo() { | ||||
|     if (asked.length >= 1) { | ||||
|         $.getJSON("/api/members/club/?format=json&search="+asked, function(buttons){ | ||||
|             let selected_id = buttons.results.map((a => "#row-"+a.id)); | ||||
|             console.log(selected_id.join()); | ||||
|             $(".table-row,"+selected_id.join()).show(); | ||||
|             $(".table-row").not(selected_id.join()).hide(); | ||||
|              | ||||
|   | ||||
| @@ -7,7 +7,13 @@ | ||||
|     <hr> | ||||
|  | ||||
|     <div id="user_table"> | ||||
|         {% render_table table %} | ||||
|         {% if table.data %} | ||||
|             {% render_table table %} | ||||
|         {% else %} | ||||
|             <div class="alert alert-warning"> | ||||
|                 {% trans "There is no pending user with this pattern." %} | ||||
|             </div> | ||||
|         {% endif %} | ||||
|     </div> | ||||
|  | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -37,7 +37,6 @@ function getInfo() { | ||||
|     if (asked.length >= 1) { | ||||
|         $.getJSON("/api/note/transaction/template/?format=json&search="+asked, function(buttons){ | ||||
|             let selected_id = buttons.results.map((a => "#row-"+a.id)); | ||||
|             console.log(selected_id.join()); | ||||
|             $(".table-row,"+selected_id.join()).show(); | ||||
|             $(".table-row").not(selected_id.join()).hide(); | ||||
|              | ||||
|   | ||||
| @@ -5,24 +5,49 @@ | ||||
|  | ||||
| {% block content %} | ||||
|     <a href="{% url 'registration:signup' %}"><button class="btn btn-primary btn-block">{% trans "New user" %}</button></a> | ||||
|  | ||||
|     <hr> | ||||
|     <input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note/section ..."> | ||||
|     <hr> | ||||
|  | ||||
|     {% if table.data %} | ||||
|         <div id="user_table"> | ||||
|     <div id="user_table"> | ||||
|         {% if table.data %} | ||||
|             {% render_table table %} | ||||
|         </div> | ||||
|     {% else %} | ||||
|         <div class="alert alert-warning"> | ||||
|             {% trans "There is no pending user." %} | ||||
|         </div> | ||||
|     {% endif %} | ||||
|         {% else %} | ||||
|             <div class="alert alert-warning"> | ||||
|                 {% trans "There is no pending user with this pattern." %} | ||||
|             </div> | ||||
|         {% endif %} | ||||
|     </div> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block extrajavascript %} | ||||
| <script type="text/javascript"> | ||||
|     $(".table-row").click(function() { | ||||
|         window.document.location = $(this).data("href"); | ||||
|     $(document).ready(function() { | ||||
|         let old_pattern = null; | ||||
|         let searchbar_obj = $("#searchbar"); | ||||
|  | ||||
|         function reloadTable() { | ||||
|             let pattern = searchbar_obj.val(); | ||||
|  | ||||
|             if (pattern === old_pattern || pattern === "") | ||||
|                 return; | ||||
|  | ||||
|             $("#user_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #user_table", init); | ||||
|  | ||||
|             $(".table-row").click(function() { | ||||
|                 window.document.location = $(this).data("href"); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         searchbar_obj.keyup(reloadTable); | ||||
|  | ||||
|         function init() { | ||||
|             $(".table-row").click(function() { | ||||
|                 window.document.location = $(this).data("href"); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         init(); | ||||
|     }); | ||||
| </script> | ||||
| {% endblock %} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user