From b8a88eeda4e9e5b58883ecd2ae473aff71de6f53 Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <yohann.danello@gmail.com>
Date: Wed, 29 Jul 2020 11:38:59 +0200
Subject: [PATCH] Only staff with good permission mask can visit Django Admin

---
 apps/member/admin.py                  |   8 +-
 apps/note/admin.py                    |  20 +++--
 apps/permission/admin.py              |   7 +-
 apps/permission/backends.py           |   6 +-
 apps/permission/templatetags/perms.py |  17 ++--
 apps/treasury/admin.py                |   7 +-
 apps/wei/admin.py                     |  15 ++--
 locale/de/LC_MESSAGES/django.po       | 119 ++++++++++++-------------
 locale/fr/LC_MESSAGES/django.po       | 122 +++++++++++++-------------
 note_kfet/admin.py                    |  25 ++++++
 note_kfet/urls.py                     |   5 +-
 templates/base.html                   |   2 +-
 templates/registration/login.html     |   5 +-
 13 files changed, 196 insertions(+), 162 deletions(-)
 create mode 100644 note_kfet/admin.py

diff --git a/apps/member/admin.py b/apps/member/admin.py
index 2e50e8dc..76edb762 100644
--- a/apps/member/admin.py
+++ b/apps/member/admin.py
@@ -5,6 +5,7 @@ from django.contrib import admin
 from django.contrib.auth.admin import UserAdmin
 from django.contrib.auth.models import User
 
+from note_kfet.admin import admin_site
 from .forms import ProfileForm
 from .models import Club, Membership, Profile
 
@@ -33,9 +34,8 @@ class CustomUserAdmin(UserAdmin):
 
 
 # Update Django User with profile
-admin.site.unregister(User)
-admin.site.register(User, CustomUserAdmin)
+admin_site.register(User, CustomUserAdmin)
 
 # Add other models
-admin.site.register(Club)
-admin.site.register(Membership)
+admin_site.register(Club)
+admin_site.register(Membership)
diff --git a/apps/note/admin.py b/apps/note/admin.py
index dc6470d2..96823d2b 100644
--- a/apps/note/admin.py
+++ b/apps/note/admin.py
@@ -6,6 +6,8 @@ from django.utils.translation import gettext_lazy as _
 from polymorphic.admin import PolymorphicChildModelAdmin, \
     PolymorphicChildModelFilter, PolymorphicParentModelAdmin
 
+from note_kfet.admin import admin_site
+
 from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 from .models.transactions import Transaction, TemplateCategory, TransactionTemplate, \
     RecurrentTransaction, MembershipTransaction, SpecialTransaction
@@ -19,7 +21,7 @@ class AliasInlines(admin.TabularInline):
     model = Alias
 
 
-@admin.register(Note)
+@admin.register(Note, site=admin_site)
 class NoteAdmin(PolymorphicParentModelAdmin):
     """
     Parent regrouping all note types as children
@@ -42,7 +44,7 @@ class NoteAdmin(PolymorphicParentModelAdmin):
     search_fields = ['alias__name']
 
 
-@admin.register(NoteClub)
+@admin.register(NoteClub, site=admin_site)
 class NoteClubAdmin(PolymorphicChildModelAdmin):
     """
     Child for a club note, see NoteAdmin
@@ -66,7 +68,7 @@ class NoteClubAdmin(PolymorphicChildModelAdmin):
         return False
 
 
-@admin.register(NoteSpecial)
+@admin.register(NoteSpecial, site=admin_site)
 class NoteSpecialAdmin(PolymorphicChildModelAdmin):
     """
     Child for a special note, see NoteAdmin
@@ -74,7 +76,7 @@ class NoteSpecialAdmin(PolymorphicChildModelAdmin):
     readonly_fields = ('balance',)
 
 
-@admin.register(NoteUser)
+@admin.register(NoteUser, site=admin_site)
 class NoteUserAdmin(PolymorphicChildModelAdmin):
     """
     Child for an user note, see NoteAdmin
@@ -97,7 +99,7 @@ class NoteUserAdmin(PolymorphicChildModelAdmin):
         return False
 
 
-@admin.register(Transaction)
+@admin.register(Transaction, site=admin_site)
 class TransactionAdmin(PolymorphicParentModelAdmin):
     """
     Admin customisation for Transaction
@@ -138,21 +140,21 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
         return []
 
 
-@admin.register(MembershipTransaction)
+@admin.register(MembershipTransaction, site=admin_site)
 class MembershipTransactionAdmin(PolymorphicChildModelAdmin):
     """
     Admin customisation for MembershipTransaction
     """
 
 
-@admin.register(SpecialTransaction)
+@admin.register(SpecialTransaction, site=admin_site)
 class SpecialTransactionAdmin(PolymorphicChildModelAdmin):
     """
     Admin customisation for SpecialTransaction
     """
 
 
-@admin.register(TransactionTemplate)
+@admin.register(TransactionTemplate, site=admin_site)
 class TransactionTemplateAdmin(admin.ModelAdmin):
     """
     Admin customisation for TransactionTemplate
@@ -170,7 +172,7 @@ class TransactionTemplateAdmin(admin.ModelAdmin):
     poly_destination.short_description = _('destination')
 
 
-@admin.register(TemplateCategory)
+@admin.register(TemplateCategory, site=admin_site)
 class TemplateCategoryAdmin(admin.ModelAdmin):
     """
     Admin customisation for TransactionTemplate
diff --git a/apps/permission/admin.py b/apps/permission/admin.py
index 41e59695..7d189c94 100644
--- a/apps/permission/admin.py
+++ b/apps/permission/admin.py
@@ -3,10 +3,11 @@
 
 from django.contrib import admin
 
+from note_kfet.admin import admin_site
 from .models import Permission, PermissionMask, Role
 
 
-@admin.register(PermissionMask)
+@admin.register(PermissionMask, site=admin_site)
 class PermissionMaskAdmin(admin.ModelAdmin):
     """
     Admin customisation for PermissionMask
@@ -14,7 +15,7 @@ class PermissionMaskAdmin(admin.ModelAdmin):
     list_display = ('description', 'rank', )
 
 
-@admin.register(Permission)
+@admin.register(Permission, site=admin_site)
 class PermissionAdmin(admin.ModelAdmin):
     """
     Admin customisation for Permission
@@ -22,7 +23,7 @@ class PermissionAdmin(admin.ModelAdmin):
     list_display = ('type', 'model', 'field', 'mask', 'description', )
 
 
-@admin.register(Role)
+@admin.register(Role, site=admin_site)
 class RoleAdmin(admin.ModelAdmin):
     """
     Admin customisation for Role
diff --git a/apps/permission/backends.py b/apps/permission/backends.py
index 374e67e6..c1291a2f 100644
--- a/apps/permission/backends.py
+++ b/apps/permission/backends.py
@@ -42,7 +42,7 @@ class PermissionBackend(ModelBackend):
 
         for membership in memberships:
             for role in membership.roles.all():
-                for perm in role.permissions.filter(type=t, mask__rank__lte=get_current_session().get("permission_mask", 42)).all():
+                for perm in role.permissions.filter(type=t, mask__rank__lte=get_current_session().get("permission_mask", -1)).all():
                     if not perm.permanent:
                         if membership.date_start > timezone.now().date() or membership.date_end < timezone.now().date():
                             continue
@@ -101,7 +101,7 @@ class PermissionBackend(ModelBackend):
             # Anonymous users can't do anything
             return Q(pk=-1)
 
-        if user.is_superuser and get_current_session().get("permission_mask", 42) >= 42:
+        if user.is_superuser and get_current_session().get("permission_mask", -1) >= 42:
             # Superusers have all rights
             return Q()
 
@@ -137,7 +137,7 @@ class PermissionBackend(ModelBackend):
         if sess is not None and sess.session_key is None:
             return False
 
-        if user_obj.is_superuser and get_current_session().get("permission_mask", 42) >= 42:
+        if user_obj.is_superuser and get_current_session().get("permission_mask", -1) >= 42:
             return True
 
         if obj is None:
diff --git a/apps/permission/templatetags/perms.py b/apps/permission/templatetags/perms.py
index 101be6e7..335721a1 100644
--- a/apps/permission/templatetags/perms.py
+++ b/apps/permission/templatetags/perms.py
@@ -1,6 +1,7 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
+from django.contrib.auth.models import AnonymousUser
 from django.contrib.contenttypes.models import ContentType
 from django.template.defaultfilters import stringfilter
 from django import template
@@ -16,9 +17,9 @@ def not_empty_model_list(model_name):
     """
     user = get_current_authenticated_user()
     session = get_current_session()
-    if user is None:
+    if user is None or isinstance(user, AnonymousUser):
         return False
-    elif user.is_superuser and session.get("permission_mask", 0) >= 42:
+    elif user.is_superuser and session.get("permission_mask", -1) >= 42:
         return True
     qs = model_list(model_name)
     return qs.exists()
@@ -31,9 +32,9 @@ def not_empty_model_change_list(model_name):
     """
     user = get_current_authenticated_user()
     session = get_current_session()
-    if user is None:
+    if user is None or isinstance(user, AnonymousUser):
         return False
-    elif user.is_superuser and session.get("permission_mask", 0) >= 42:
+    elif user.is_superuser and session.get("permission_mask", -1) >= 42:
         return True
     qs = model_list(model_name, "change")
     return qs.exists()
@@ -45,11 +46,11 @@ def model_list(model_name, t="view", fetch=True):
     Return the queryset of all visible instances of the given model.
     """
     user = get_current_authenticated_user()
-    if user is None:
-        return False
     spl = model_name.split(".")
     ct = ContentType.objects.get(app_label=spl[0], model=spl[1])
     qs = ct.model_class().objects.filter(PermissionBackend.filter_queryset(user, ct, t))
+    if user is None or isinstance(user, AnonymousUser):
+        return qs.none()
     if fetch:
         qs = qs.all()
     return qs
@@ -73,9 +74,9 @@ def can_create_transaction():
     """
     user = get_current_authenticated_user()
     session = get_current_session()
-    if user is None:
+    if user is None or isinstance(user, AnonymousUser):
         return False
-    elif user.is_superuser and session.get("permission_mask", 0) >= 42:
+    elif user.is_superuser and session.get("permission_mask", -1) >= 42:
         return True
     if session.get("can_create_transaction", None):
         return session.get("can_create_transaction", None) == 1
diff --git a/apps/treasury/admin.py b/apps/treasury/admin.py
index 9c8aaf2e..e1b597b9 100644
--- a/apps/treasury/admin.py
+++ b/apps/treasury/admin.py
@@ -3,10 +3,11 @@
 
 from django.contrib import admin
 
+from note_kfet.admin import admin_site
 from .models import RemittanceType, Remittance, SogeCredit
 
 
-@admin.register(RemittanceType)
+@admin.register(RemittanceType, site=admin_site)
 class RemittanceTypeAdmin(admin.ModelAdmin):
     """
     Admin customisation for RemiitanceType
@@ -14,7 +15,7 @@ class RemittanceTypeAdmin(admin.ModelAdmin):
     list_display = ('note', )
 
 
-@admin.register(Remittance)
+@admin.register(Remittance, site=admin_site)
 class RemittanceAdmin(admin.ModelAdmin):
     """
     Admin customisation for Remittance
@@ -27,4 +28,4 @@ class RemittanceAdmin(admin.ModelAdmin):
         return not obj.closed and super().has_change_permission(request, obj)
 
 
-admin.site.register(SogeCredit)
+admin_site.register(SogeCredit)
diff --git a/apps/wei/admin.py b/apps/wei/admin.py
index f93a44ed..a3e1d546 100644
--- a/apps/wei/admin.py
+++ b/apps/wei/admin.py
@@ -1,13 +1,12 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
-from django.contrib import admin
-
+from note_kfet.admin import admin_site
 from .models import WEIClub, WEIRegistration, WEIMembership, WEIRole, Bus, BusTeam
 
-admin.site.register(WEIClub)
-admin.site.register(WEIRegistration)
-admin.site.register(WEIMembership)
-admin.site.register(WEIRole)
-admin.site.register(Bus)
-admin.site.register(BusTeam)
+admin_site.register(WEIClub)
+admin_site.register(WEIRegistration)
+admin_site.register(WEIMembership)
+admin_site.register(WEIRole)
+admin_site.register(Bus)
+admin_site.register(BusTeam)
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index b9d24fd5..1e22bacd 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-07-28 20:42+0200\n"
+"POT-Creation-Date: 2020-07-29 10:56+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -186,12 +186,12 @@ msgstr ""
 msgid "Type"
 msgstr ""
 
-#: apps/activity/tables.py:77 apps/member/forms.py:83
+#: apps/activity/tables.py:77 apps/member/forms.py:92
 #: apps/registration/forms.py:64 apps/treasury/forms.py:120
 msgid "Last name"
 msgstr ""
 
-#: apps/activity/tables.py:79 apps/member/forms.py:88
+#: apps/activity/tables.py:79 apps/member/forms.py:97
 #: apps/registration/forms.py:69 apps/treasury/forms.py:122
 #: templates/note/transaction_form.html:126
 msgid "First name"
@@ -205,7 +205,7 @@ msgstr ""
 msgid "Balance"
 msgstr ""
 
-#: apps/activity/views.py:47 templates/base.html:120
+#: apps/activity/views.py:47 templates/base.html:121
 msgid "Activities"
 msgstr ""
 
@@ -279,31 +279,35 @@ msgstr ""
 msgid "member"
 msgstr ""
 
-#: apps/member/forms.py:62 apps/registration/forms.py:44
+#: apps/member/forms.py:46 apps/member/views.py:77
+msgid "An alias with a similar name already exists."
+msgstr ""
+
+#: apps/member/forms.py:71 apps/registration/forms.py:44
 msgid "Inscription paid by Société Générale"
 msgstr ""
 
-#: apps/member/forms.py:64 apps/registration/forms.py:46
+#: apps/member/forms.py:73 apps/registration/forms.py:46
 msgid "Check this case is the Société Générale paid the inscription."
 msgstr ""
 
-#: apps/member/forms.py:69 apps/registration/forms.py:51
+#: apps/member/forms.py:78 apps/registration/forms.py:51
 msgid "Credit type"
 msgstr ""
 
-#: apps/member/forms.py:70 apps/registration/forms.py:52
+#: apps/member/forms.py:79 apps/registration/forms.py:52
 msgid "No credit"
 msgstr ""
 
-#: apps/member/forms.py:72
+#: apps/member/forms.py:81
 msgid "You can credit the note of the user."
 msgstr ""
 
-#: apps/member/forms.py:76 apps/registration/forms.py:57
+#: apps/member/forms.py:85 apps/registration/forms.py:57
 msgid "Credit amount"
 msgstr ""
 
-#: apps/member/forms.py:93 apps/registration/forms.py:74
+#: apps/member/forms.py:102 apps/registration/forms.py:74
 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:132
 msgid "Bank"
 msgstr ""
@@ -541,14 +545,10 @@ msgstr ""
 
 #: apps/member/views.py:67 templates/member/profile_info.html:47
 #: templates/registration/future_profile_detail.html:48
-#: templates/wei/weimembership_form.html:124
+#: templates/wei/weimembership_form.html:130
 msgid "Update Profile"
 msgstr ""
 
-#: apps/member/views.py:77
-msgid "An alias with a similar name already exists."
-msgstr ""
-
 #: apps/member/views.py:183
 msgid "Search user"
 msgstr ""
@@ -760,7 +760,7 @@ msgid ""
 msgstr ""
 
 #: apps/note/models/transactions.py:228
-#: templates/activity/activity_entry.html:13 templates/base.html:98
+#: templates/activity/activity_entry.html:13 templates/base.html:99
 #: templates/note/transaction_form.html:19
 #: templates/note/transaction_form.html:140
 msgid "Transfer"
@@ -831,7 +831,7 @@ msgstr ""
 msgid "Transfer money"
 msgstr ""
 
-#: apps/note/views.py:140 templates/base.html:93
+#: apps/note/views.py:140 templates/base.html:94
 msgid "Consumptions"
 msgstr ""
 
@@ -975,7 +975,7 @@ msgid ""
 "The entered amount is not enough for the memberships, should be at least {}"
 msgstr ""
 
-#: apps/treasury/apps.py:12 templates/base.html:125
+#: apps/treasury/apps.py:12 templates/base.html:126
 msgid "Treasury"
 msgstr ""
 
@@ -1173,7 +1173,7 @@ msgid "No"
 msgstr ""
 
 #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49
-#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:130
+#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131
 msgid "WEI"
 msgstr ""
 
@@ -1267,7 +1267,7 @@ msgstr ""
 msgid "Caution check given"
 msgstr ""
 
-#: apps/wei/models.py:180 templates/wei/weimembership_form.html:62
+#: apps/wei/models.py:180 templates/wei/weimembership_form.html:68
 msgid "birth date"
 msgstr ""
 
@@ -1287,39 +1287,39 @@ msgstr ""
 msgid "gender"
 msgstr ""
 
-#: apps/wei/models.py:199
+#: apps/wei/models.py:199 templates/wei/weimembership_form.html:62
 msgid "clothing cut"
 msgstr ""
 
-#: apps/wei/models.py:212
+#: apps/wei/models.py:212 templates/wei/weimembership_form.html:65
 msgid "clothing size"
 msgstr ""
 
-#: apps/wei/models.py:218 templates/wei/weimembership_form.html:65
+#: apps/wei/models.py:218 templates/wei/weimembership_form.html:71
 msgid "health issues"
 msgstr ""
 
-#: apps/wei/models.py:223 templates/wei/weimembership_form.html:68
+#: apps/wei/models.py:223 templates/wei/weimembership_form.html:74
 msgid "emergency contact name"
 msgstr ""
 
-#: apps/wei/models.py:228 templates/wei/weimembership_form.html:71
+#: apps/wei/models.py:228 templates/wei/weimembership_form.html:77
 msgid "emergency contact phone"
 msgstr ""
 
-#: apps/wei/models.py:233 templates/wei/weimembership_form.html:74
+#: apps/wei/models.py:233 templates/wei/weimembership_form.html:80
 msgid ""
 "Register on the mailing list to stay informed of the events of the campus (1 "
 "mail/week)"
 msgstr ""
 
-#: apps/wei/models.py:238 templates/wei/weimembership_form.html:77
+#: apps/wei/models.py:238 templates/wei/weimembership_form.html:83
 msgid ""
 "Register on the mailing list to stay informed of the sport events of the "
 "campus (1 mail/week)"
 msgstr ""
 
-#: apps/wei/models.py:243 templates/wei/weimembership_form.html:80
+#: apps/wei/models.py:243 templates/wei/weimembership_form.html:86
 msgid ""
 "Register on the mailing list to stay informed of the art events of the "
 "campus (1 mail/week)"
@@ -1550,27 +1550,27 @@ msgstr ""
 msgid "The ENS Paris-Saclay BDE note."
 msgstr ""
 
-#: templates/base.html:103
+#: templates/base.html:104
 msgid "Users"
 msgstr ""
 
-#: templates/base.html:108
+#: templates/base.html:109
 msgid "Clubs"
 msgstr ""
 
-#: templates/base.html:114
+#: templates/base.html:115
 msgid "Registrations"
 msgstr ""
 
-#: templates/base.html:134
+#: templates/base.html:135
 msgid "Rights"
 msgstr ""
 
-#: templates/base.html:138
+#: templates/base.html:139
 msgid "Administration"
 msgstr ""
 
-#: templates/base.html:177
+#: templates/base.html:178
 msgid ""
 "Your e-mail address is not validated. Please check your mail inbox and click "
 "on the validation link."
@@ -1850,8 +1850,8 @@ msgid "Validate account"
 msgstr ""
 
 #: templates/registration/future_profile_detail.html:64
-#: templates/wei/weimembership_form.html:134
-#: templates/wei/weimembership_form.html:192
+#: templates/wei/weimembership_form.html:140
+#: templates/wei/weimembership_form.html:198
 msgid "Validate registration"
 msgstr ""
 
@@ -1872,7 +1872,7 @@ msgid "Log in again"
 msgstr ""
 
 #: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:21
+#: templates/registration/login.html:22
 #: templates/registration/password_reset_complete.html:10
 msgid "Log in"
 msgstr ""
@@ -1881,10 +1881,11 @@ msgstr ""
 #, python-format
 msgid ""
 "You are authenticated as %(username)s, but are not authorized to access this "
-"page. Would you like to login to a different account?"
+"page. Would you like to login to a different account, or with a higher "
+"permission mask?"
 msgstr ""
 
-#: templates/registration/login.html:22
+#: templates/registration/login.html:23
 msgid "Forgotten your password or username?"
 msgstr ""
 
@@ -2204,64 +2205,64 @@ msgstr ""
 msgid "ENS year"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:83
+#: templates/wei/weimembership_form.html:89
 msgid "Payment from Société générale"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:87
+#: templates/wei/weimembership_form.html:93
 msgid "Suggested bus from the survey:"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:92
+#: templates/wei/weimembership_form.html:98
 msgid "Raw survey information"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:102
+#: templates/wei/weimembership_form.html:108
 msgid "The algorithm didn't run."
 msgstr ""
 
-#: templates/wei/weimembership_form.html:105
+#: templates/wei/weimembership_form.html:111
 msgid "caution check given"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:109
+#: templates/wei/weimembership_form.html:115
 msgid "preferred bus"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:112
+#: templates/wei/weimembership_form.html:118
 msgid "preferred team"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:115
+#: templates/wei/weimembership_form.html:121
 msgid "preferred roles"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:122
+#: templates/wei/weimembership_form.html:128
 #: templates/wei/weiregistration_confirm_delete.html:31
 msgid "Update registration"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:138
+#: templates/wei/weimembership_form.html:144
 msgid "The registration is already validated and can't be unvalidated."
 msgstr ""
 
-#: templates/wei/weimembership_form.html:139
+#: templates/wei/weimembership_form.html:145
 msgid "The user joined the bus"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:140
+#: templates/wei/weimembership_form.html:146
 msgid "in the team"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:141
+#: templates/wei/weimembership_form.html:147
 msgid "in no team (staff)"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:141
+#: templates/wei/weimembership_form.html:147
 msgid "with the following roles:"
 msgstr ""
 
-#: templates/wei/weimembership_form.html:146
+#: templates/wei/weimembership_form.html:152
 msgid ""
 "\n"
 "                            The WEI will be paid by Société générale. The "
@@ -2273,7 +2274,7 @@ msgid ""
 "                        "
 msgstr ""
 
-#: templates/wei/weimembership_form.html:156
+#: templates/wei/weimembership_form.html:162
 #, python-format
 msgid ""
 "\n"
@@ -2282,15 +2283,15 @@ msgid ""
 "                            "
 msgstr ""
 
-#: templates/wei/weimembership_form.html:163
+#: templates/wei/weimembership_form.html:169
 msgid "The note has enough money, the registration is possible."
 msgstr ""
 
-#: templates/wei/weimembership_form.html:170
+#: templates/wei/weimembership_form.html:176
 msgid "The user didn't give her/his caution check."
 msgstr ""
 
-#: templates/wei/weimembership_form.html:178
+#: templates/wei/weimembership_form.html:184
 #, python-format
 msgid ""
 "\n"
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 62abc447..b53f558a 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-07-28 20:42+0200\n"
+"POT-Creation-Date: 2020-07-29 10:56+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -187,12 +187,12 @@ msgstr "supprimer"
 msgid "Type"
 msgstr "Type"
 
-#: apps/activity/tables.py:77 apps/member/forms.py:83
+#: apps/activity/tables.py:77 apps/member/forms.py:92
 #: apps/registration/forms.py:64 apps/treasury/forms.py:120
 msgid "Last name"
 msgstr "Nom de famille"
 
-#: apps/activity/tables.py:79 apps/member/forms.py:88
+#: apps/activity/tables.py:79 apps/member/forms.py:97
 #: apps/registration/forms.py:69 apps/treasury/forms.py:122
 #: templates/note/transaction_form.html:126
 msgid "First name"
@@ -206,7 +206,7 @@ msgstr "Note"
 msgid "Balance"
 msgstr "Solde du compte"
 
-#: apps/activity/views.py:47 templates/base.html:120
+#: apps/activity/views.py:47 templates/base.html:121
 msgid "Activities"
 msgstr "Activités"
 
@@ -280,31 +280,35 @@ msgstr "journaux de modifications"
 msgid "member"
 msgstr "adhérent"
 
-#: apps/member/forms.py:62 apps/registration/forms.py:44
+#: apps/member/forms.py:46 apps/member/views.py:77
+msgid "An alias with a similar name already exists."
+msgstr "Un alias avec un nom similaire existe déjà."
+
+#: apps/member/forms.py:71 apps/registration/forms.py:44
 msgid "Inscription paid by Société Générale"
 msgstr "Inscription payée par la Société générale"
 
-#: apps/member/forms.py:64 apps/registration/forms.py:46
+#: apps/member/forms.py:73 apps/registration/forms.py:46
 msgid "Check this case is the Société Générale paid the inscription."
 msgstr "Cochez cette case si la Société Générale a payé l'inscription."
 
-#: apps/member/forms.py:69 apps/registration/forms.py:51
+#: apps/member/forms.py:78 apps/registration/forms.py:51
 msgid "Credit type"
 msgstr "Type de rechargement"
 
-#: apps/member/forms.py:70 apps/registration/forms.py:52
+#: apps/member/forms.py:79 apps/registration/forms.py:52
 msgid "No credit"
 msgstr "Pas de rechargement"
 
-#: apps/member/forms.py:72
+#: apps/member/forms.py:81
 msgid "You can credit the note of the user."
 msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion."
 
-#: apps/member/forms.py:76 apps/registration/forms.py:57
+#: apps/member/forms.py:85 apps/registration/forms.py:57
 msgid "Credit amount"
 msgstr "Montant à créditer"
 
-#: apps/member/forms.py:93 apps/registration/forms.py:74
+#: apps/member/forms.py:102 apps/registration/forms.py:74
 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:132
 msgid "Bank"
 msgstr "Banque"
@@ -546,14 +550,10 @@ msgstr "Cette adresse doit être valide."
 
 #: apps/member/views.py:67 templates/member/profile_info.html:47
 #: templates/registration/future_profile_detail.html:48
-#: templates/wei/weimembership_form.html:124
+#: templates/wei/weimembership_form.html:130
 msgid "Update Profile"
 msgstr "Modifier le profil"
 
-#: apps/member/views.py:77
-msgid "An alias with a similar name already exists."
-msgstr "Un alias avec un nom similaire existe déjà."
-
 #: apps/member/views.py:183
 msgid "Search user"
 msgstr "Chercher un utilisateur"
@@ -770,7 +770,7 @@ msgstr ""
 "note de destination n'est pas active."
 
 #: apps/note/models/transactions.py:228
-#: templates/activity/activity_entry.html:13 templates/base.html:98
+#: templates/activity/activity_entry.html:13 templates/base.html:99
 #: templates/note/transaction_form.html:19
 #: templates/note/transaction_form.html:140
 msgid "Transfer"
@@ -843,7 +843,7 @@ msgstr "Éditer"
 msgid "Transfer money"
 msgstr "Transférer de l'argent"
 
-#: apps/note/views.py:140 templates/base.html:93
+#: apps/note/views.py:140 templates/base.html:94
 msgid "Consumptions"
 msgstr "Consommations"
 
@@ -1002,7 +1002,7 @@ msgstr ""
 "Le montant crédité est trop faible pour adhérer, il doit être au minimum de "
 "{}"
 
-#: apps/treasury/apps.py:12 templates/base.html:125
+#: apps/treasury/apps.py:12 templates/base.html:126
 msgid "Treasury"
 msgstr "Trésorerie"
 
@@ -1202,7 +1202,7 @@ msgid "No"
 msgstr "Non"
 
 #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49
-#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:130
+#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131
 msgid "WEI"
 msgstr "WEI"
 
@@ -1303,7 +1303,7 @@ msgstr "Crédit de la Société générale"
 msgid "Caution check given"
 msgstr "Chèque de caution donné"
 
-#: apps/wei/models.py:180 templates/wei/weimembership_form.html:62
+#: apps/wei/models.py:180 templates/wei/weimembership_form.html:68
 msgid "birth date"
 msgstr "date de naissance"
 
@@ -1323,27 +1323,27 @@ msgstr "Non-binaire"
 msgid "gender"
 msgstr "genre"
 
-#: apps/wei/models.py:199
+#: apps/wei/models.py:199 templates/wei/weimembership_form.html:62
 msgid "clothing cut"
 msgstr "coupe de vêtement"
 
-#: apps/wei/models.py:212
+#: apps/wei/models.py:212 templates/wei/weimembership_form.html:65
 msgid "clothing size"
 msgstr "taille de vêtement"
 
-#: apps/wei/models.py:218 templates/wei/weimembership_form.html:65
+#: apps/wei/models.py:218 templates/wei/weimembership_form.html:71
 msgid "health issues"
 msgstr "problèmes de santé"
 
-#: apps/wei/models.py:223 templates/wei/weimembership_form.html:68
+#: apps/wei/models.py:223 templates/wei/weimembership_form.html:74
 msgid "emergency contact name"
 msgstr "Nom du contact en cas d'urgence"
 
-#: apps/wei/models.py:228 templates/wei/weimembership_form.html:71
+#: apps/wei/models.py:228 templates/wei/weimembership_form.html:77
 msgid "emergency contact phone"
 msgstr "Téléphone du contact en cas d'urgence"
 
-#: apps/wei/models.py:233 templates/wei/weimembership_form.html:74
+#: apps/wei/models.py:233 templates/wei/weimembership_form.html:80
 msgid ""
 "Register on the mailing list to stay informed of the events of the campus (1 "
 "mail/week)"
@@ -1351,7 +1351,7 @@ msgstr ""
 "S'inscrire sur la liste de diffusion pour rester informé des événements sur "
 "le campus (1 mail par semaine)"
 
-#: apps/wei/models.py:238 templates/wei/weimembership_form.html:77
+#: apps/wei/models.py:238 templates/wei/weimembership_form.html:83
 msgid ""
 "Register on the mailing list to stay informed of the sport events of the "
 "campus (1 mail/week)"
@@ -1359,7 +1359,7 @@ msgstr ""
 "S'inscrire sur la liste de diffusion pour rester informé des actualités "
 "sportives sur le campus (1 mail par semaine)"
 
-#: apps/wei/models.py:243 templates/wei/weimembership_form.html:80
+#: apps/wei/models.py:243 templates/wei/weimembership_form.html:86
 msgid ""
 "Register on the mailing list to stay informed of the art events of the "
 "campus (1 mail/week)"
@@ -1605,29 +1605,29 @@ msgstr "Toutes les activités"
 msgid "The ENS Paris-Saclay BDE note."
 msgstr "La note du BDE de l'ENS Paris-Saclay."
 
-#: templates/base.html:103
+#: templates/base.html:104
 msgid "Users"
 msgstr "Utilisateurs"
 
-#: templates/base.html:108
+#: templates/base.html:109
 msgid "Clubs"
 msgstr "Clubs"
 
-#: templates/base.html:114
+#: templates/base.html:115
 msgid "Registrations"
 msgstr "Inscriptions"
 
-#: templates/base.html:134
+#: templates/base.html:135
 msgid "Rights"
 msgstr "Droits"
 
-#: templates/base.html:138
+#: templates/base.html:139
 #, fuzzy
 #| msgid "registration"
 msgid "Administration"
 msgstr "inscription"
 
-#: templates/base.html:177
+#: templates/base.html:178
 msgid ""
 "Your e-mail address is not validated. Please check your mail inbox and click "
 "on the validation link."
@@ -1916,8 +1916,8 @@ msgid "Validate account"
 msgstr "Valider le compte"
 
 #: templates/registration/future_profile_detail.html:64
-#: templates/wei/weimembership_form.html:134
-#: templates/wei/weimembership_form.html:192
+#: templates/wei/weimembership_form.html:140
+#: templates/wei/weimembership_form.html:198
 msgid "Validate registration"
 msgstr "Valider l'inscription"
 
@@ -1938,7 +1938,7 @@ msgid "Log in again"
 msgstr "Se connecter à nouveau"
 
 #: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:21
+#: templates/registration/login.html:22
 #: templates/registration/password_reset_complete.html:10
 msgid "Log in"
 msgstr "Se connecter"
@@ -1947,12 +1947,14 @@ msgstr "Se connecter"
 #, python-format
 msgid ""
 "You are authenticated as %(username)s, but are not authorized to access this "
-"page. Would you like to login to a different account?"
+"page. Would you like to login to a different account, or with a higher "
+"permission mask?"
 msgstr ""
 "Vous êtes connecté en tant que %(username)s, mais vous n'avez le droit "
-"d'accéder à cette page. Voulez vous essayer avec un autre compte ?"
+"d'accéder à cette page. Voulez-vous essayer avec un autre compte, ou avec "
+"un masque de permissions plus fort ?"
 
-#: templates/registration/login.html:22
+#: templates/registration/login.html:23
 msgid "Forgotten your password or username?"
 msgstr "Mot de passe ou pseudo oublié ?"
 
@@ -2309,64 +2311,64 @@ msgstr "Vérifier l'inscription"
 msgid "ENS year"
 msgstr "Année à l'ENS"
 
-#: templates/wei/weimembership_form.html:83
+#: templates/wei/weimembership_form.html:89
 msgid "Payment from Société générale"
 msgstr "Paiement de la Société générale"
 
-#: templates/wei/weimembership_form.html:87
+#: templates/wei/weimembership_form.html:93
 msgid "Suggested bus from the survey:"
 msgstr "Bus suggéré par le sondage :"
 
-#: templates/wei/weimembership_form.html:92
+#: templates/wei/weimembership_form.html:98
 msgid "Raw survey information"
 msgstr "Informations brutes du sondage"
 
-#: templates/wei/weimembership_form.html:102
+#: templates/wei/weimembership_form.html:108
 msgid "The algorithm didn't run."
 msgstr "L'algorithme n'a pas été exécuté."
 
-#: templates/wei/weimembership_form.html:105
+#: templates/wei/weimembership_form.html:111
 msgid "caution check given"
 msgstr "chèque de caution donné"
 
-#: templates/wei/weimembership_form.html:109
+#: templates/wei/weimembership_form.html:115
 msgid "preferred bus"
 msgstr "bus préféré"
 
-#: templates/wei/weimembership_form.html:112
+#: templates/wei/weimembership_form.html:118
 msgid "preferred team"
 msgstr "équipe préférée"
 
-#: templates/wei/weimembership_form.html:115
+#: templates/wei/weimembership_form.html:121
 msgid "preferred roles"
 msgstr "rôles préférés"
 
-#: templates/wei/weimembership_form.html:122
+#: templates/wei/weimembership_form.html:128
 #: templates/wei/weiregistration_confirm_delete.html:31
 msgid "Update registration"
 msgstr "Mettre à jour l'inscription"
 
-#: templates/wei/weimembership_form.html:138
+#: templates/wei/weimembership_form.html:144
 msgid "The registration is already validated and can't be unvalidated."
 msgstr "L'inscription a déjà été validée et ne peut pas être dévalidée."
 
-#: templates/wei/weimembership_form.html:139
+#: templates/wei/weimembership_form.html:145
 msgid "The user joined the bus"
 msgstr "L'utilisateur a rejoint le bus"
 
-#: templates/wei/weimembership_form.html:140
+#: templates/wei/weimembership_form.html:146
 msgid "in the team"
 msgstr "dans l'équipe"
 
-#: templates/wei/weimembership_form.html:141
+#: templates/wei/weimembership_form.html:147
 msgid "in no team (staff)"
 msgstr "dans aucune équipe (staff)"
 
-#: templates/wei/weimembership_form.html:141
+#: templates/wei/weimembership_form.html:147
 msgid "with the following roles:"
 msgstr "avec les rôles suivants :"
 
-#: templates/wei/weimembership_form.html:146
+#: templates/wei/weimembership_form.html:152
 msgid ""
 "\n"
 "                            The WEI will be paid by Société générale. The "
@@ -2385,7 +2387,7 @@ msgstr ""
 "aura validé la création du compte, ou bien changer de moyen de paiement.\n"
 "                    "
 
-#: templates/wei/weimembership_form.html:156
+#: templates/wei/weimembership_form.html:162
 #, python-format
 msgid ""
 "\n"
@@ -2398,15 +2400,15 @@ msgstr ""
 "L'inscription va échouer.\n"
 "                            "
 
-#: templates/wei/weimembership_form.html:163
+#: templates/wei/weimembership_form.html:169
 msgid "The note has enough money, the registration is possible."
 msgstr "La note a assez d'argent, l'inscription est possible."
 
-#: templates/wei/weimembership_form.html:170
+#: templates/wei/weimembership_form.html:176
 msgid "The user didn't give her/his caution check."
 msgstr "L'utilisateur n'a pas donné son chèque de caution."
 
-#: templates/wei/weimembership_form.html:178
+#: templates/wei/weimembership_form.html:184
 #, python-format
 msgid ""
 "\n"
diff --git a/note_kfet/admin.py b/note_kfet/admin.py
new file mode 100644
index 00000000..67ac872e
--- /dev/null
+++ b/note_kfet/admin.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.contrib.admin import AdminSite
+from django.contrib.sites.admin import Site, SiteAdmin
+
+from member.views import CustomLoginView
+from .middlewares import get_current_session
+
+
+class StrongAdminSite(AdminSite):
+    def has_permission(self, request):
+        """
+        Authorize only staff that have the correct permission mask
+        """
+        session = get_current_session()
+        return request.user.is_active and request.user.is_staff and session.get("permission_mask", -1) >= 42
+
+    def login(self, request, extra_context=None):
+        return CustomLoginView.as_view()(request)
+
+
+# Instantiate admin site and register some defaults
+admin_site = StrongAdminSite()
+admin_site.register(Site, SiteAdmin)
diff --git a/note_kfet/urls.py b/note_kfet/urls.py
index 9717087a..24ab075d 100644
--- a/note_kfet/urls.py
+++ b/note_kfet/urls.py
@@ -3,13 +3,14 @@
 
 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.defaults import bad_request, permission_denied, page_not_found, server_error
 from django.views.generic import RedirectView
 
 from member.views import CustomLoginView
 
+from .admin import admin_site
+
 urlpatterns = [
     # Dev so redirect to something random
     path('', RedirectView.as_view(pattern_name='note:transfer'), name='index'),
@@ -25,7 +26,7 @@ urlpatterns = [
     # Include Django Contrib and Core routers
     path('i18n/', include('django.conf.urls.i18n')),
     path('admin/doc/', include('django.contrib.admindocs.urls')),
-    path('admin/', admin.site.urls, name="admin"),
+    path('admin/', admin_site.urls, name="admin"),
     path('accounts/login/', CustomLoginView.as_view()),
     path('accounts/', include('django.contrib.auth.urls')),
     path('api/', include('api.urls')),
diff --git a/templates/base.html b/templates/base.html
index 872fde06..9aa34437 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -134,7 +134,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
                 <li class="nav-item active">
                     <a class="nav-link" href="{% url 'permission:rights' %}"><i class="fas fa-balance-scale"></i> {% trans 'Rights' %}</a>
                 </li>
-                {% if user.is_staff %}
+                {% if user.is_staff and ""|has_perm:user %}
                     <li class="nav-item active">
                         <a data-turbolinks="false" class="nav-link" href="{% url 'admin:index' %}"><i class="fas fa-user-cog"></i> {% trans 'Administration' %}</a>
                     </li>
diff --git a/templates/registration/login.html b/templates/registration/login.html
index 32e54e00..87354721 100644
--- a/templates/registration/login.html
+++ b/templates/registration/login.html
@@ -10,9 +10,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
 {% block content %}
     {% if user.is_authenticated %}
         <p class="errornote">
-            {% blocktrans trimmed %}
+            {% blocktrans trimmed with username=request.user.username %}
                 You are authenticated as {{ username }}, but are not authorized to
-                access this page. Would you like to login to a different account?
+                access this page. Would you like to login to a different account,
+                or with a higher permission mask?
             {% endblocktrans %}
         </p>
     {% endif %}
-- 
GitLab