Ce patch ajoute un lien bidirectionnel entre la page d'affichage d'un petit cours pour le Burô et l'administration générale. Plus précisément, - Un lien est ajouté sur la page du petit cours, ainsi que sur la page de traitement, vers l'administration générale - La fonctionalité "Voir sur le site" de Django est utilisée pour renvoyer sur la page de la demande. Si des modifications sont apportées, il faut choisir "Enregistrer et continuer les modifications", puis cliquer sur "Voir sur le site". Le workflow n'est pas forcément optimal, mais permet au COF d'accéder facilement à la demande si un traitement manuel ou complexe est nécessaire - et de facilement revenir à la vue de traitement.
335 lines
9.9 KiB
Python
335 lines
9.9 KiB
Python
from dal.autocomplete import ModelSelect2
|
|
from django import forms
|
|
from django.contrib import admin
|
|
from django.contrib.auth.admin import UserAdmin
|
|
from django.contrib.auth.models import Group, Permission, User
|
|
from django.core.urlresolvers import reverse
|
|
from django.db.models import Q
|
|
from django.utils.safestring import mark_safe
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from gestioncof.models import (
|
|
Club,
|
|
CofProfile,
|
|
Event,
|
|
EventCommentField,
|
|
EventOption,
|
|
EventOptionChoice,
|
|
EventRegistration,
|
|
Survey,
|
|
SurveyQuestion,
|
|
SurveyQuestionAnswer,
|
|
)
|
|
from petitscours.models import (
|
|
PetitCoursAbility,
|
|
PetitCoursAttribution,
|
|
PetitCoursAttributionCounter,
|
|
PetitCoursDemande,
|
|
PetitCoursSubject,
|
|
)
|
|
|
|
|
|
def add_link_field(target_model="", field="", link_text=str, desc_text=str):
|
|
def add_link(cls):
|
|
reverse_name = target_model or cls.model.__name__.lower()
|
|
|
|
def link(self, instance):
|
|
app_name = instance._meta.app_label
|
|
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
|
|
link_obj = getattr(instance, field, None) or instance
|
|
if not link_obj.id:
|
|
return ""
|
|
url = reverse(reverse_path, args=(link_obj.id,))
|
|
return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
|
|
|
|
link.allow_tags = True
|
|
link.short_description = desc_text(reverse_name + " link")
|
|
cls.link = link
|
|
cls.readonly_fields = list(getattr(cls, "readonly_fields", [])) + ["link"]
|
|
return cls
|
|
|
|
return add_link
|
|
|
|
|
|
class SurveyQuestionAnswerInline(admin.TabularInline):
|
|
model = SurveyQuestionAnswer
|
|
|
|
|
|
@add_link_field(
|
|
desc_text=lambda x: "Réponses", link_text=lambda x: "Éditer les réponses"
|
|
)
|
|
class SurveyQuestionInline(admin.TabularInline):
|
|
model = SurveyQuestion
|
|
|
|
|
|
class SurveyQuestionAdmin(admin.ModelAdmin):
|
|
search_fields = ("survey__title", "answer")
|
|
inlines = [SurveyQuestionAnswerInline]
|
|
|
|
|
|
class SurveyAdmin(admin.ModelAdmin):
|
|
search_fields = ("title", "details")
|
|
inlines = [SurveyQuestionInline]
|
|
|
|
|
|
class EventOptionChoiceInline(admin.TabularInline):
|
|
model = EventOptionChoice
|
|
|
|
|
|
@add_link_field(desc_text=lambda x: "Choix", link_text=lambda x: "Éditer les choix")
|
|
class EventOptionInline(admin.TabularInline):
|
|
model = EventOption
|
|
|
|
|
|
class EventCommentFieldInline(admin.TabularInline):
|
|
model = EventCommentField
|
|
|
|
|
|
class EventOptionAdmin(admin.ModelAdmin):
|
|
search_fields = ("event__title", "name")
|
|
inlines = [EventOptionChoiceInline]
|
|
|
|
|
|
class EventAdmin(admin.ModelAdmin):
|
|
search_fields = ("title", "location", "description")
|
|
inlines = [EventOptionInline, EventCommentFieldInline]
|
|
|
|
|
|
class CofProfileInline(admin.StackedInline):
|
|
model = CofProfile
|
|
inline_classes = ("collapse open",)
|
|
|
|
|
|
class FkeyLookup(object):
|
|
def __init__(self, fkeydecl, short_description=None, admin_order_field=None):
|
|
self.fk, fkattrs = fkeydecl.split("__", 1)
|
|
self.fkattrs = fkattrs.split("__")
|
|
|
|
self.short_description = short_description or self.fkattrs[-1]
|
|
self.admin_order_field = admin_order_field or fkeydecl
|
|
|
|
def __get__(self, obj, klass):
|
|
if obj is None:
|
|
"""
|
|
hack required to make Django validate (if obj is
|
|
None, then we're a class, and classes are callable
|
|
<wink>)
|
|
"""
|
|
return self
|
|
item = getattr(obj, self.fk)
|
|
for attr in self.fkattrs:
|
|
item = getattr(item, attr)
|
|
return item
|
|
|
|
|
|
def ProfileInfo(field, short_description, boolean=False):
|
|
def getter(self):
|
|
try:
|
|
return getattr(self.profile, field)
|
|
except CofProfile.DoesNotExist:
|
|
return ""
|
|
|
|
getter.short_description = short_description
|
|
getter.boolean = boolean
|
|
return getter
|
|
|
|
|
|
User.profile_login_clipper = FkeyLookup("profile__login_clipper", "Login clipper")
|
|
User.profile_phone = ProfileInfo("phone", "Téléphone")
|
|
User.profile_occupation = ProfileInfo("occupation", "Occupation")
|
|
User.profile_departement = ProfileInfo("departement", "Departement")
|
|
User.profile_mailing_cof = ProfileInfo("mailing_cof", "ML COF", True)
|
|
User.profile_mailing_bda = ProfileInfo("mailing_bda", "ML BdA", True)
|
|
User.profile_mailing_bda_revente = ProfileInfo("mailing_bda_revente", "ML BdA-R", True)
|
|
|
|
|
|
class UserProfileAdmin(UserAdmin):
|
|
def is_buro(self, obj):
|
|
try:
|
|
return obj.profile.is_buro
|
|
except CofProfile.DoesNotExist:
|
|
return False
|
|
|
|
is_buro.short_description = "Membre du Buro"
|
|
is_buro.boolean = True
|
|
|
|
def is_cof(self, obj):
|
|
try:
|
|
return obj.profile.is_cof
|
|
except CofProfile.DoesNotExist:
|
|
return False
|
|
|
|
is_cof.short_description = "Membre du COF"
|
|
is_cof.boolean = True
|
|
|
|
list_display = UserAdmin.list_display + (
|
|
"profile_login_clipper",
|
|
"profile_phone",
|
|
"profile_occupation",
|
|
"profile_mailing_cof",
|
|
"profile_mailing_bda",
|
|
"profile_mailing_bda_revente",
|
|
"is_cof",
|
|
"is_buro",
|
|
)
|
|
list_display_links = ("username", "email", "first_name", "last_name")
|
|
list_filter = UserAdmin.list_filter + (
|
|
"profile__is_cof",
|
|
"profile__is_buro",
|
|
"profile__mailing_cof",
|
|
"profile__mailing_bda",
|
|
)
|
|
search_fields = UserAdmin.search_fields + ("profile__phone",)
|
|
inlines = [CofProfileInline]
|
|
|
|
staff_fieldsets = [
|
|
(None, {"fields": ["username", "password"]}),
|
|
(_("Personal info"), {"fields": ["first_name", "last_name", "email"]}),
|
|
]
|
|
|
|
def get_fieldsets(self, request, user=None):
|
|
if not request.user.is_superuser:
|
|
return self.staff_fieldsets
|
|
return super().get_fieldsets(request, user)
|
|
|
|
def save_model(self, request, user, form, change):
|
|
cof_group, created = Group.objects.get_or_create(name="COF")
|
|
if created:
|
|
# Si le groupe COF n'était pas déjà dans la bdd
|
|
# On lui assigne les bonnes permissions
|
|
perms = Permission.objects.filter(
|
|
Q(content_type__app_label="gestioncof")
|
|
| Q(content_type__app_label="bda")
|
|
| (Q(content_type__app_label="auth") & Q(content_type__model="user"))
|
|
)
|
|
cof_group.permissions = perms
|
|
# On y associe les membres du Burô
|
|
cof_group.user_set = User.objects.filter(profile__is_buro=True)
|
|
# Sauvegarde
|
|
cof_group.save()
|
|
# le Burô est staff et appartient au groupe COF
|
|
if user.profile.is_buro:
|
|
user.is_staff = True
|
|
user.groups.add(cof_group)
|
|
else:
|
|
user.is_staff = False
|
|
user.groups.remove(cof_group)
|
|
user.save()
|
|
|
|
|
|
# FIXME: This is absolutely horrible.
|
|
def user_str(self):
|
|
if self.first_name and self.last_name:
|
|
return "{} ({})".format(self.get_full_name(), self.username)
|
|
else:
|
|
return self.username
|
|
|
|
|
|
User.__str__ = user_str
|
|
|
|
|
|
class EventRegistrationAdminForm(forms.ModelForm):
|
|
class Meta:
|
|
widgets = {"user": ModelSelect2(url="cof-user-autocomplete")}
|
|
|
|
|
|
class EventRegistrationAdmin(admin.ModelAdmin):
|
|
form = EventRegistrationAdminForm
|
|
|
|
list_display = ("__str__", "event", "user", "paid")
|
|
list_filter = ("paid",)
|
|
search_fields = (
|
|
"user__username",
|
|
"user__first_name",
|
|
"user__last_name",
|
|
"user__email",
|
|
"event__title",
|
|
)
|
|
|
|
|
|
class PetitCoursAbilityAdmin(admin.ModelAdmin):
|
|
list_display = ("user", "matiere", "niveau", "agrege")
|
|
search_fields = (
|
|
"user__username",
|
|
"user__first_name",
|
|
"user__last_name",
|
|
"user__email",
|
|
"matiere__name",
|
|
"niveau",
|
|
)
|
|
list_filter = ("matiere", "niveau", "agrege")
|
|
|
|
|
|
class PetitCoursAttributionAdmin(admin.ModelAdmin):
|
|
list_display = ("user", "demande", "matiere", "rank")
|
|
search_fields = ("user__username", "matiere__name")
|
|
|
|
|
|
class PetitCoursAttributionCounterAdmin(admin.ModelAdmin):
|
|
list_display = ("user", "matiere", "count")
|
|
list_filter = ("matiere",)
|
|
search_fields = (
|
|
"user__username",
|
|
"user__first_name",
|
|
"user__last_name",
|
|
"user__email",
|
|
"matiere__name",
|
|
)
|
|
actions = ["reset"]
|
|
actions_on_bottom = True
|
|
|
|
def reset(self, request, queryset):
|
|
queryset.update(count=0)
|
|
|
|
reset.short_description = "Remise à zéro du compteur"
|
|
|
|
|
|
class PetitCoursDemandeAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
"name",
|
|
"email",
|
|
"agrege_requis",
|
|
"niveau",
|
|
"created",
|
|
"traitee",
|
|
"processed",
|
|
)
|
|
list_filter = ("traitee", "niveau")
|
|
search_fields = ("name", "email", "phone", "lieu", "remarques")
|
|
readonly_fields = ("created",)
|
|
|
|
|
|
class ClubAdminForm(forms.ModelForm):
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
respos = cleaned_data.get("respos")
|
|
members = cleaned_data.get("membres")
|
|
for respo in respos.all():
|
|
if respo not in members:
|
|
raise forms.ValidationError(
|
|
"Erreur : le respo %s n'est pas membre du club."
|
|
% respo.get_full_name()
|
|
)
|
|
return cleaned_data
|
|
|
|
|
|
class ClubAdmin(admin.ModelAdmin):
|
|
list_display = ["name"]
|
|
form = ClubAdminForm
|
|
|
|
|
|
admin.site.register(Survey, SurveyAdmin)
|
|
admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
|
|
admin.site.register(Event, EventAdmin)
|
|
admin.site.register(EventOption, EventOptionAdmin)
|
|
admin.site.unregister(User)
|
|
admin.site.register(User, UserProfileAdmin)
|
|
admin.site.register(CofProfile)
|
|
admin.site.register(Club, ClubAdmin)
|
|
admin.site.register(PetitCoursSubject)
|
|
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
|
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
|
admin.site.register(PetitCoursAttributionCounter, PetitCoursAttributionCounterAdmin)
|
|
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)
|
|
admin.site.register(EventRegistration, EventRegistrationAdmin)
|