diff --git a/oser_backend/settings/common.py b/oser_backend/settings/common.py index 7d62a94f890549cc8797de087956b476057a91cc..84ccf8246385333d1cfbb3d32340090720319435 100644 --- a/oser_backend/settings/common.py +++ b/oser_backend/settings/common.py @@ -255,10 +255,10 @@ EMAIL_PORT = 587 EMAIL_USE_TLS = True # Toggle sandbox mode (when running in DEBUG mode) -SENDGRID_SANDBOX_MODE_IN_DEBUG=False +SENDGRID_SANDBOX_MODE_IN_DEBUG = False # echo to stdout or any other file-like object that is passed to the backend via the stream kwarg. -SENDGRID_ECHO_TO_STDOUT=True +SENDGRID_ECHO_TO_STDOUT = True # Mails app config diff --git a/projects/MultiSelectFieldListFilter.py b/projects/MultiSelectFieldListFilter.py new file mode 100644 index 0000000000000000000000000000000000000000..28bbb89e6eae617f147881cdc9e5a5bce7a5a420 --- /dev/null +++ b/projects/MultiSelectFieldListFilter.py @@ -0,0 +1,68 @@ +from django.contrib import admin +from django.contrib.admin.utils import reverse_field_path +from django.utils.translation import gettext_lazy as _ + + +class MultiSelectFieldListFilter(admin.FieldListFilter): + def __init__(self, field, request, params, model, model_admin, field_path): + self.lookup_kwarg = field_path + '__in' + self.lookup_kwarg_isnull = field_path + '__isnull' + + super().__init__(field, request, params, model, model_admin, field_path) + + self.lookup_val = self.used_parameters.get(self.lookup_kwarg, []) + if len(self.lookup_val) == 1 and self.lookup_val[0] == '': + self.lookup_val = [] + self.lookup_val_isnull = self.used_parameters.get( + self.lookup_kwarg_isnull) + + self.empty_value_display = model_admin.get_empty_value_display() + parent_model, reverse_path = reverse_field_path(model, field_path) + # Obey parent ModelAdmin queryset when deciding which options to show + if model == parent_model: + queryset = model_admin.get_queryset(request) + else: + queryset = parent_model._default_manager.all() + self.lookup_choices = queryset.distinct().order_by( + field.name).values_list(field.name, flat=True) + + def expected_parameters(self): + return [self.lookup_kwarg, self.lookup_kwarg_isnull] + + def choices(self, changelist): + yield { + 'selected': not self.lookup_val and self.lookup_val_isnull is None, + 'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]), + 'display': _('All'), + } + include_none = False + for val in self.lookup_choices: + if val is None: + include_none = True + continue + val = str(val) + + if val in self.lookup_val: + values = [v for v in self.lookup_val if v != val] + else: + values = self.lookup_val + [val] + + if values: + yield { + 'selected': val in self.lookup_val, + 'query_string': changelist.get_query_string({self.lookup_kwarg: ','.join(values)}, [self.lookup_kwarg_isnull]), + 'display': val, + } + else: + yield { + 'selected': val in self.lookup_val, + 'query_string': changelist.get_query_string(remove=[self.lookup_kwarg]), + 'display': val, + } + + if include_none: + yield { + 'selected': bool(self.lookup_val_isnull), + 'query_string': changelist.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]), + 'display': self.empty_value_display, + } diff --git a/projects/admin.py b/projects/admin.py index 5a65a46fdfe9f65c4e90bd4f5293542db2ec39bb..e43c198933a4a26170dc30281e0b5bcfc49817f1 100644 --- a/projects/admin.py +++ b/projects/admin.py @@ -5,6 +5,8 @@ from django.contrib import admin from dynamicforms.views import download_multiple_forms_entries from dynamicforms.models import Form from .models import Edition, Participation, Project, EditionForm +from django.contrib.admin import SimpleListFilter +from profiles.models import Student @admin.register(Project) @@ -37,7 +39,26 @@ class OrganizersInline(admin.TabularInline): extra = 0 -@admin.register(Edition) +class SchoolFilter(admin.SimpleListFilter): + title = 'établissement' + parameter_name = 'profiles__school' + + def lookups(self, request, model_admin): + list_of_school = [] + query = Student.objects.values_list( + "school", flat=True).distinct() + for school in query: + list_of_school.append((school, school)) + return list_of_school + + def queryset(self, request, queryset): + if self.value(): + emails = Student.objects.filter( + school=self.value()).values_list("user__email", flat=True) + return queryset.filter(user__email__in=emails) + + +@ admin.register(Edition) class EditionAdmin(admin.ModelAdmin): """Admin panel for editions.""" @@ -73,7 +94,7 @@ class EditionAdmin(admin.ModelAdmin): num_cancelled.short_description = 'Annulés' -@admin.register(EditionForm) +@ admin.register(EditionForm) class EditionFormAdmin(admin.ModelAdmin): """Admin panel for edition forms.""" @@ -81,11 +102,12 @@ class EditionFormAdmin(admin.ModelAdmin): list_filter = ('edition', 'deadline',) -@admin.register(Participation) +@ admin.register(Participation) class ParticipationAdmin(admin.ModelAdmin): """Participation admin panel.""" list_display = ('user', 'edition', 'submitted', 'state') - list_filter = ('edition', 'submitted', 'state',) + list_filter = (SchoolFilter, + 'edition', 'submitted', 'state',) readonly_fields = ('submitted',) search_fields = ('user__first_name', 'user__last_name', 'user__email',) diff --git a/register/MultiSelectFieldListFilter.py b/register/MultiSelectFieldListFilter.py new file mode 100644 index 0000000000000000000000000000000000000000..28bbb89e6eae617f147881cdc9e5a5bce7a5a420 --- /dev/null +++ b/register/MultiSelectFieldListFilter.py @@ -0,0 +1,68 @@ +from django.contrib import admin +from django.contrib.admin.utils import reverse_field_path +from django.utils.translation import gettext_lazy as _ + + +class MultiSelectFieldListFilter(admin.FieldListFilter): + def __init__(self, field, request, params, model, model_admin, field_path): + self.lookup_kwarg = field_path + '__in' + self.lookup_kwarg_isnull = field_path + '__isnull' + + super().__init__(field, request, params, model, model_admin, field_path) + + self.lookup_val = self.used_parameters.get(self.lookup_kwarg, []) + if len(self.lookup_val) == 1 and self.lookup_val[0] == '': + self.lookup_val = [] + self.lookup_val_isnull = self.used_parameters.get( + self.lookup_kwarg_isnull) + + self.empty_value_display = model_admin.get_empty_value_display() + parent_model, reverse_path = reverse_field_path(model, field_path) + # Obey parent ModelAdmin queryset when deciding which options to show + if model == parent_model: + queryset = model_admin.get_queryset(request) + else: + queryset = parent_model._default_manager.all() + self.lookup_choices = queryset.distinct().order_by( + field.name).values_list(field.name, flat=True) + + def expected_parameters(self): + return [self.lookup_kwarg, self.lookup_kwarg_isnull] + + def choices(self, changelist): + yield { + 'selected': not self.lookup_val and self.lookup_val_isnull is None, + 'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]), + 'display': _('All'), + } + include_none = False + for val in self.lookup_choices: + if val is None: + include_none = True + continue + val = str(val) + + if val in self.lookup_val: + values = [v for v in self.lookup_val if v != val] + else: + values = self.lookup_val + [val] + + if values: + yield { + 'selected': val in self.lookup_val, + 'query_string': changelist.get_query_string({self.lookup_kwarg: ','.join(values)}, [self.lookup_kwarg_isnull]), + 'display': val, + } + else: + yield { + 'selected': val in self.lookup_val, + 'query_string': changelist.get_query_string(remove=[self.lookup_kwarg]), + 'display': val, + } + + if include_none: + yield { + 'selected': bool(self.lookup_val_isnull), + 'query_string': changelist.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]), + 'display': self.empty_value_display, + } diff --git a/register/admin.py b/register/admin.py index f18b03b65b8f1151972ff51fd6255696c9d3246e..95a4138df47b10c89c2dac2604b074f5fe30404a 100644 --- a/register/admin.py +++ b/register/admin.py @@ -2,6 +2,26 @@ from django.contrib import admin from .models import Registration +from profiles.models import Student + + +class SchoolFilter(admin.SimpleListFilter): + title = 'établissement' + parameter_name = 'profiles__school' + + def lookups(self, request, model_admin): + list_of_school = [] + query = Student.objects.values_list( + "school", flat=True).distinct() + for school in query: + list_of_school.append((school, school)) + return list_of_school + + def queryset(self, request, queryset): + if self.value(): + emails = Student.objects.filter( + school=self.value()).values_list("user__email", flat=True) + return queryset.filter(email__in=emails) @admin.register(Registration) @@ -10,4 +30,5 @@ class RegistrationAdmin(admin.ModelAdmin): list_display = ('last_name', 'first_name', 'submitted') readonly_fields = ('submitted',) - list_filter = ('submitted', 'validated') + list_filter = (SchoolFilter, + 'submitted', 'validated') diff --git a/visits/admin.py b/visits/admin.py index 7056c6da996d4be842a76c089466079d86ef9faf..a7b6392529941962e2bb2ee3c755c27efc5dff8a 100644 --- a/visits/admin.py +++ b/visits/admin.py @@ -13,6 +13,25 @@ from profiles.models import Student # Register your models here. +class SchoolFilter(admin.SimpleListFilter): + title = 'établissement' + parameter_name = 'profiles__school' + + def lookups(self, request, model_admin): + list_of_school = [] + query = Student.objects.values_list( + "school", flat=True).distinct() + for school in query: + list_of_school.append((school, school)) + return list_of_school + + def queryset(self, request, queryset): + if self.value(): + emails = Student.objects.filter( + school=self.value()).values_list("user__email", flat=True) + return queryset.filter(user__email__in=emails) + + class RegistrationsOpenFilter(admin.SimpleListFilter): """Custom filter to filter visits by their registration openness. @@ -133,8 +152,10 @@ reject_selected_participations.short_description = ( class ParticipationAdmin(admin.ModelAdmin): """Admin panel for visit participations.""" - list_display = ('submitted', 'visit', 'user_link', 'school', 'accepted', 'present') - list_filter = ('submitted', 'accepted', 'present') + list_display = ('submitted', 'visit', 'user_link', 'accepted', 'present') + list_filter = (SchoolFilter, 'submitted', 'accepted', 'present') + + actions = [accept_selected_participations, reject_selected_participations] def user_link(self, participation: Participation):