diff --git a/apps/activity/admin.py b/apps/activity/admin.py index 5ceb4e81..0529d306 100644 --- a/apps/activity/admin.py +++ b/apps/activity/admin.py @@ -11,7 +11,7 @@ class ActivityAdmin(admin.ModelAdmin): Admin customisation for Activity """ list_display = ('name', 'activity_type', 'organizer') - list_filter = ('activity_type', ) + list_filter = ('activity_type',) search_fields = ['name', 'organizer__name'] # Organize activities by start date diff --git a/apps/activity/api/serializers.py b/apps/activity/api/serializers.py index 0b9302f1..514515ef 100644 --- a/apps/activity/api/serializers.py +++ b/apps/activity/api/serializers.py @@ -11,6 +11,7 @@ class ActivityTypeSerializer(serializers.ModelSerializer): REST API Serializer for Activity types. The djangorestframework plugin will analyse the model `ActivityType` and parse all fields in the API. """ + class Meta: model = ActivityType fields = '__all__' @@ -21,6 +22,7 @@ class ActivitySerializer(serializers.ModelSerializer): REST API Serializer for Activities. The djangorestframework plugin will analyse the model `Activity` and parse all fields in the API. """ + class Meta: model = Activity fields = '__all__' @@ -31,6 +33,7 @@ class GuestSerializer(serializers.ModelSerializer): REST API Serializer for Guests. The djangorestframework plugin will analyse the model `Guest` and parse all fields in the API. """ + class Meta: model = Guest fields = '__all__' diff --git a/apps/activity/api/views.py b/apps/activity/api/views.py index 5683d458..6a6c024e 100644 --- a/apps/activity/api/views.py +++ b/apps/activity/api/views.py @@ -3,8 +3,8 @@ from rest_framework import viewsets -from ..models import ActivityType, Activity, Guest from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer +from ..models import ActivityType, Activity, Guest class ActivityTypeViewSet(viewsets.ModelViewSet): diff --git a/apps/api/urls.py b/apps/api/urls.py index 7e59a8c0..c1b6bf48 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -14,6 +14,7 @@ class UserSerializer(serializers.ModelSerializer): REST API Serializer for Users. The djangorestframework plugin will analyse the model `User` and parse all fields in the API. """ + class Meta: model = User exclude = ( diff --git a/apps/logs/models.py b/apps/logs/models.py index 337315bb..1018ce72 100644 --- a/apps/logs/models.py +++ b/apps/logs/models.py @@ -1,11 +1,11 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext_lazy as _ from django.conf import settings +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import models +from django.utils.translation import gettext_lazy as _ class Changelog(models.Model): diff --git a/apps/logs/signals.py b/apps/logs/signals.py index 13194e5b..415e7c1c 100644 --- a/apps/logs/signals.py +++ b/apps/logs/signals.py @@ -7,6 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.core import serializers from django.db.models.signals import pre_save, post_save, post_delete from django.dispatch import receiver + from .models import Changelog @@ -43,20 +44,20 @@ def get_user_and_ip(sender): EXCLUDED = [ - 'admin.logentry', - 'authtoken.token', - 'cas_server.user', - 'cas_server.userattributes', - 'contenttypes.contenttype', - 'logs.changelog', - 'migrations.migration', - 'note.noteuser', - 'note.noteclub', - 'note.notespecial', - 'sessions.session', - 'reversion.revision', - 'reversion.version', - ] + 'admin.logentry', + 'authtoken.token', + 'cas_server.user', + 'cas_server.userattributes', + 'contenttypes.contenttype', + 'logs.changelog', + 'migrations.migration', + 'note.noteuser', + 'note.noteclub', + 'note.notespecial', + 'sessions.session', + 'reversion.revision', + 'reversion.version', +] @receiver(pre_save) diff --git a/apps/member/admin.py b/apps/member/admin.py index fb107377..c7c3ead3 100644 --- a/apps/member/admin.py +++ b/apps/member/admin.py @@ -18,9 +18,9 @@ class ProfileInline(admin.StackedInline): class CustomUserAdmin(UserAdmin): - inlines = (ProfileInline, ) + inlines = (ProfileInline,) list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') - list_select_related = ('profile', ) + list_select_related = ('profile',) form = ProfileForm def get_inline_instances(self, request, obj=None): diff --git a/apps/member/api/serializers.py b/apps/member/api/serializers.py index f4df6799..962841ae 100644 --- a/apps/member/api/serializers.py +++ b/apps/member/api/serializers.py @@ -11,6 +11,7 @@ class ProfileSerializer(serializers.ModelSerializer): REST API Serializer for Profiles. The djangorestframework plugin will analyse the model `Profile` and parse all fields in the API. """ + class Meta: model = Profile fields = '__all__' @@ -21,6 +22,7 @@ class ClubSerializer(serializers.ModelSerializer): REST API Serializer for Clubs. The djangorestframework plugin will analyse the model `Club` and parse all fields in the API. """ + class Meta: model = Club fields = '__all__' @@ -31,6 +33,7 @@ class RoleSerializer(serializers.ModelSerializer): REST API Serializer for Roles. The djangorestframework plugin will analyse the model `Role` and parse all fields in the API. """ + class Meta: model = Role fields = '__all__' @@ -41,6 +44,7 @@ class MembershipSerializer(serializers.ModelSerializer): REST API Serializer for Memberships. The djangorestframework plugin will analyse the model `Memberships` and parse all fields in the API. """ + class Meta: model = Membership fields = '__all__' diff --git a/apps/member/api/views.py b/apps/member/api/views.py index 79ba4c12..7e7dcd1d 100644 --- a/apps/member/api/views.py +++ b/apps/member/api/views.py @@ -3,8 +3,8 @@ from rest_framework import viewsets -from ..models import Profile, Club, Role, Membership from .serializers import ProfileSerializer, ClubSerializer, RoleSerializer, MembershipSerializer +from ..models import Profile, Club, Role, Membership class ProfileViewSet(viewsets.ModelViewSet): diff --git a/apps/member/filters.py b/apps/member/filters.py index 418e52fc..951723e8 100644 --- a/apps/member/filters.py +++ b/apps/member/filters.py @@ -1,11 +1,11 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django_filters import FilterSet, CharFilter -from django.contrib.auth.models import User -from django.db.models import CharField from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Submit +from django.contrib.auth.models import User +from django.db.models import CharField +from django_filters import FilterSet, CharFilter class UserFilter(FilterSet): diff --git a/apps/member/forms.py b/apps/member/forms.py index abb35cd9..d2134cdd 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -1,23 +1,22 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from crispy_forms.bootstrap import Div +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Layout from dal import autocomplete +from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User -from django import forms from .models import Profile, Club, Membership -from crispy_forms.helper import FormHelper -from crispy_forms.bootstrap import Div -from crispy_forms.layout import Layout - class SignUpForm(UserCreationForm): - def __init__(self,*args,**kwargs): - super().__init__(*args,**kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.fields['username'].widget.attrs.pop("autofocus", None) - self.fields['first_name'].widget.attrs.update({"autofocus":"autofocus"}) + self.fields['first_name'].widget.attrs.update({"autofocus": "autofocus"}) class Meta: model = User @@ -28,6 +27,7 @@ class ProfileForm(forms.ModelForm): """ A form for the extras field provided by the :model:`member.Profile` model. """ + class Meta: model = Profile fields = '__all__' @@ -42,7 +42,7 @@ class ClubForm(forms.ModelForm): class AddMembersForm(forms.Form): class Meta: - fields = ('', ) + fields = ('',) class MembershipForm(forms.ModelForm): @@ -54,13 +54,13 @@ class MembershipForm(forms.ModelForm): # et récupère les noms d'utilisateur valides widgets = { 'user': - autocomplete.ModelSelect2( - url='member:user_autocomplete', - attrs={ - 'data-placeholder': 'Nom ...', - 'data-minimum-input-length': 1, - }, - ), + autocomplete.ModelSelect2( + url='member:user_autocomplete', + attrs={ + 'data-placeholder': 'Nom ...', + 'data-minimum-input-length': 1, + }, + ), } diff --git a/apps/member/models.py b/apps/member/models.py index cd754bd8..50b0bea1 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -3,8 +3,8 @@ from django.conf import settings from django.db import models -from django.utils.translation import gettext_lazy as _ from django.urls import reverse, reverse_lazy +from django.utils.translation import gettext_lazy as _ class Profile(models.Model): @@ -48,7 +48,7 @@ class Profile(models.Model): verbose_name_plural = _('user profile') def get_absolute_url(self): - return reverse('user_detail', args=(self.pk, )) + return reverse('user_detail', args=(self.pk,)) class Club(models.Model): @@ -97,7 +97,7 @@ class Club(models.Model): return self.name def get_absolute_url(self): - return reverse_lazy('member:club_detail', args=(self.pk, )) + return reverse_lazy('member:club_detail', args=(self.pk,)) class Role(models.Model): @@ -153,7 +153,6 @@ class Membership(models.Model): verbose_name = _('membership') verbose_name_plural = _('memberships') - # @receiver(post_save, sender=settings.AUTH_USER_MODEL) # def save_user_profile(instance, created, **_kwargs): # """ diff --git a/apps/member/signals.py b/apps/member/signals.py index b17b3ae8..2b03e3ce 100644 --- a/apps/member/signals.py +++ b/apps/member/signals.py @@ -1,6 +1,7 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later + def save_user_profile(instance, created, raw, **_kwargs): """ Hook to create and save a profile when an user is updated if it is not registered with the signup form diff --git a/apps/member/views.py b/apps/member/views.py index d4bbc592..88bd2678 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -1,33 +1,33 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import redirect -from django.utils.translation import gettext_lazy as _ -from django.views.generic import CreateView, DetailView, UpdateView, TemplateView,DeleteView -from django.views.generic.edit import FormMixin -from django.contrib.auth.models import User -from django.contrib import messages -from django.urls import reverse_lazy -from django.http import HttpResponseRedirect -from django.db.models import Q -from django.core.exceptions import ValidationError -from django.conf import settings -from django_tables2.views import SingleTableView -from rest_framework.authtoken.models import Token -from dal import autocomplete -from PIL import Image import io +from PIL import Image +from dal import autocomplete +from django.conf import settings +from django.contrib import messages +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.http import HttpResponseRedirect +from django.shortcuts import redirect +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ +from django.views.generic import CreateView, DetailView, UpdateView, TemplateView, DeleteView +from django.views.generic.edit import FormMixin +from django_tables2.views import SingleTableView +from rest_framework.authtoken.models import Token +from note.forms import AliasForm, ImageForm from note.models import Alias, NoteUser from note.models.transactions import Transaction from note.tables import HistoryTable, AliasTable -from note.forms import AliasForm, ImageForm -from .models import Profile, Club, Membership -from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper -from .tables import ClubTable, UserTable from .filters import UserFilter, UserFilterFormHelper +from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper +from .models import Club, Membership +from .tables import ClubTable, UserTable class UserCreateView(CreateView): @@ -109,7 +109,7 @@ class UserUpdateView(LoginRequiredMixin, UpdateView): return reverse_lazy('member:user_detail', kwargs={'pk': kwargs['id']}) else: - return reverse_lazy('member:user_detail', args=(self.object.id, )) + return reverse_lazy('member:user_detail', args=(self.object.id,)) class UserDetailView(LoginRequiredMixin, DetailView): @@ -157,13 +157,14 @@ class UserListView(LoginRequiredMixin, SingleTableView): context["filter"] = self.filter return context -class AliasView(LoginRequiredMixin,FormMixin,DetailView): + +class AliasView(LoginRequiredMixin, FormMixin, DetailView): model = User template_name = 'member/profile_alias.html' context_object_name = 'user_object' form_class = AliasForm - def get_context_data(self,**kwargs): + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) note = context['user_object'].note context["aliases"] = AliasTable(note.alias_set.all()) @@ -172,7 +173,7 @@ class AliasView(LoginRequiredMixin,FormMixin,DetailView): def get_success_url(self): return reverse_lazy('member:user_alias', kwargs={'pk': self.object.id}) - def post(self,request,*args,**kwargs): + def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.get_form() if form.is_valid(): @@ -186,42 +187,45 @@ class AliasView(LoginRequiredMixin,FormMixin,DetailView): alias.save() return super().form_valid(form) + class DeleteAliasView(LoginRequiredMixin, DeleteView): model = Alias - def delete(self,request,*args,**kwargs): + def delete(self, request, *args, **kwargs): try: self.object = self.get_object() self.object.delete() except ValidationError as e: # TODO: pass message to redirected view. - messages.error(self.request,str(e)) + messages.error(self.request, str(e)) else: - messages.success(self.request,_("Alias successfully deleted")) + messages.success(self.request, _("Alias successfully deleted")) return HttpResponseRedirect(self.get_success_url()) - + def get_success_url(self): print(self.request) - return reverse_lazy('member:user_alias',kwargs={'pk':self.object.note.user.pk}) + return reverse_lazy('member:user_alias', kwargs={'pk': self.object.note.user.pk}) def get(self, request, *args, **kwargs): return self.post(request, *args, **kwargs) + class ProfilePictureUpdateView(LoginRequiredMixin, FormMixin, DetailView): model = User template_name = 'member/profile_picture_update.html' context_object_name = 'user_object' form_class = ImageForm - def get_context_data(self,*args,**kwargs): - context = super().get_context_data(*args,**kwargs) - context['form'] = self.form_class(self.request.POST,self.request.FILES) + + def get_context_data(self, *args, **kwargs): + context = super().get_context_data(*args, **kwargs) + context['form'] = self.form_class(self.request.POST, self.request.FILES) return context - + def get_success_url(self): return reverse_lazy('member:user_detail', kwargs={'pk': self.object.id}) - def post(self,request,*args,**kwargs): - form = self.get_form() + def post(self, request, *args, **kwargs): + form = self.get_form() self.object = self.get_object() if form.is_valid(): return self.form_valid(form) @@ -230,7 +234,7 @@ class ProfilePictureUpdateView(LoginRequiredMixin, FormMixin, DetailView): print(form) return self.form_invalid(form) - def form_valid(self,form): + def form_valid(self, form): image_field = form.cleaned_data['image'] x = form.cleaned_data['x'] y = form.cleaned_data['y'] @@ -238,15 +242,15 @@ class ProfilePictureUpdateView(LoginRequiredMixin, FormMixin, DetailView): h = form.cleaned_data['height'] # image crop and resize image_file = io.BytesIO(image_field.read()) - ext = image_field.name.split('.')[-1].lower() - #TODO: support GIF format + # ext = image_field.name.split('.')[-1].lower() + # TODO: support GIF format image = Image.open(image_file) - image = image.crop((x, y, x+w, y+h)) + image = image.crop((x, y, x + w, y + h)) image_clean = image.resize((settings.PIC_WIDTH, - settings.PIC_RATIO*settings.PIC_WIDTH), - Image.ANTIALIAS) + settings.PIC_RATIO * settings.PIC_WIDTH), + Image.ANTIALIAS) image_file = io.BytesIO() - image_clean.save(image_file,"PNG") + image_clean.save(image_file, "PNG") image_field.file = image_file # renaming filename = "{}_pic.png".format(self.object.note.pk) @@ -255,7 +259,7 @@ class ProfilePictureUpdateView(LoginRequiredMixin, FormMixin, DetailView): self.object.note.save() return super().form_valid(form) - + class ManageAuthTokens(LoginRequiredMixin, TemplateView): """ Affiche le jeton d'authentification, et permet de le regénérer @@ -283,6 +287,7 @@ class UserAutocomplete(autocomplete.Select2QuerySetView): """ Auto complete users by usernames """ + def get_queryset(self): """ Quand une personne cherche un utilisateur par pseudo, une requête est envoyée sur l'API dédiée à l'auto-complétion. @@ -331,7 +336,7 @@ class ClubDetailView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) club = context["club"] - club_transactions = \ + club_transactions = \ Transaction.objects.all().filter(Q(source=club.note) | Q(destination=club.note)) context['history_list'] = HistoryTable(club_transactions) club_member = \ diff --git a/apps/note/admin.py b/apps/note/admin.py index 52c1cc17..a0928641 100644 --- a/apps/note/admin.py +++ b/apps/note/admin.py @@ -47,11 +47,11 @@ class NoteClubAdmin(PolymorphicChildModelAdmin): """ Child for a club note, see NoteAdmin """ - inlines = (AliasInlines, ) + inlines = (AliasInlines,) # We can't change club after creation or the balance readonly_fields = ('club', 'balance') - search_fields = ('club', ) + search_fields = ('club',) def has_add_permission(self, request): """ @@ -71,7 +71,7 @@ class NoteSpecialAdmin(PolymorphicChildModelAdmin): """ Child for a special note, see NoteAdmin """ - readonly_fields = ('balance', ) + readonly_fields = ('balance',) @admin.register(NoteUser) @@ -79,7 +79,7 @@ class NoteUserAdmin(PolymorphicChildModelAdmin): """ Child for an user note, see NoteAdmin """ - inlines = (AliasInlines, ) + inlines = (AliasInlines,) # We can't change user after creation or the balance readonly_fields = ('user', 'balance') @@ -133,7 +133,7 @@ class TransactionAdmin(PolymorphicParentModelAdmin): Else the amount of money would not be transferred """ if obj: # user is editing an existing object - return 'created_at', 'source', 'destination', 'quantity',\ + return 'created_at', 'source', 'destination', 'quantity', \ 'amount' return [] @@ -143,9 +143,9 @@ class TransactionTemplateAdmin(admin.ModelAdmin): """ Admin customisation for TransactionTemplate """ - list_display = ('name', 'poly_destination', 'amount', 'category', 'display', ) + list_display = ('name', 'poly_destination', 'amount', 'category', 'display',) list_filter = ('category', 'display') - autocomplete_fields = ('destination', ) + autocomplete_fields = ('destination',) def poly_destination(self, obj): """ @@ -161,5 +161,5 @@ class TemplateCategoryAdmin(admin.ModelAdmin): """ Admin customisation for TransactionTemplate """ - list_display = ('name', ) - list_filter = ('name', ) + list_display = ('name',) + list_filter = ('name',) diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py index db0e3531..1696bfee 100644 --- a/apps/note/api/serializers.py +++ b/apps/note/api/serializers.py @@ -13,6 +13,7 @@ class NoteSerializer(serializers.ModelSerializer): REST API Serializer for Notes. The djangorestframework plugin will analyse the model `Note` and parse all fields in the API. """ + class Meta: model = Note fields = '__all__' @@ -29,6 +30,7 @@ class NoteClubSerializer(serializers.ModelSerializer): REST API Serializer for Club's notes. The djangorestframework plugin will analyse the model `NoteClub` and parse all fields in the API. """ + class Meta: model = NoteClub fields = '__all__' @@ -39,6 +41,7 @@ class NoteSpecialSerializer(serializers.ModelSerializer): REST API Serializer for special notes. The djangorestframework plugin will analyse the model `NoteSpecial` and parse all fields in the API. """ + class Meta: model = NoteSpecial fields = '__all__' @@ -49,6 +52,7 @@ class NoteUserSerializer(serializers.ModelSerializer): REST API Serializer for User's notes. The djangorestframework plugin will analyse the model `NoteUser` and parse all fields in the API. """ + class Meta: model = NoteUser fields = '__all__' @@ -59,6 +63,7 @@ class AliasSerializer(serializers.ModelSerializer): REST API Serializer for Aliases. The djangorestframework plugin will analyse the model `Alias` and parse all fields in the API. """ + class Meta: model = Alias fields = '__all__' @@ -78,6 +83,7 @@ class TransactionTemplateSerializer(serializers.ModelSerializer): REST API Serializer for Transaction templates. The djangorestframework plugin will analyse the model `TransactionTemplate` and parse all fields in the API. """ + class Meta: model = TransactionTemplate fields = '__all__' @@ -88,6 +94,7 @@ class TransactionSerializer(serializers.ModelSerializer): REST API Serializer for Transactions. The djangorestframework plugin will analyse the model `Transaction` and parse all fields in the API. """ + class Meta: model = Transaction fields = '__all__' @@ -98,6 +105,7 @@ class MembershipTransactionSerializer(serializers.ModelSerializer): REST API Serializer for Membership transactions. The djangorestframework plugin will analyse the model `MembershipTransaction` and parse all fields in the API. """ + class Meta: model = MembershipTransaction fields = '__all__' diff --git a/apps/note/api/views.py b/apps/note/api/views.py index 94b4a47a..cf0136f2 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -4,11 +4,11 @@ from django.db.models import Q from rest_framework import viewsets -from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias -from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction from .serializers import NoteSerializer, NotePolymorphicSerializer, NoteClubSerializer, NoteSpecialSerializer, \ NoteUserSerializer, AliasSerializer, \ TransactionTemplateSerializer, TransactionSerializer, MembershipTransactionSerializer +from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias +from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction class NoteViewSet(viewsets.ModelViewSet): diff --git a/apps/note/forms.py b/apps/note/forms.py index 819ed97a..07e44206 100644 --- a/apps/note/forms.py +++ b/apps/note/forms.py @@ -3,31 +3,25 @@ from dal import autocomplete from django import forms -from django.conf import settings from django.utils.translation import gettext_lazy as _ -import os - -from crispy_forms.helper import FormHelper -from crispy_forms.bootstrap import Div -from crispy_forms.layout import Layout, HTML - +from .models import Alias from .models import Transaction, TransactionTemplate, TemplateTransaction -from .models import Note, Alias + class AliasForm(forms.ModelForm): class Meta: model = Alias fields = ("name",) - def __init__(self,*args,**kwargs): - super().__init__(*args,**kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.fields["name"].label = False - self.fields["name"].widget.attrs={"placeholder":_('New Alias')} - + self.fields["name"].widget.attrs = {"placeholder": _('New Alias')} + class ImageForm(forms.Form): - image = forms.ImageField(required = False, + image = forms.ImageField(required=False, label=_('select an image'), help_text=_('Maximal size: 2MB')) x = forms.FloatField(widget=forms.HiddenInput()) @@ -35,7 +29,7 @@ class ImageForm(forms.Form): width = forms.FloatField(widget=forms.HiddenInput()) height = forms.FloatField(widget=forms.HiddenInput()) - + class TransactionTemplateForm(forms.ModelForm): class Meta: model = TransactionTemplate @@ -48,13 +42,13 @@ class TransactionTemplateForm(forms.ModelForm): # forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special} widgets = { 'destination': - autocomplete.ModelSelect2( - url='note:note_autocomplete', - attrs={ - 'data-placeholder': 'Note ...', - 'data-minimum-input-length': 1, - }, - ), + autocomplete.ModelSelect2( + url='note:note_autocomplete', + attrs={ + 'data-placeholder': 'Note ...', + 'data-minimum-input-length': 1, + }, + ), } @@ -62,7 +56,6 @@ class TransactionForm(forms.ModelForm): def save(self, commit=True): super().save(commit) - def clean(self): """ If the user has no right to transfer funds, then it will be the source of the transfer by default. @@ -70,7 +63,7 @@ class TransactionForm(forms.ModelForm): """ cleaned_data = super().clean() - if not "source" in cleaned_data: # TODO Replace it with "if %user has no right to transfer funds" + if "source" not in cleaned_data: # TODO Replace it with "if %user has no right to transfer funds" cleaned_data["source"] = self.user.note if cleaned_data["source"].pk == cleaned_data["destination"].pk: @@ -78,7 +71,6 @@ class TransactionForm(forms.ModelForm): return cleaned_data - class Meta: model = Transaction fields = ( @@ -91,21 +83,21 @@ class TransactionForm(forms.ModelForm): # Voir ci-dessus widgets = { 'source': - autocomplete.ModelSelect2( - url='note:note_autocomplete', - attrs={ - 'data-placeholder': 'Note ...', - 'data-minimum-input-length': 1, - }, - ), + autocomplete.ModelSelect2( + url='note:note_autocomplete', + attrs={ + 'data-placeholder': 'Note ...', + 'data-minimum-input-length': 1, + }, + ), 'destination': - autocomplete.ModelSelect2( - url='note:note_autocomplete', - attrs={ - 'data-placeholder': 'Note ...', - 'data-minimum-input-length': 1, - }, - ), + autocomplete.ModelSelect2( + url='note:note_autocomplete', + attrs={ + 'data-placeholder': 'Note ...', + 'data-minimum-input-length': 1, + }, + ), } @@ -122,18 +114,18 @@ class ConsoForm(forms.ModelForm): class Meta: model = TemplateTransaction - fields = ('source', ) + fields = ('source',) # Le champ d'utilisateur est remplacé par un champ d'auto-complétion. # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion # et récupère les aliases de note valides widgets = { 'source': - autocomplete.ModelSelect2( - url='note:note_autocomplete', - attrs={ - 'data-placeholder': 'Note ...', - 'data-minimum-input-length': 1, - }, - ), + autocomplete.ModelSelect2( + url='note:note_autocomplete', + attrs={ + 'data-placeholder': 'Note ...', + 'data-minimum-input-length': 1, + }, + ), } diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py index 4b06c93a..74cda3ea 100644 --- a/apps/note/models/notes.py +++ b/apps/note/models/notes.py @@ -9,6 +9,7 @@ from django.core.validators import RegexValidator from django.db import models from django.utils.translation import gettext_lazy as _ from polymorphic.models import PolymorphicModel + """ Defines each note types """ @@ -27,7 +28,7 @@ class Note(PolymorphicModel): help_text=_('in centimes, money credited for this instance'), default=0, ) - last_negative= models.DateTimeField( + last_negative = models.DateTimeField( verbose_name=_('last negative date'), help_text=_('last time the balance was negative'), null=True, @@ -98,7 +99,7 @@ class Note(PolymorphicModel): # Alias exists, so check if it is linked to this note if aliases.first().note != self: raise ValidationError(_('This alias is already taken.'), - code="same_alias",) + code="same_alias", ) else: # Alias does not exist yet, so check if it can exist a = Alias(name=str(self)) @@ -231,12 +232,12 @@ class Alias(models.Model): sim_alias = Alias.objects.get(normalized_name=normalized_name) if self != sim_alias: raise ValidationError(_('An alias with a similar name already exists: {} '.format(sim_alias)), - code="same_alias" - ) + code="same_alias" + ) except Alias.DoesNotExist: pass self.normalized_name = normalized_name - + def delete(self, using=None, keep_parents=False): if self.name == str(self.note): raise ValidationError(_("You can't delete your main alias."), diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 598c119b..3bb7ca76 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -2,9 +2,9 @@ # SPDX-License-Identifier: GPL-3.0-or-later from django.db import models +from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from django.urls import reverse from polymorphic.models import PolymorphicModel from .notes import Note, NoteClub @@ -44,7 +44,7 @@ class TransactionTemplate(models.Model): verbose_name=_('name'), max_length=255, unique=True, - error_messages={'unique':_("A template with this name already exist")}, + error_messages={'unique': _("A template with this name already exist")}, ) destination = models.ForeignKey( NoteClub, @@ -63,7 +63,7 @@ class TransactionTemplate(models.Model): max_length=31, ) display = models.BooleanField( - default = True, + default=True, ) description = models.CharField( verbose_name=_('description'), @@ -75,7 +75,7 @@ class TransactionTemplate(models.Model): verbose_name_plural = _("transaction templates") def get_absolute_url(self): - return reverse('note:template_update', args=(self.pk, )) + return reverse('note:template_update', args=(self.pk,)) class Transaction(PolymorphicModel): @@ -168,6 +168,7 @@ class TemplateTransaction(Transaction): on_delete=models.PROTECT, ) + class MembershipTransaction(Transaction): """ Special type of :model:`note.Transaction` associated to a :model:`member.Membership`. diff --git a/apps/note/tables.py b/apps/note/tables.py index 20476cb6..9a2dce45 100644 --- a/apps/note/tables.py +++ b/apps/note/tables.py @@ -4,14 +4,16 @@ import django_tables2 as tables from django.db.models import F from django_tables2.utils import A -from .models.transactions import Transaction + from .models.notes import Alias +from .models.transactions import Transaction + class HistoryTable(tables.Table): class Meta: attrs = { 'class': - 'table table-condensed table-striped table-hover' + 'table table-condensed table-striped table-hover' } model = Transaction template_name = 'django_tables2/bootstrap4.html' @@ -25,21 +27,22 @@ class HistoryTable(tables.Table): .order_by(('-' if is_descending else '') + 'total') return (queryset, True) + class AliasTable(tables.Table): class Meta: attrs = { 'class': - 'table table condensed table-striped table-hover' + 'table table condensed table-striped table-hover' } model = Alias - fields =('name',) + fields = ('name',) template_name = 'django_tables2/bootstrap4.html' show_header = False - name = tables.Column(attrs={'td':{'class':'text-center'}}) + name = tables.Column(attrs={'td': {'class': 'text-center'}}) delete = tables.LinkColumn('member:user_alias_delete', args=[A('pk')], attrs={ - 'td': {'class':'col-sm-2'}, - 'a': {'class': 'btn btn-danger'} }, - text='delete',accessor='pk') + 'td': {'class': 'col-sm-2'}, + 'a': {'class': 'btn btn-danger'}}, + text='delete', accessor='pk') diff --git a/apps/note/views.py b/apps/note/views.py index 5038df16..09846057 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -8,8 +8,8 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, ListView, UpdateView -from .models import Transaction, TransactionTemplate, Alias, TemplateTransaction from .forms import TransactionForm, TransactionTemplateForm, ConsoForm +from .models import Transaction, TransactionTemplate, Alias, TemplateTransaction class TransactionCreate(LoginRequiredMixin, CreateView): @@ -53,6 +53,7 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView): """ Auto complete note by aliases """ + def get_queryset(self): """ Quand une personne cherche un alias, une requête est envoyée sur l'API dédiée à l'auto-complétion. @@ -66,7 +67,7 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView): # self.q est le paramètre de la recherche if self.q: - qs = qs.filter(Q(name__regex=self.q) | Q(normalized_name__regex=Alias.normalize(self.q)))\ + qs = qs.filter(Q(name__regex=self.q) | Q(normalized_name__regex=Alias.normalize(self.q))) \ .order_by('normalized_name').distinct() # Filtrage par type de note (user, club, special) @@ -147,4 +148,3 @@ class ConsoView(LoginRequiredMixin, CreateView): When clicking a button, reload the same page """ return reverse('note:consos') - diff --git a/note_kfet/middlewares.py b/note_kfet/middlewares.py index 73b87e36..b034e2be 100644 --- a/note_kfet/middlewares.py +++ b/note_kfet/middlewares.py @@ -1,10 +1,6 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django.http import HttpResponseRedirect - -from urllib.parse import urlencode, parse_qs, urlsplit, urlunsplit - class TurbolinksMiddleware(object): """ @@ -35,4 +31,3 @@ class TurbolinksMiddleware(object): location = request.session.pop('_turbolinks_redirect_to') response['Turbolinks-Location'] = location return response - diff --git a/note_kfet/settings/__init__.py b/note_kfet/settings/__init__.py index 68a40b88..02abcd6e 100644 --- a/note_kfet/settings/__init__.py +++ b/note_kfet/settings/__init__.py @@ -1,8 +1,6 @@ -import os -import re - from .base import * + def read_env(): """Pulled from Honcho code with minor updates, reads local default environment variables from a .env file located in the project root @@ -25,14 +23,16 @@ def read_env(): val = re.sub(r'\\(.)', r'\1', m3.group(1)) os.environ.setdefault(key, val) + read_env() app_stage = os.environ.get('DJANGO_APP_STAGE', 'dev') if app_stage == 'prod': from .production import * - DATABASES["default"]["PASSWORD"] = os.environ.get('DJANGO_DB_PASSWORD','CHANGE_ME_IN_ENV_SETTINGS') - SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY','CHANGE_ME_IN_ENV_SETTINGS') - ALLOWED_HOSTS.append(os.environ.get('ALLOWED_HOSTS','localhost')) + + DATABASES["default"]["PASSWORD"] = os.environ.get('DJANGO_DB_PASSWORD', 'CHANGE_ME_IN_ENV_SETTINGS') + SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'CHANGE_ME_IN_ENV_SETTINGS') + ALLOWED_HOSTS.append(os.environ.get('ALLOWED_HOSTS', 'localhost')) else: from .development import * @@ -43,4 +43,3 @@ except ImportError: # env variables set at the of in /env/bin/activate # don't forget to unset in deactivate ! - diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index 7ab59272..103e368d 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -97,7 +97,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.request', - # 'django.template.context_processors.media', + # 'django.template.context_processors.media', ], }, }, @@ -183,7 +183,7 @@ FIXTURE_DIRS = [os.path.join(BASE_DIR, "note_kfet/fixtures")] # Don't put anything in this directory yourself; store your static files # in apps' "static/" subdirectories and in STATICFILES_DIRS. # Example: "/var/www/example.com/static/" -STATIC_ROOT = os.path.join(BASE_DIR,"static/") +STATIC_ROOT = os.path.join(BASE_DIR, "static/") # STATICFILES_DIRS = [ # os.path.join(BASE_DIR, 'static')] STATICFILES_DIRS = [] @@ -195,8 +195,8 @@ STATIC_URL = '/static/' ALIAS_VALIDATOR_REGEX = r'' -MEDIA_ROOT=os.path.join(BASE_DIR,"media") -MEDIA_URL='/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, "media") +MEDIA_URL = '/media/' # Profile Picture Settings PIC_WIDTH = 200 @@ -211,7 +211,7 @@ CAS_SHOW_POWERED = False CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT = False CAS_INFO_MESSAGES = { "cas_explained": { - "message":_( + "message": _( u"The Central Authentication Service grants you access to most of our websites by " u"authenticating only once, so you don't need to type your credentials again unless " u"your session expires or you logout." @@ -224,4 +224,3 @@ CAS_INFO_MESSAGES = { CAS_INFO_MESSAGES_ORDER = [ 'cas_explained', ] - diff --git a/note_kfet/settings/development.py b/note_kfet/settings/development.py index 83436339..cf738f33 100644 --- a/note_kfet/settings/development.py +++ b/note_kfet/settings/development.py @@ -11,10 +11,11 @@ # - and more ... +import os + # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases from . import * -import os DATABASES = { 'default': { @@ -53,8 +54,6 @@ SESSION_COOKIE_AGE = 60 * 60 * 3 # Can be modified in secrets.py CAS_SERVER_URL = "http://localhost:8000/cas/" - -STATIC_ROOT = '' # not needed in development settings +STATIC_ROOT = '' # not needed in development settings STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static')] - + os.path.join(BASE_DIR, 'static')] diff --git a/note_kfet/settings/production.py b/note_kfet/settings/production.py index 353d7b8a..c595ee1f 100644 --- a/note_kfet/settings/production.py +++ b/note_kfet/settings/production.py @@ -26,7 +26,7 @@ DATABASES = { DEBUG = True # Mandatory ! -ALLOWED_HOSTS = ['127.0.0.1','note.comby.xyz'] +ALLOWED_HOSTS = ['127.0.0.1', 'note.comby.xyz'] # Emails EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/note_kfet/urls.py b/note_kfet/urls.py index a261a9eb..56251955 100644 --- a/note_kfet/urls.py +++ b/note_kfet/urls.py @@ -1,13 +1,12 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from cas import views as cas_views +from django.conf import settings +from django.conf.urls.static import static from django.contrib import admin from django.urls import path, include from django.views.generic import RedirectView -from django.conf.urls.static import static -from django.conf import settings - -from cas import views as cas_views urlpatterns = [ # Dev so redirect to something random @@ -36,5 +35,5 @@ urlpatterns = [ path('logs/', include('logs.urls')), ] -urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) -urlpatterns += static(settings.STATIC_URL,document_root=settings.STATIC_ROOT) +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/templates/cas_server/samlValidate.xml b/templates/cas_server/samlValidate.xml index d61bed11..3b130fd2 100644 --- a/templates/cas_server/samlValidate.xml +++ b/templates/cas_server/samlValidate.xml @@ -1,11 +1,11 @@ - + diff --git a/templates/cas_server/samlValidateError.xml b/templates/cas_server/samlValidateError.xml index b1b4226f..c72daba1 100644 --- a/templates/cas_server/samlValidateError.xml +++ b/templates/cas_server/samlValidateError.xml @@ -1,11 +1,11 @@ - + {{msg}}