mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-20 17:41:55 +02:00
Merge branch 'consos' into rights
# Conflicts: # apps/logs/signals.py # note_kfet/settings/base.py
This commit is contained in:
@ -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):
|
||||
|
@ -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__'
|
||||
|
@ -2,9 +2,10 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.filters import SearchFilter
|
||||
|
||||
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):
|
||||
@ -25,6 +26,8 @@ class ClubViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
queryset = Club.objects.all()
|
||||
serializer_class = ClubSerializer
|
||||
filter_backends = [SearchFilter]
|
||||
search_fields = ['$name', ]
|
||||
|
||||
|
||||
class RoleViewSet(viewsets.ModelViewSet):
|
||||
@ -35,6 +38,8 @@ class RoleViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
queryset = Role.objects.all()
|
||||
serializer_class = RoleSerializer
|
||||
filter_backends = [SearchFilter]
|
||||
search_fields = ['$name', ]
|
||||
|
||||
|
||||
class MembershipViewSet(viewsets.ModelViewSet):
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,8 +5,8 @@ import datetime
|
||||
|
||||
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,9 +48,10 @@ class Profile(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _('user profile')
|
||||
verbose_name_plural = _('user profile')
|
||||
indexes = [models.Index(fields=['user'])]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('user_detail', args=(self.pk, ))
|
||||
return reverse('user_detail', args=(self.pk,))
|
||||
|
||||
|
||||
|
||||
@ -100,7 +101,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):
|
||||
@ -161,7 +162,7 @@ class Membership(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _('membership')
|
||||
verbose_name_plural = _('memberships')
|
||||
|
||||
indexes = [models.Index(fields=['user'])]
|
||||
|
||||
class RolePermissions(models.Model):
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
@ -49,10 +49,10 @@ class UserCreateView(CreateView):
|
||||
def form_valid(self, form):
|
||||
profile_form = ProfileForm(self.request.POST)
|
||||
if form.is_valid() and profile_form.is_valid():
|
||||
user = form.save()
|
||||
profile = profile_form.save(commit=False)
|
||||
profile.user = user
|
||||
profile.save()
|
||||
user = form.save(commit=False)
|
||||
user.profile = profile_form.save(commit=False)
|
||||
user.save()
|
||||
user.profile.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
@ -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):
|
||||
@ -124,7 +124,7 @@ class UserDetailView(LoginRequiredMixin, DetailView):
|
||||
context = super().get_context_data(**kwargs)
|
||||
user = context['user_object']
|
||||
history_list = \
|
||||
Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note))
|
||||
Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note)).order_by("-id")
|
||||
context['history_list'] = HistoryTable(history_list)
|
||||
club_list = \
|
||||
Membership.objects.all().filter(user=user).only("club")
|
||||
@ -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,23 +242,24 @@ 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]
|
||||
# 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,ext)
|
||||
image_clean.save(image_file, "PNG")
|
||||
image_field.file = image_file
|
||||
# renaming
|
||||
filename = "{}_pic.{}".format(self.object.note.pk, ext)
|
||||
filename = "{}_pic.png".format(self.object.note.pk)
|
||||
image_field.name = filename
|
||||
self.object.note.display_image = image_field
|
||||
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
|
||||
@ -282,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.
|
||||
@ -294,7 +300,7 @@ class UserAutocomplete(autocomplete.Select2QuerySetView):
|
||||
qs = User.objects.all()
|
||||
|
||||
if self.q:
|
||||
qs = qs.filter(username__regex=self.q)
|
||||
qs = qs.filter(username__regex="^" + self.q)
|
||||
|
||||
return qs
|
||||
|
||||
@ -330,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 = \
|
||||
|
Reference in New Issue
Block a user