diff --git a/.env_example b/.env_example
index d903b724..9afdd138 100644
--- a/.env_example
+++ b/.env_example
@@ -11,3 +11,5 @@ DJANGO_SETTINGS_MODULE=note_kfet.settings
DOMAIN=localhost
CONTACT_EMAIL=tresorerie.bde@localhost
NOTE_URL=localhost
+NOTE_MAIL=notekfet@localhost
+WEBMASTER_MAIL=notekfet@localhost
diff --git a/README.md b/README.md
index 0c0cfb2e..be27e63e 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,8 @@ On supposera pour la suite que vous utilisez Debian/Ubuntu sur un serveur tout n
DOMAIN=localhost # note.example.com
CONTACT_EMAIL=tresorerie.bde@localhost
NOTE_URL=localhost # serveur cas note.example.com si auto-hébergé.
+ NOTE_MAIL=notekfet@localhost # Adresse expéditrice des mails
+ WEBMASTER_MAIL=notekfet@localhost # Adresse sur laquelle contacter les webmasters de la note
Ensuite on (re)bascule dans l'environement virtuel et on lance les migrations
diff --git a/apps/activity/forms.py b/apps/activity/forms.py
index dcbd3c9d..dced014a 100644
--- a/apps/activity/forms.py
+++ b/apps/activity/forms.py
@@ -4,7 +4,7 @@ from datetime import timedelta, datetime
from django import forms
from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import gettext as _
+from django.utils.translation import gettext_lazy as _
from member.models import Club
from note.models import NoteUser, Note
from note_kfet.inputs import DateTimePickerInput, Autocomplete
diff --git a/apps/activity/models.py b/apps/activity/models.py
index 29f04b39..cab229c4 100644
--- a/apps/activity/models.py
+++ b/apps/activity/models.py
@@ -139,7 +139,7 @@ class Entry(models.Model):
verbose_name = _("entry")
verbose_name_plural = _("entries")
- def save(self, *args,**kwargs):
+ def save(self, *args, **kwargs):
qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest)
if qs.exists():
@@ -153,7 +153,7 @@ class Entry(models.Model):
if self.note.balance < 0:
raise ValidationError(_("The balance is negative."))
- ret = super().save(*args,**kwargs)
+ ret = super().save(*args, **kwargs)
if insert and self.guest:
GuestTransaction.objects.create(
diff --git a/apps/activity/views.py b/apps/activity/views.py
index 14746929..12386bd1 100644
--- a/apps/activity/views.py
+++ b/apps/activity/views.py
@@ -45,8 +45,8 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
context['title'] = _("Activities")
upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now())
- context['upcoming'] = ActivityTable(data=upcoming_activities
- .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")))
+ context['upcoming'] = ActivityTable(
+ data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")))
return context
@@ -153,9 +153,9 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
context["title"] = _('Entry for activity "{}"').format(activity.name)
context["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk
context["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk
-
+
context["activities_open"] = Activity.objects.filter(open=True).filter(
PermissionBackend.filter_queryset(self.request.user, Activity, "view")).filter(
PermissionBackend.filter_queryset(self.request.user, Activity, "change")).all()
- return context
\ No newline at end of file
+ return context
diff --git a/apps/api/urls.py b/apps/api/urls.py
index 67fdba30..03d6bd68 100644
--- a/apps/api/urls.py
+++ b/apps/api/urls.py
@@ -15,6 +15,7 @@ from note.api.urls import register_note_urls
from treasury.api.urls import register_treasury_urls
from logs.api.urls import register_logs_urls
from permission.api.urls import register_permission_urls
+from wei.api.urls import register_wei_urls
class UserSerializer(serializers.ModelSerializer):
@@ -78,6 +79,7 @@ register_note_urls(router, 'note')
register_treasury_urls(router, 'treasury')
register_permission_urls(router, 'permission')
register_logs_urls(router, 'logs')
+register_wei_urls(router, 'wei')
app_name = 'api'
diff --git a/apps/member/forms.py b/apps/member/forms.py
index 6fe95f5a..e546d652 100644
--- a/apps/member/forms.py
+++ b/apps/member/forms.py
@@ -9,7 +9,7 @@ from note.models import NoteSpecial
from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput
from permission.models import PermissionMask
-from .models import Profile, Club, Membership
+from .models import Profile, Club, Membership, Role
class CustomAuthenticationForm(AuthenticationForm):
@@ -25,10 +25,16 @@ class ProfileForm(forms.ModelForm):
A form for the extras field provided by the :model:`member.Profile` model.
"""
+ def save(self, commit=True):
+ if not self.instance.section or (("department" in self.changed_data
+ or "promotion" in self.changed_data) and "section" not in self.changed_data):
+ self.instance.section = self.instance.section_generated
+ return super().save(commit)
+
class Meta:
model = Profile
fields = '__all__'
- exclude = ('user', 'email_confirmed', 'registration_valid', 'soge', )
+ exclude = ('user', 'email_confirmed', 'registration_valid', )
class ClubForm(forms.ModelForm):
@@ -50,6 +56,8 @@ class ClubForm(forms.ModelForm):
class MembershipForm(forms.ModelForm):
+ roles = forms.ModelMultipleChoiceField(queryset=Role.objects.filter(weirole=None).all())
+
soge = forms.BooleanField(
label=_("Inscription paid by Société Générale"),
required=False,
diff --git a/apps/member/models.py b/apps/member/models.py
index 3a022434..17b8f044 100644
--- a/apps/member/models.py
+++ b/apps/member/models.py
@@ -23,18 +23,20 @@ class Profile(models.Model):
We do not want to patch the Django Contrib :model:`auth.User`model;
so this model add an user profile with additional information.
-
"""
+
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
+
phone_number = models.CharField(
verbose_name=_('phone number'),
max_length=50,
blank=True,
null=True,
)
+
section = models.CharField(
verbose_name=_('section'),
help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'),
@@ -42,12 +44,44 @@ class Profile(models.Model):
blank=True,
null=True,
)
+
+ department = models.CharField(
+ max_length=8,
+ verbose_name=_("department"),
+ choices=[
+ ('A0', _("Informatics (A0)")),
+ ('A1', _("Mathematics (A1)")),
+ ('A2', _("Physics (A2)")),
+ ("A'2", _("Applied physics (A'2)")),
+ ('A''2', _("Chemistry (A''2)")),
+ ('A3', _("Biology (A3)")),
+ ('B1234', _("SAPHIRE (B1234)")),
+ ('B1', _("Mechanics (B1)")),
+ ('B2', _("Civil engineering (B2)")),
+ ('B3', _("Mechanical engineering (B3)")),
+ ('B4', _("EEA (B4)")),
+ ('C', _("Design (C)")),
+ ('D2', _("Economy-management (D2)")),
+ ('D3', _("Social sciences (D3)")),
+ ('E', _("English (E)")),
+ ('EXT', _("External (EXT)")),
+ ]
+ )
+
+ promotion = models.PositiveIntegerField(
+ null=True,
+ default=datetime.date.today().year,
+ verbose_name=_("promotion"),
+ help_text=_("Year of entry to the school (None if not ENS student)"),
+ )
+
address = models.CharField(
verbose_name=_('address'),
max_length=255,
blank=True,
null=True,
)
+
paid = models.BooleanField(
verbose_name=_("paid"),
help_text=_("Tells if the user receive a salary."),
@@ -64,11 +98,29 @@ class Profile(models.Model):
default=False,
)
- soge = models.BooleanField(
- verbose_name=_("Société générale"),
- help_text=_("Has the user ever be paid by the Société générale?"),
- default=False,
- )
+ @property
+ def ens_year(self):
+ """
+ Number of years since the 1st august of the entry year, rounded up.
+ """
+ if self.promotion is None:
+ return 0
+ today = datetime.date.today()
+ years = today.year - self.promotion
+ if today.month >= 8:
+ years += 1
+ return years
+
+ @property
+ def section_generated(self):
+ return str(self.ens_year) + self.department
+
+ @property
+ def soge(self):
+ if "treasury" in settings.INSTALLED_APPS:
+ from treasury.models import SogeCredit
+ return SogeCredit.objects.filter(user=self.user, credit_transaction__isnull=False).exists()
+ return False
class Meta:
verbose_name = _('user profile')
@@ -85,7 +137,7 @@ class Profile(models.Model):
'user': self.user,
'domain': os.getenv("NOTE_URL", "note.example.com"),
'token': email_validation_token.make_token(self.user),
- 'uid': urlsafe_base64_encode(force_bytes(self.user.pk)).decode('UTF-8'),
+ 'uid': urlsafe_base64_encode(force_bytes(self.user.pk)),
})
self.user.email_user(subject, message)
@@ -171,6 +223,7 @@ class Club(models.Model):
self.membership_start.month, self.membership_start.day)
self.membership_end = datetime.date(self.membership_end.year + 1,
self.membership_end.month, self.membership_end.day)
+ self._force_save = True
self.save(force_update=True)
def save(self, force_insert=False, force_update=False, using=None,
@@ -220,6 +273,7 @@ class Membership(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT,
+ related_name="memberships",
verbose_name=_("user"),
)
@@ -308,7 +362,20 @@ class Membership(models.Model):
reason="Adhésion " + self.club.name,
)
transaction._force_save = True
- transaction.save(force_insert=True)
+ print(hasattr(self, '_soge'))
+ if hasattr(self, '_soge') and "treasury" in settings.INSTALLED_APPS:
+ # If the soge pays, then the transaction is unvalidated in a first time, then submitted for control
+ # to treasurers.
+ transaction.valid = False
+ from treasury.models import SogeCredit
+ soge_credit = SogeCredit.objects.get_or_create(user=self.user)[0]
+ soge_credit.refresh_from_db()
+ transaction.save(force_insert=True)
+ transaction.refresh_from_db()
+ soge_credit.transactions.add(transaction)
+ soge_credit.save()
+ else:
+ transaction.save(force_insert=True)
def __str__(self):
return _("Membership of {user} for the club {club}").format(user=self.user.username, club=self.club.name, )
diff --git a/apps/member/views.py b/apps/member/views.py
index 381314b2..04742f32 100644
--- a/apps/member/views.py
+++ b/apps/member/views.py
@@ -18,7 +18,7 @@ from django.views.generic.edit import FormMixin
from django_tables2.views import SingleTableView
from rest_framework.authtoken.models import Token
from note.forms import ImageForm
-from note.models import Alias, NoteUser, NoteSpecial
+from note.models import Alias, NoteUser
from note.models.transactions import Transaction, SpecialTransaction
from note.tables import HistoryTable, AliasTable
from permission.backends import PermissionBackend
@@ -128,7 +128,8 @@ class UserDetailView(ProtectQuerysetMixin, 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)).order_by("-id")\
+ Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note))\
+ .order_by("-created_at", "-id")\
.filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))
history_table = HistoryTable(history_list, prefix='transaction-')
history_table.paginate(per_page=20, page=self.request.GET.get("transaction-page", 1))
@@ -165,7 +166,7 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
Q(first_name__iregex=pattern)
| Q(last_name__iregex=pattern)
| Q(profile__section__iregex=pattern)
- | Q(profile__username__iregex="^" + pattern)
+ | Q(username__iregex="^" + pattern)
| Q(note__alias__name__iregex="^" + pattern)
| Q(note__alias__normalized_name__iregex=Alias.normalize("^" + pattern))
)
@@ -314,7 +315,8 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
club.update_membership_dates()
club_transactions = Transaction.objects.all().filter(Q(source=club.note) | Q(destination=club.note))\
- .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by('-id')
+ .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))\
+ .order_by('-created_at', '-id')
history_table = HistoryTable(club_transactions, prefix="history-")
history_table.paginate(per_page=20, page=self.request.GET.get('history-page', 1))
context['history_list'] = history_table
@@ -365,6 +367,15 @@ class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
form_class = ClubForm
template_name = "member/club_form.html"
+ def get_queryset(self, **kwargs):
+ qs = super().get_queryset(**kwargs)
+
+ # Don't update a WEI club through this view
+ if "wei" in settings.INSTALLED_APPS:
+ qs = qs.filter(weiclub=None)
+
+ return qs
+
def get_success_url(self):
return reverse_lazy("member:club_detail", kwargs={"pk": self.object.pk})
@@ -396,7 +407,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
if "club_pk" in self.kwargs:
# We create a new membership.
club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
- .get(pk=self.kwargs["club_pk"])
+ .get(pk=self.kwargs["club_pk"], weiclub=None)
form.fields['credit_amount'].initial = club.membership_fee_paid
form.fields['roles'].initial = Role.objects.filter(name="Membre de club").all()
@@ -463,17 +474,11 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
bank = form.cleaned_data["bank"]
soge = form.cleaned_data["soge"] and not user.profile.soge and club.name == "BDE"
- # If Société générale pays, then we auto-fill some data
+ # If Société générale pays, then we store that information but the payment must be controlled by treasurers
+ # later. The membership transaction will be invalidated.
if soge:
- credit_type = NoteSpecial.objects.get(special_type="Virement bancaire")
- bde = club
- kfet = Club.objects.get(name="Kfet")
- if user.profile.paid:
- fee = bde.membership_fee_paid + kfet.membership_fee_paid
- else:
- fee = bde.membership_fee_unpaid + kfet.membership_fee_unpaid
- credit_amount = fee
- bank = "Société générale"
+ credit_type = None
+ form.instance._soge = True
if credit_type is None:
credit_amount = 0
@@ -521,6 +526,13 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
# Now, all is fine, the membership can be created.
+ if club.name == "BDE":
+ # When we renew the BDE membership, we update the profile section.
+ # We could automate that and remove the section field from the Profile model,
+ # but with this way users can customize their section as they want.
+ user.profile.section = user.profile.section_generated
+ user.profile.save()
+
# Credit note before the membership is created.
if credit_amount > 0:
if not last_name or not first_name or (not bank and credit_type.special_type == "Chèque"):
@@ -544,11 +556,11 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
valid=True,
)
- # If Société générale pays, then we store the information: the bank can't pay twice to a same person.
- if soge:
- user.profile.soge = True
- user.profile.save()
+ ret = super().form_valid(form)
+ # If Société générale pays, then we assume that this is the BDE membership, and we auto-renew the
+ # Kfet membership.
+ if soge:
kfet = Club.objects.get(name="Kfet")
kfet_fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid
@@ -560,20 +572,23 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
date_end__gte=datetime.today(),
)
- membership = Membership.objects.create(
+ membership = Membership(
club=kfet,
user=user,
fee=kfet_fee,
date_start=old_membership.get().date_end + timedelta(days=1)
if old_membership.exists() else form.instance.date_start,
)
+ membership._soge = True
+ membership.save()
+ membership.refresh_from_db()
if old_membership.exists():
membership.roles.set(old_membership.get().roles.all())
else:
membership.roles.add(Role.objects.get(name="Adhérent Kfet"))
membership.save()
- return super().form_valid(form)
+ return ret
def get_success_url(self):
return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id})
diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py
index 83f8f914..081f6022 100644
--- a/apps/note/models/transactions.py
+++ b/apps/note/models/transactions.py
@@ -8,6 +8,7 @@ from django.utils.translation import gettext_lazy as _
from polymorphic.models import PolymorphicModel
from .notes import Note, NoteClub, NoteSpecial
+from ..templatetags.pretty_money import pretty_money
"""
Defines transactions
@@ -198,6 +199,14 @@ class Transaction(PolymorphicModel):
self.source.save()
self.destination.save()
+ def delete(self, **kwargs):
+ """
+ Whenever we want to delete a transaction (caution with this), we ensure the transaction is invalid first.
+ """
+ self.valid = False
+ self.save(**kwargs)
+ super().delete(**kwargs)
+
@property
def total(self):
return self.amount * self.quantity
@@ -206,6 +215,10 @@ class Transaction(PolymorphicModel):
def type(self):
return _('Transfer')
+ def __str__(self):
+ return self.__class__.__name__ + " from " + str(self.source) + " to " + str(self.destination) + " of "\
+ + pretty_money(self.quantity * self.amount) + ("" if self.valid else " invalid")
+
class RecurrentTransaction(Transaction):
"""
diff --git a/apps/note/signals.py b/apps/note/signals.py
index 37737a45..0baa39e6 100644
--- a/apps/note/signals.py
+++ b/apps/note/signals.py
@@ -10,14 +10,14 @@ def save_user_note(instance, raw, **_kwargs):
# When provisionning data, do not try to autocreate
return
- if (instance.is_superuser or instance.profile.registration_valid) and instance.is_active:
+ if instance.is_superuser or instance.profile.registration_valid:
# Create note only when the registration is validated
from note.models import NoteUser
NoteUser.objects.get_or_create(user=instance)
instance.note.save()
-def save_club_note(instance, created, raw, **_kwargs):
+def save_club_note(instance, raw, **_kwargs):
"""
Hook to create and save a note when a club is updated
"""
@@ -25,7 +25,6 @@ def save_club_note(instance, created, raw, **_kwargs):
# When provisionning data, do not try to autocreate
return
- if created:
- from .models import NoteClub
- NoteClub.objects.create(club=instance)
+ from .models import NoteClub
+ NoteClub.objects.get_or_create(club=instance)
instance.note.save()
diff --git a/apps/note/views.py b/apps/note/views.py
index 88d47847..b26e6cf1 100644
--- a/apps/note/views.py
+++ b/apps/note/views.py
@@ -30,7 +30,7 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl
table_class = HistoryTable
def get_queryset(self, **kwargs):
- return super().get_queryset(**kwargs).order_by("-id").all()[:20]
+ return super().get_queryset(**kwargs).order_by("-created_at", "-id").all()[:20]
def get_context_data(self, **kwargs):
"""
@@ -93,7 +93,7 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
table_class = HistoryTable
def get_queryset(self, **kwargs):
- return super().get_queryset(**kwargs).order_by("-id").all()[:20]
+ return super().get_queryset(**kwargs).order_by("-created_at", "-id").all()[:20]
def get_context_data(self, **kwargs):
"""
diff --git a/apps/permission/backends.py b/apps/permission/backends.py
index 04d93528..3dd47fa7 100644
--- a/apps/permission/backends.py
+++ b/apps/permission/backends.py
@@ -36,13 +36,15 @@ class PermissionBackend(ModelBackend):
# Unauthenticated users have no permissions
return Permission.objects.none()
- return Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
- .filter(
- rolepermissions__role__membership__user=user,
- rolepermissions__role__membership__date_start__lte=datetime.date.today(),
- rolepermissions__role__membership__date_end__gte=datetime.date.today(),
- type=t,
- mask__rank__lte=get_current_session().get("permission_mask", 0),
+ return Permission.objects.annotate(
+ club=F("rolepermissions__role__membership__club"),
+ membership=F("rolepermissions__role__membership"),
+ ).filter(
+ rolepermissions__role__membership__user=user,
+ rolepermissions__role__membership__date_start__lte=datetime.date.today(),
+ rolepermissions__role__membership__date_end__gte=datetime.date.today(),
+ type=t,
+ mask__rank__lte=get_current_session().get("permission_mask", 0),
).distinct()
@staticmethod
@@ -55,6 +57,7 @@ class PermissionBackend(ModelBackend):
:return: A generator of the requested permissions
"""
clubs = {}
+ memberships = {}
for permission in PermissionBackend.get_raw_permissions(user, type):
if not isinstance(model.model_class()(), permission.model.model_class()) or not permission.club:
@@ -64,9 +67,16 @@ class PermissionBackend(ModelBackend):
clubs[permission.club] = club = Club.objects.get(pk=permission.club)
else:
club = clubs[permission.club]
+
+ if permission.membership not in memberships:
+ memberships[permission.membership] = membership = Membership.objects.get(pk=permission.membership)
+ else:
+ membership = memberships[permission.membership]
+
permission = permission.about(
user=user,
club=club,
+ membership=membership,
User=User,
Club=Club,
Membership=Membership,
@@ -75,7 +85,9 @@ class PermissionBackend(ModelBackend):
NoteClub=NoteClub,
NoteSpecial=NoteSpecial,
F=F,
- Q=Q
+ Q=Q,
+ now=datetime.datetime.now(),
+ today=datetime.date.today(),
)
yield permission
diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json
index d7eca508..bad0ec80 100644
--- a/apps/permission/fixtures/initial.json
+++ b/apps/permission/fixtures/initial.json
@@ -1,1184 +1,2459 @@
[
- {
- "model": "member.role",
- "pk": 1,
- "fields": {
- "name": "Adh\u00e9rent BDE"
- }
- },
- {
- "model": "member.role",
- "pk": 2,
- "fields": {
- "name": "Adh\u00e9rent Kfet"
- }
- },
- {
- "model": "member.role",
- "pk": 3,
- "fields": {
- "name": "Membre de club"
- }
- },
- {
- "model": "member.role",
- "pk": 4,
- "fields": {
- "name": "Bureau de club"
- }
- },
- {
- "model": "member.role",
- "pk": 5,
- "fields": {
- "name": "Pr\u00e9sident\u00b7e de club"
- }
- },
- {
- "model": "member.role",
- "pk": 6,
- "fields": {
- "name": "Tr\u00e9sorier\u00b7\u00e8re de club"
- }
- },
- {
- "model": "member.role",
- "pk": 7,
- "fields": {
- "name": "Pr\u00e9sident\u00b7e BDE"
- }
- },
- {
- "model": "member.role",
- "pk": 8,
- "fields": {
- "name": "Tr\u00e9sorier\u00b7\u00e8re BDE"
- }
- },
- {
- "model": "member.role",
- "pk": 9,
- "fields": {
- "name": "Respo info"
- }
- },
- {
- "model": "member.role",
- "pk": 10,
- "fields": {
- "name": "GC Kfet"
- }
- },
- {
- "model": "member.role",
- "pk": 11,
- "fields": {
- "name": "Res[pot]"
- }
- },
- {
- "model": "permission.permissionmask",
- "pk": 1,
- "fields": {
- "rank": 0,
- "description": "Droits basiques"
- }
- },
- {
- "model": "permission.permissionmask",
- "pk": 2,
- "fields": {
- "rank": 1,
- "description": "Droits note seulement"
- }
- },
- {
- "model": "permission.permissionmask",
- "pk": 3,
- "fields": {
- "rank": 42,
- "description": "Tous mes droits"
- }
- },
- {
- "model": "permission.permission",
- "pk": 1,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our User object"
- }
- },
- {
- "model": "permission.permission",
- "pk": 2,
- "fields": {
- "model": 17,
- "query": "{\"user\": [\"user\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our profile"
- }
- },
- {
- "model": "permission.permission",
- "pk": 3,
- "fields": {
- "model": 27,
- "query": "{\"pk\": [\"user\", \"note\", \"pk\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our own note"
- }
- },
- {
- "model": "permission.permission",
- "pk": 4,
- "fields": {
- "model": 8,
- "query": "{\"user\": [\"user\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our API token"
- }
- },
- {
- "model": "permission.permission",
- "pk": 5,
- "fields": {
- "model": 22,
- "query": "[\"OR\", {\"source\": [\"user\", \"note\"]}, {\"destination\": [\"user\", \"note\"]}]",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our own transactions"
- }
- },
- {
- "model": "permission.permission",
- "pk": 6,
- "fields": {
- "model": 19,
- "query": "[\"OR\", {\"note__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club__name\": \"Kfet\"}], [\"all\"]]}, {\"note__in\": [\"NoteClub\", \"objects\", [\"all\"]]}]",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View aliases of clubs and members of Kfet club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 7,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "last_login",
- "description": "Change myself's last login"
- }
- },
- {
- "model": "permission.permission",
- "pk": 8,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "username",
- "description": "Change myself's username"
- }
- },
- {
- "model": "permission.permission",
- "pk": 9,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "first_name",
- "description": "Change myself's first name"
- }
- },
- {
- "model": "permission.permission",
- "pk": 10,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "last_name",
- "description": "Change myself's last name"
- }
- },
- {
- "model": "permission.permission",
- "pk": 11,
- "fields": {
- "model": 4,
- "query": "{\"pk\": [\"user\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "email",
- "description": "Change myself's email"
- }
- },
- {
- "model": "permission.permission",
- "pk": 12,
- "fields": {
- "model": 8,
- "query": "{\"user\": [\"user\"]}",
- "type": "delete",
- "mask": 1,
- "field": "",
- "description": "Delete API Token"
- }
- },
- {
- "model": "permission.permission",
- "pk": 13,
- "fields": {
- "model": 8,
- "query": "{\"user\": [\"user\"]}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Create API Token"
- }
- },
- {
- "model": "permission.permission",
- "pk": 14,
- "fields": {
- "model": 19,
- "query": "{\"note\": [\"user\", \"note\"]}",
- "type": "delete",
- "mask": 1,
- "field": "",
- "description": "Remove alias"
- }
- },
- {
- "model": "permission.permission",
- "pk": 15,
- "fields": {
- "model": 19,
- "query": "{\"note\": [\"user\", \"note\"]}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Add alias"
- }
- },
- {
- "model": "permission.permission",
- "pk": 16,
- "fields": {
- "model": 27,
- "query": "{\"pk\": [\"user\", \"note\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "display_image",
- "description": "Change myself's display image"
- }
- },
- {
- "model": "permission.permission",
- "pk": 17,
- "fields": {
- "model": 22,
- "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, [\"OR\", {\"amount__lte\": [\"user\", \"note\", \"balance\"]}, {\"valid\": false}]]",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Transfer from myself's note"
- }
- },
- {
- "model": "permission.permission",
- "pk": 18,
- "fields": {
- "model": 20,
- "query": "{}",
- "type": "change",
- "mask": 1,
- "field": "balance",
- "description": "Update a note balance with a transaction"
- }
- },
- {
- "model": "permission.permission",
- "pk": 19,
- "fields": {
- "model": 20,
- "query": "[\"OR\", {\"pk\": [\"club\", \"note\", \"pk\"]}, {\"pk__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club\": [\"club\"]}], [\"all\"]]}]",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View notes of club members"
- }
- },
- {
- "model": "permission.permission",
- "pk": 20,
- "fields": {
- "model": 22,
- "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Create transactions with a club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 21,
- "fields": {
- "model": 28,
- "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Create transactions from buttons with a club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 22,
- "fields": {
- "model": 15,
- "query": "{\"pk\": [\"club\", \"pk\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View club infos"
- }
- },
- {
- "model": "permission.permission",
- "pk": 23,
- "fields": {
- "model": 22,
- "query": "{}",
- "type": "change",
- "mask": 1,
- "field": "valid",
- "description": "Update validation status of a transaction"
- }
- },
- {
- "model": "permission.permission",
- "pk": 24,
- "fields": {
- "model": 22,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View all transactions"
- }
- },
- {
- "model": "permission.permission",
- "pk": 25,
- "fields": {
- "model": 26,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "Display credit/debit interface"
- }
- },
- {
- "model": "permission.permission",
- "pk": 26,
- "fields": {
- "model": 29,
- "query": "{}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Create credit/debit transaction"
- }
- },
- {
- "model": "permission.permission",
- "pk": 27,
- "fields": {
- "model": 21,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View button categories"
- }
- },
- {
- "model": "permission.permission",
- "pk": 28,
- "fields": {
- "model": 21,
- "query": "{}",
- "type": "change",
- "mask": 3,
- "field": "",
- "description": "Change button category"
- }
- },
- {
- "model": "permission.permission",
- "pk": 29,
- "fields": {
- "model": 21,
- "query": "{}",
- "type": "add",
- "mask": 3,
- "field": "",
- "description": "Add button category"
- }
- },
- {
- "model": "permission.permission",
- "pk": 30,
- "fields": {
- "model": 23,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View buttons"
- }
- },
- {
- "model": "permission.permission",
- "pk": 31,
- "fields": {
- "model": 23,
- "query": "{}",
- "type": "add",
- "mask": 3,
- "field": "",
- "description": "Add buttons"
- }
- },
- {
- "model": "permission.permission",
- "pk": 32,
- "fields": {
- "model": 23,
- "query": "{}",
- "type": "change",
- "mask": 3,
- "field": "",
- "description": "Update buttons"
- }
- },
- {
- "model": "permission.permission",
- "pk": 33,
- "fields": {
- "model": 22,
- "query": "{}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Create any transaction"
- }
- },
- {
- "model": "permission.permission",
- "pk": 34,
- "fields": {
- "model": 9,
- "query": "[\"OR\", {\"valid\": true}, {\"creater\": [\"user\"]}]",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View valid activites"
- }
- },
- {
- "model": "permission.permission",
- "pk": 35,
- "fields": {
- "model": 9,
- "query": "[\"AND\", {\"valid\": false}, {\"creater\": [\"user\"]}]",
- "type": "change",
- "mask": 1,
- "field": "",
- "description": "Change our activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 36,
- "fields": {
- "model": 9,
- "query": "{\"creater\": [\"user\"], \"valid\": false}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Add activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 37,
- "fields": {
- "model": 9,
- "query": "{}",
- "type": "change",
- "mask": 2,
- "field": "valid",
- "description": "Validate activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 38,
- "fields": {
- "model": 9,
- "query": "{}",
- "type": "change",
- "mask": 2,
- "field": "open",
- "description": "Open activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 39,
- "fields": {
- "model": 12,
- "query": "{\"inviter\": [\"user\", \"note\"], \"activity__activity_type__can_invite\": true}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Invite people to activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 40,
- "fields": {
- "model": 12,
- "query": "{\"inviter\": [\"user\", \"note\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View invited people"
- }
- },
- {
- "model": "permission.permission",
- "pk": 41,
- "fields": {
- "model": 9,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View all activities"
- }
- },
- {
- "model": "permission.permission",
- "pk": 42,
- "fields": {
- "model": 12,
- "query": "{}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "View all invited people"
- }
- },
- {
- "model": "permission.permission",
- "pk": 43,
- "fields": {
- "model": 11,
- "query": "{}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Manage entries"
- }
- },
- {
- "model": "permission.permission",
- "pk": 44,
- "fields": {
- "model": 13,
- "query": "{}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Add invitation transactions"
- }
- },
- {
- "model": "permission.permission",
- "pk": 45,
- "fields": {
- "model": 13,
- "query": "{}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View invitation transactions"
- }
- },
- {
- "model": "permission.permission",
- "pk": 46,
- "fields": {
- "model": 13,
- "query": "{}",
- "type": "change",
- "mask": 2,
- "field": "valid",
- "description": "Validate invitation transactions"
- }
- },
- {
- "model": "permission.permission",
- "pk": 47,
- "fields": {
- "model": 15,
- "query": "{\"pk\": [\"club\", \"pk\"]}",
- "type": "change",
- "mask": 1,
- "field": "",
- "description": "Update club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 48,
- "fields": {
- "model": 16,
- "query": "{\"user\": [\"user\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View our memberships"
- }
- },
- {
- "model": "permission.permission",
- "pk": 49,
- "fields": {
- "model": 16,
- "query": "{\"club\": [\"club\"]}",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View club's memberships"
- }
- },
- {
- "model": "permission.permission",
- "pk": 50,
- "fields": {
- "model": 16,
- "query": "{\"club\": [\"club\"]}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Add a membership to a club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 51,
- "fields": {
- "model": 16,
- "query": "{\"club\": [\"club\"]}",
- "type": "change",
- "mask": 2,
- "field": "roles",
- "description": "Update user roles"
- }
- },
- {
- "model": "permission.permission",
- "pk": 52,
- "fields": {
- "model": 17,
- "query": "{\"user\": [\"user\"]}",
- "type": "change",
- "mask": 1,
- "field": "",
- "description": "Change own profile"
- }
- },
- {
- "model": "permission.permission",
- "pk": 53,
- "fields": {
- "model": 17,
- "query": "{}",
- "type": "change",
- "mask": 2,
- "field": "",
- "description": "Change any profile"
- }
- },
- {
- "model": "permission.permission",
- "pk": 54,
- "fields": {
- "model": 4,
- "query": "{}",
- "type": "change",
- "mask": 2,
- "field": "",
- "description": "Change any user"
- }
- },
- {
- "model": "permission.permission",
- "pk": 55,
- "fields": {
- "model": 4,
- "query": "{}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Add user"
- }
- },
- {
- "model": "permission.permission",
- "pk": 56,
- "fields": {
- "model": 17,
- "query": "{\"email_confirmed\": false, \"registration_valid\": false}",
- "type": "add",
- "mask": 1,
- "field": "",
- "description": "Add profile"
- }
- },
- {
- "model": "permission.permission",
- "pk": 57,
- "fields": {
- "model": 4,
- "query": "{\"profile__registration_valid\": false}",
- "type": "delete",
- "mask": 2,
- "field": "",
- "description": "Delete pre-registered user"
- }
- },
- {
- "model": "permission.permission",
- "pk": 58,
- "fields": {
- "model": 17,
- "query": "{\"registration_valid\": false}",
- "type": "delete",
- "mask": 2,
- "field": "",
- "description": "Delete pre-registered user profile"
- }
- },
- {
- "model": "permission.permission",
- "pk": 59,
- "fields": {
- "model": 23,
- "query": "{\"destination\": [\"club\", \"note\"]}",
- "type": "view",
- "mask": 2,
- "field": "",
- "description": "New club button"
- }
- },
- {
- "model": "permission.permission",
- "pk": 60,
- "fields": {
- "model": 23,
- "query": "{\"destination\": [\"club\", \"note\"]}",
- "type": "add",
- "mask": 2,
- "field": "",
- "description": "Create club button"
- }
- },
- {
- "model": "permission.permission",
- "pk": 61,
- "fields": {
- "model": 23,
- "query": "{\"destination\": [\"club\", \"note\"]}",
- "type": "change",
- "mask": 2,
- "field": "",
- "description": "Update club button"
- }
- },
- {
- "model": "permission.permission",
- "pk": 62,
- "fields": {
- "model": 22,
- "query": "[\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}]",
- "type": "view",
- "mask": 1,
- "field": "",
- "description": "View transactions of a club"
- }
- },
- {
- "model": "permission.permission",
- "pk": 63,
- "fields": {
- "model": 33,
- "query": "{}",
- "type": "view",
- "mask": 3,
- "field": "",
- "description": "View invoices"
- }
- },
- {
- "model": "permission.permission",
- "pk": 64,
- "fields": {
- "model": 33,
- "query": "{}",
- "type": "add",
- "mask": 3,
- "field": "",
- "description": "Add invoice"
- }
- },
- {
- "model": "permission.permission",
- "pk": 65,
- "fields": {
- "model": 33,
- "query": "{}",
- "type": "change",
- "mask": 3,
- "field": "",
- "description": "Change invoice"
- }
- },
- {
- "model": "permission.permission",
- "pk": 66,
- "fields": {
- "model": 34,
- "query": "{}",
- "type": "view",
- "mask": 3,
- "field": "",
- "description": "View products"
- }
- },
- {
- "model": "permission.permission",
- "pk": 67,
- "fields": {
- "model": 34,
- "query": "{}",
- "type": "add",
- "mask": 3,
- "field": "",
- "description": "Add products"
- }
- },
- {
- "model": "permission.permission",
- "pk": 68,
- "fields": {
- "model": 34,
- "query": "{}",
- "type": "change",
- "mask": 3,
- "field": "",
- "description": "Change product"
- }
- },
- {
- "model": "permission.permission",
- "pk": 69,
- "fields": {
- "model": 34,
- "query": "{}",
- "type": "delete",
- "mask": 3,
- "field": "",
- "description": "Delete product"
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 1,
- "fields": {
- "role": 1,
- "permissions": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 48,
- 52
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 2,
- "fields": {
- "role": 2,
- "permissions": [
- 6,
- 14,
- 15,
- 16,
- 17,
- 18,
- 34,
- 35,
- 36,
- 39,
- 40
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 4,
- "fields": {
- "role": 4,
- "permissions": [
- 22,
- 47,
- 49
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 5,
- "fields": {
- "role": 5,
- "permissions": [
- 50,
- 51,
- 62
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 6,
- "fields": {
- "role": 6,
- "permissions": [
- 19,
- 21,
- 27,
- 59,
- 60,
- 61,
- 20,
- 62
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 7,
- "fields": {
- "role": 7,
- "permissions": [
- 33,
- 24,
- 25,
- 26,
- 27
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 8,
- "fields": {
- "role": 8,
- "permissions": [
- 32,
- 33,
- 56,
- 58,
- 55,
- 57,
- 53,
- 54,
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 64,
- 65,
- 66,
- 67,
- 68,
- 69,
- 63
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 9,
- "fields": {
- "role": 9,
- "permissions": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 21,
- 22,
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 32,
- 33,
- 34,
- 35,
- 36,
- 37,
- 38,
- 39,
- 40,
- 41,
- 42,
- 43,
- 44,
- 45,
- 46,
- 47,
- 48,
- 49,
- 50,
- 51,
- 52,
- 53,
- 54,
- 55,
- 56,
- 57,
- 58,
- 59,
- 60,
- 61,
- 20,
- 62,
- 63,
- 64,
- 65,
- 66,
- 67,
- 68,
- 69
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 10,
- "fields": {
- "role": 10,
- "permissions": [
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 32,
- 33,
- 52,
- 53,
- 54,
- 55,
- 56,
- 57,
- 58
- ]
- }
- },
- {
- "model": "permission.rolepermissions",
- "pk": 11,
- "fields": {
- "role": 11,
- "permissions": [
- 37,
- 38,
- 41,
- 42,
- 43,
- 44,
- 45,
- 46
- ]
- }
- }
-]
+ {
+ "model": "member.role",
+ "pk": 1,
+ "fields": {
+ "name": "Adh\u00e9rent BDE"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 2,
+ "fields": {
+ "name": "Adh\u00e9rent Kfet"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 3,
+ "fields": {
+ "name": "Membre de club"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 4,
+ "fields": {
+ "name": "Bureau de club"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 5,
+ "fields": {
+ "name": "Pr\u00e9sident\u00b7e de club"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 6,
+ "fields": {
+ "name": "Tr\u00e9sorier\u00b7\u00e8re de club"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 7,
+ "fields": {
+ "name": "Pr\u00e9sident\u00b7e BDE"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 8,
+ "fields": {
+ "name": "Tr\u00e9sorier\u00b7\u00e8re BDE"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 9,
+ "fields": {
+ "name": "Respo info"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 10,
+ "fields": {
+ "name": "GC Kfet"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 11,
+ "fields": {
+ "name": "Res[pot]"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 12,
+ "fields": {
+ "name": "GC WEI"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 13,
+ "fields": {
+ "name": "Chef de bus"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 14,
+ "fields": {
+ "name": "Chef d'\u00e9quipe"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 15,
+ "fields": {
+ "name": "\u00c9lectron libre"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 16,
+ "fields": {
+ "name": "\u00c9lectron libre (avec perm)"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 17,
+ "fields": {
+ "name": "1A"
+ }
+ },
+ {
+ "model": "member.role",
+ "pk": 18,
+ "fields": {
+ "name": "Adhérent WEI"
+ }
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 12,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 13,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 14,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 15,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 16,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 17,
+ "fields": {}
+ },
+ {
+ "model": "wei.weirole",
+ "pk": 18,
+ "fields": {}
+ },
+ {
+ "model": "permission.permissionmask",
+ "pk": 1,
+ "fields": {
+ "rank": 0,
+ "description": "Droits basiques"
+ }
+ },
+ {
+ "model": "permission.permissionmask",
+ "pk": 2,
+ "fields": {
+ "rank": 1,
+ "description": "Droits note seulement"
+ }
+ },
+ {
+ "model": "permission.permissionmask",
+ "pk": 3,
+ "fields": {
+ "rank": 42,
+ "description": "Tous mes droits"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 1,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our User object"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 2,
+ "fields": {
+ "model": [
+ "member",
+ "profile"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our profile"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 3,
+ "fields": {
+ "model": [
+ "note",
+ "noteuser"
+ ],
+ "query": "{\"pk\": [\"user\", \"note\", \"pk\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our own note"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 4,
+ "fields": {
+ "model": [
+ "authtoken",
+ "token"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our API token"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 5,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "[\"OR\", {\"source\": [\"user\", \"note\"]}, {\"destination\": [\"user\", \"note\"]}]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our own transactions"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 6,
+ "fields": {
+ "model": [
+ "note",
+ "alias"
+ ],
+ "query": "[\"OR\", {\"note__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club__name\": \"Kfet\"}], [\"all\"]]}, {\"note__in\": [\"NoteClub\", \"objects\", [\"all\"]]}]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View aliases of clubs and members of Kfet club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 7,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "last_login",
+ "description": "Change myself's last login"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 8,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "username",
+ "description": "Change myself's username"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 9,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "first_name",
+ "description": "Change myself's first name"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 10,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "last_name",
+ "description": "Change myself's last name"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 11,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"pk\": [\"user\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "email",
+ "description": "Change myself's email"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 12,
+ "fields": {
+ "model": [
+ "authtoken",
+ "token"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "delete",
+ "mask": 1,
+ "field": "",
+ "description": "Delete API Token"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 13,
+ "fields": {
+ "model": [
+ "authtoken",
+ "token"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Create API Token"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 14,
+ "fields": {
+ "model": [
+ "note",
+ "alias"
+ ],
+ "query": "{\"note\": [\"user\", \"note\"]}",
+ "type": "delete",
+ "mask": 1,
+ "field": "",
+ "description": "Remove alias"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 15,
+ "fields": {
+ "model": [
+ "note",
+ "alias"
+ ],
+ "query": "{\"note\": [\"user\", \"note\"]}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add alias"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 16,
+ "fields": {
+ "model": [
+ "note",
+ "noteuser"
+ ],
+ "query": "{\"pk\": [\"user\", \"note\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "display_image",
+ "description": "Change myself's display image"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 17,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "[\"AND\", {\"source\": [\"user\", \"note\"]}, [\"OR\", {\"amount__lte\": [\"user\", \"note\", \"balance\"]}, {\"valid\": false}]]",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Transfer from myself's note"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 18,
+ "fields": {
+ "model": [
+ "note",
+ "note"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 1,
+ "field": "balance",
+ "description": "Update a note balance with a transaction"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 19,
+ "fields": {
+ "model": [
+ "note",
+ "note"
+ ],
+ "query": "[\"OR\", {\"pk\": [\"club\", \"note\", \"pk\"]}, {\"pk__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club\": [\"club\"]}], [\"all\"]]}]",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View notes of club members"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 20,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Create transactions with a club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 21,
+ "fields": {
+ "model": [
+ "note",
+ "recurrenttransaction"
+ ],
+ "query": "[\"AND\", {\"destination\": [\"club\", \"note\"]}, [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Create transactions from buttons with a club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 22,
+ "fields": {
+ "model": [
+ "member",
+ "club"
+ ],
+ "query": "{\"pk\": [\"club\", \"pk\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View club infos"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 23,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 1,
+ "field": "valid",
+ "description": "Update validation status of a transaction"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 24,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View all transactions"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 25,
+ "fields": {
+ "model": [
+ "note",
+ "notespecial"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "Display credit/debit interface"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 26,
+ "fields": {
+ "model": [
+ "note",
+ "specialtransaction"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Create credit/debit transaction"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 27,
+ "fields": {
+ "model": [
+ "note",
+ "templatecategory"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View button categories"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 28,
+ "fields": {
+ "model": [
+ "note",
+ "templatecategory"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Change button category"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 29,
+ "fields": {
+ "model": [
+ "note",
+ "templatecategory"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add button category"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 30,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View buttons"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 31,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add buttons"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 32,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Update buttons"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 33,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Create any transaction"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 34,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "[\"OR\", {\"valid\": true}, {\"creater\": [\"user\"]}]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View valid activites"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 35,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "[\"AND\", {\"valid\": false}, {\"creater\": [\"user\"]}]",
+ "type": "change",
+ "mask": 1,
+ "field": "",
+ "description": "Change our activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 36,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "{\"creater\": [\"user\"], \"valid\": false}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 37,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 2,
+ "field": "valid",
+ "description": "Validate activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 38,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 2,
+ "field": "open",
+ "description": "Open activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 39,
+ "fields": {
+ "model": [
+ "activity",
+ "guest"
+ ],
+ "query": "{\"inviter\": [\"user\", \"note\"], \"activity__activity_type__can_invite\": true}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Invite people to activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 40,
+ "fields": {
+ "model": [
+ "activity",
+ "guest"
+ ],
+ "query": "{\"inviter\": [\"user\", \"note\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View invited people"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 41,
+ "fields": {
+ "model": [
+ "activity",
+ "activity"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View all activities"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 42,
+ "fields": {
+ "model": [
+ "activity",
+ "guest"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "View all invited people"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 43,
+ "fields": {
+ "model": [
+ "activity",
+ "entry"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Manage entries"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 44,
+ "fields": {
+ "model": [
+ "activity",
+ "guesttransaction"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Add invitation transactions"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 45,
+ "fields": {
+ "model": [
+ "activity",
+ "guesttransaction"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View invitation transactions"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 46,
+ "fields": {
+ "model": [
+ "activity",
+ "guesttransaction"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 2,
+ "field": "valid",
+ "description": "Validate invitation transactions"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 47,
+ "fields": {
+ "model": [
+ "member",
+ "club"
+ ],
+ "query": "{\"pk\": [\"club\", \"pk\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "",
+ "description": "Update club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 48,
+ "fields": {
+ "model": [
+ "member",
+ "membership"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View our memberships"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 49,
+ "fields": {
+ "model": [
+ "member",
+ "membership"
+ ],
+ "query": "{\"club\": [\"club\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View club's memberships"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 50,
+ "fields": {
+ "model": [
+ "member",
+ "membership"
+ ],
+ "query": "{\"club\": [\"club\"]}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Add a membership to a club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 51,
+ "fields": {
+ "model": [
+ "member",
+ "membership"
+ ],
+ "query": "{\"club\": [\"club\"]}",
+ "type": "change",
+ "mask": 2,
+ "field": "roles",
+ "description": "Update user roles"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 52,
+ "fields": {
+ "model": [
+ "member",
+ "profile"
+ ],
+ "query": "{\"user\": [\"user\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "",
+ "description": "Change own profile"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 53,
+ "fields": {
+ "model": [
+ "member",
+ "profile"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 2,
+ "field": "",
+ "description": "Change any profile"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 54,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 2,
+ "field": "",
+ "description": "Change any user"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 55,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add user"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 56,
+ "fields": {
+ "model": [
+ "member",
+ "profile"
+ ],
+ "query": "{\"email_confirmed\": false, \"registration_valid\": false}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add profile"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 57,
+ "fields": {
+ "model": [
+ "auth",
+ "user"
+ ],
+ "query": "{\"profile__registration_valid\": false}",
+ "type": "delete",
+ "mask": 2,
+ "field": "",
+ "description": "Delete pre-registered user"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 58,
+ "fields": {
+ "model": [
+ "member",
+ "profile"
+ ],
+ "query": "{\"registration_valid\": false}",
+ "type": "delete",
+ "mask": 2,
+ "field": "",
+ "description": "Delete pre-registered user profile"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 59,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{\"destination\": [\"club\", \"note\"]}",
+ "type": "view",
+ "mask": 2,
+ "field": "",
+ "description": "New club button"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 60,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{\"destination\": [\"club\", \"note\"]}",
+ "type": "add",
+ "mask": 2,
+ "field": "",
+ "description": "Create club button"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 61,
+ "fields": {
+ "model": [
+ "note",
+ "transactiontemplate"
+ ],
+ "query": "{\"destination\": [\"club\", \"note\"]}",
+ "type": "change",
+ "mask": 2,
+ "field": "",
+ "description": "Update club button"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 62,
+ "fields": {
+ "model": [
+ "note",
+ "transaction"
+ ],
+ "query": "[\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View transactions of a club"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 63,
+ "fields": {
+ "model": [
+ "treasury",
+ "invoice"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 3,
+ "field": "",
+ "description": "View invoices"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 64,
+ "fields": {
+ "model": [
+ "treasury",
+ "invoice"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add invoice"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 65,
+ "fields": {
+ "model": [
+ "treasury",
+ "invoice"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Change invoice"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 66,
+ "fields": {
+ "model": [
+ "treasury",
+ "product"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 3,
+ "field": "",
+ "description": "View products"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 67,
+ "fields": {
+ "model": [
+ "treasury",
+ "product"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add products"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 68,
+ "fields": {
+ "model": [
+ "treasury",
+ "product"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Change product"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 69,
+ "fields": {
+ "model": [
+ "treasury",
+ "product"
+ ],
+ "query": "{}",
+ "type": "delete",
+ "mask": 3,
+ "field": "",
+ "description": "Delete product"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 70,
+ "fields": {
+ "model": [
+ "treasury",
+ "sogecredit"
+ ],
+ "query": "{\"credit_transaction\": null}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add Soci\u00e9t\u00e9 g\u00e9n\u00e9rale credit"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 71,
+ "fields": {
+ "model": [
+ "treasury",
+ "sogecredit"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 3,
+ "field": "",
+ "description": "View all Soci\u00e9t\u00e9 g\u00e9n\u00e9rale credits"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 72,
+ "fields": {
+ "model": [
+ "treasury",
+ "sogecredit"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 1,
+ "field": "",
+ "description": "Update Soci\u00e9t\u00e9 g\u00e9n\u00e9rale credit"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 73,
+ "fields": {
+ "model": [
+ "treasury",
+ "sogecredit"
+ ],
+ "query": "{}",
+ "type": "delete",
+ "mask": 3,
+ "field": "",
+ "description": "Delete Soci\u00e9t\u00e9 g\u00e9n\u00e9rale credit"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 74,
+ "fields": {
+ "model": [
+ "wei",
+ "weiclub"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Create a WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 75,
+ "fields": {
+ "model": [
+ "wei",
+ "weiclub"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Update all WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 76,
+ "fields": {
+ "model": [
+ "wei",
+ "weiclub"
+ ],
+ "query": "{\"pk\": [\"club\", \"pk\"]}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Update this WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 77,
+ "fields": {
+ "model": [
+ "wei",
+ "weiclub"
+ ],
+ "query": "{\"pk\": [\"club\", \"pk\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View my WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 78,
+ "fields": {
+ "model": [
+ "wei",
+ "weiclub"
+ ],
+ "query": "{\"membership_start__lte\": [\"today\"], \"year\": [\"today\", \"year\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 79,
+ "fields": {
+ "model": [
+ "wei",
+ "weirole"
+ ],
+ "query": "{}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View WEI Roles"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 80,
+ "fields": {
+ "model": [
+ "wei",
+ "weirole"
+ ],
+ "query": "{}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add WEI Role"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 81,
+ "fields": {
+ "model": [
+ "wei",
+ "weirole"
+ ],
+ "query": "{}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Change WEI Role"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 82,
+ "fields": {
+ "model": [
+ "wei",
+ "weirole"
+ ],
+ "query": "{}",
+ "type": "delete",
+ "mask": 3,
+ "field": "",
+ "description": "Delete WEI Role"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 83,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"user\": [\"user\"], \"wei__year\": [\"today\", \"year\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"], \"membership\": null}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Register myself to the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 84,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"first_year\": true, \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"], \"membership\": null}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Register first year members to the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 85,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"], \"membership\": null}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Register anyone to this WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 86,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"]}",
+ "type": "delete",
+ "mask": 1,
+ "field": "",
+ "description": "Delete WEI registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 87,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View my own WEI registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 88,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View all WEI Registrations"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 89,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "soge_credit",
+ "description": "Update the soge credit field of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 90,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "soge_credit",
+ "description": "Update the soge credit field of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 91,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "caution_check",
+ "description": "Update the caution check field of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 92,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "birth_date",
+ "description": "Update the birth date of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 93,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "birth_date",
+ "description": "Update the birth date of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 94,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "gender",
+ "description": "Update the gender of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 95,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "gender",
+ "description": "Update the gender of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 96,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "health_issues",
+ "description": "Update the health issues of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 97,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "health_issues",
+ "description": "Update the health issues of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 98,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "emergency_contact_name",
+ "description": "Update the emergency contact name of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 99,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "emergency_contact_name",
+ "description": "Update the emergency contact name of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 100,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "emergency_contact_phone",
+ "description": "Update the emergency contact phone of any WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 101,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"]}, [\"OR\", {\"wei\": [\"club\"]}, {\"wei__year\": [\"today\", \"year\"], \"membership\": null}]]",
+ "type": "change",
+ "mask": 1,
+ "field": "emergency_contact_phone",
+ "description": "Update the emergency contact phone of my own WEI Registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 102,
+ "fields": {
+ "model": [
+ "wei",
+ "weiregistration"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "information_json",
+ "description": "Update information of any WEI registration"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 103,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "{\"wei\": [\"club\"]}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Add a bus for the current WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 104,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 3,
+ "field": "name",
+ "description": "Update the name of a bus for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 105,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 3,
+ "field": "description",
+ "description": "Update the description of a bus for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 106,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Create a bus team for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 107,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"wei\": [\"club\"], \"wei__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 3,
+ "field": "",
+ "description": "Update a bus team for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 108,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "[\"AND\", {\"wei\": [\"club\"]}, [\"OR\", [\"NOT\", [\"membership\", \"registration\", \"first_year\"]], {\"wei__date_end__lte\": [\"today\"]}]]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View buses of the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 109,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "[\"AND\", {\"wei\": [\"club\"]}, [\"OR\", [\"NOT\", [\"membership\", \"registration\", \"first_year\"]], {\"wei__date_end__lte\": [\"today\"]}]]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View bus teams of the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 110,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "[\"AND\", {\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}, [\"OR\", {\"registration__soge_credit\": true}, {\"user__note__balance__gte\": [\"F\", \"fee\"]}]]",
+ "type": "add",
+ "mask": 3,
+ "field": "",
+ "description": "Create a WEI membership for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 111,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "{\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "bus",
+ "description": "Update the bus of a WEI membership"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 112,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "{\"club\": [\"club\"], \"club__weiclub__membership_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "team",
+ "description": "Update the team of a WEI membership"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 113,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "{\"club\": [\"club\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View all WEI Memberships for the last WEI"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 114,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "[\"AND\", {\"user\": [\"user\"], \"club\": [\"club\"]}, [\"OR\", {\"registration__first_year\": false, \"club__weiclub__date_end__lte\": [\"today\"]}]]",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View my own WEI membership if I am an old member or if the WEI is past"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 115,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "{\"club\": [\"club\"], \"bus\": [\"membership\", \"weimembership\", \"bus\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View the members of the bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 116,
+ "fields": {
+ "model": [
+ "wei",
+ "weimembership"
+ ],
+ "query": "{\"club\": [\"club\"], \"team\": [\"membership\", \"weimembership\", \"team\"]}",
+ "type": "view",
+ "mask": 1,
+ "field": "",
+ "description": "View the members of the team"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 117,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "{\"pk\": [\"membership\", \"bus\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "name",
+ "description": "Update the name of my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 118,
+ "fields": {
+ "model": [
+ "wei",
+ "bus"
+ ],
+ "query": "{\"pk\": [\"membership\", \"bus\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "description",
+ "description": "Update the description of my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 119,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"bus\": [\"membership\", \"bus\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "add",
+ "mask": 1,
+ "field": "",
+ "description": "Add a team to my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 120,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"bus\": [\"membership\", \"bus\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "name",
+ "description": "Update the name of a team of my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 121,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"bus\": [\"membership\", \"bus\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "color",
+ "description": "Update the color of a team of my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 122,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"bus\": [\"membership\", \"bus\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "description",
+ "description": "Update the description of a team of my bus"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 123,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"pk\": [\"membership\", \"team\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "name",
+ "description": "Update the name of my team"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 124,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"pk\": [\"membership\", \"team\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "color",
+ "description": "Update the color of my team"
+ }
+ },
+ {
+ "model": "permission.permission",
+ "pk": 125,
+ "fields": {
+ "model": [
+ "wei",
+ "busteam"
+ ],
+ "query": "{\"pk\": [\"membership\", \"team\", \"pk\"], \"wei__date_end__gte\": [\"today\"]}",
+ "type": "change",
+ "mask": 1,
+ "field": "description",
+ "description": "Update the description of my team"
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 1,
+ "fields": {
+ "role": 1,
+ "permissions": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 48,
+ 52
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 2,
+ "fields": {
+ "role": 2,
+ "permissions": [
+ 34,
+ 35,
+ 36,
+ 6,
+ 39,
+ 40,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 70,
+ 108,
+ 109,
+ 78,
+ 79,
+ 83
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 4,
+ "fields": {
+ "role": 4,
+ "permissions": [
+ 22,
+ 47,
+ 49
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 5,
+ "fields": {
+ "role": 5,
+ "permissions": [
+ 50,
+ 51,
+ 62
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 6,
+ "fields": {
+ "role": 6,
+ "permissions": [
+ 19,
+ 20,
+ 21,
+ 27,
+ 59,
+ 60,
+ 61,
+ 62
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 7,
+ "fields": {
+ "role": 7,
+ "permissions": [
+ 24,
+ 25,
+ 26,
+ 27,
+ 33
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 8,
+ "fields": {
+ "role": 8,
+ "permissions": [
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 72,
+ 73,
+ 71
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 9,
+ "fields": {
+ "role": 9,
+ "permissions": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 111,
+ 112,
+ 113,
+ 114,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 123,
+ 124,
+ 125
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 10,
+ "fields": {
+ "role": 10,
+ "permissions": [
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 11,
+ "fields": {
+ "role": 11,
+ "permissions": [
+ 37,
+ 38,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 12,
+ "fields": {
+ "role": 12,
+ "permissions": [
+ 76,
+ 80,
+ 81,
+ 82,
+ 85,
+ 86,
+ 88,
+ 89,
+ 91,
+ 92,
+ 94,
+ 96,
+ 98,
+ 100,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 110,
+ 111,
+ 112,
+ 113
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 13,
+ "fields": {
+ "role": 13,
+ "permissions": [
+ 115,
+ 117,
+ 118,
+ 120,
+ 121,
+ 122
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 14,
+ "fields": {
+ "role": 14,
+ "permissions": [
+ 116
+ ]
+ }
+ },
+ {
+ "model": "permission.rolepermissions",
+ "pk": 16,
+ "fields": {
+ "role": 18,
+ "permissions": [
+ 77,
+ 84,
+ 87,
+ 90,
+ 93,
+ 95,
+ 97,
+ 99,
+ 101,
+ 108,
+ 109,
+ 114
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/apps/permission/models.py b/apps/permission/models.py
index 81174389..fe18c226 100644
--- a/apps/permission/models.py
+++ b/apps/permission/models.py
@@ -120,7 +120,12 @@ class Permission(models.Model):
('delete', 'delete')
]
- model = models.ForeignKey(ContentType, on_delete=models.CASCADE, related_name='+')
+ model = models.ForeignKey(
+ ContentType,
+ on_delete=models.CASCADE,
+ related_name='+',
+ verbose_name=_("model"),
+ )
# A json encoded Q object with the following grammar
# query -> [] | {} (the empty query representing all objects)
@@ -142,18 +147,34 @@ class Permission(models.Model):
# Examples:
# Q(is_superuser=True) := {"is_superuser": true}
# ~Q(is_superuser=True) := ["NOT", {"is_superuser": true}]
- query = models.TextField()
+ query = models.TextField(
+ verbose_name=_("query"),
+ )
- type = models.CharField(max_length=15, choices=PERMISSION_TYPES)
+ type = models.CharField(
+ max_length=15,
+ choices=PERMISSION_TYPES,
+ verbose_name=_("type"),
+ )
mask = models.ForeignKey(
PermissionMask,
on_delete=models.PROTECT,
+ related_name="permissions",
+ verbose_name=_("mask"),
)
- field = models.CharField(max_length=255, blank=True)
+ field = models.CharField(
+ max_length=255,
+ blank=True,
+ verbose_name=_("field"),
+ )
- description = models.CharField(max_length=255, blank=True)
+ description = models.CharField(
+ max_length=255,
+ blank=True,
+ verbose_name=_("description"),
+ )
class Meta:
unique_together = ('model', 'query', 'type', 'field')
@@ -277,24 +298,22 @@ class Permission(models.Model):
return InstancedPermission(self.model, query, self.type, self.field, self.mask, **kwargs)
def __str__(self):
- if self.field:
- return _("Can {type} {model}.{field} in {query}").format(type=self.type, model=self.model, field=self.field, query=self.query)
- else:
- return _("Can {type} {model} in {query}").format(type=self.type, model=self.model, query=self.query)
+ return self.description
class RolePermissions(models.Model):
"""
Permissions associated with a Role
"""
- role = models.ForeignKey(
+ role = models.OneToOneField(
Role,
on_delete=models.PROTECT,
- related_name='+',
+ related_name='permissions',
verbose_name=_('role'),
)
permissions = models.ManyToManyField(
Permission,
+ verbose_name=_("permissions"),
)
def __str__(self):
diff --git a/apps/permission/signals.py b/apps/permission/signals.py
index bf54b72f..cac0a8a0 100644
--- a/apps/permission/signals.py
+++ b/apps/permission/signals.py
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.exceptions import PermissionDenied
+from django.utils.translation import gettext_lazy as _
from note_kfet.middlewares import get_current_authenticated_user
from permission.backends import PermissionBackend
@@ -57,13 +58,19 @@ def pre_save_object(sender, instance, **kwargs):
if old_value == new_value:
continue
if not PermissionBackend.check_perm(user, app_label + ".change_" + model_name + "_" + field_name, instance):
- raise PermissionDenied
+ raise PermissionDenied(
+ _("You don't have the permission to change the field {field} on this instance of model"
+ " {app_label}.{model_name}.")
+ .format(field=field_name, app_label=app_label, model_name=model_name, )
+ )
else:
# We check if the user has right to add the object
has_perm = PermissionBackend.check_perm(user, app_label + ".add_" + model_name, instance)
if not has_perm:
- raise PermissionDenied
+ raise PermissionDenied(
+ _("You don't have the permission to add this instance of model {app_label}.{model_name}.")
+ .format(app_label=app_label, model_name=model_name, ))
def pre_delete_object(instance, **kwargs):
@@ -88,4 +95,6 @@ def pre_delete_object(instance, **kwargs):
# We check if the user has rights to delete the object
if not PermissionBackend.check_perm(user, app_label + ".delete_" + model_name, instance):
- raise PermissionDenied
+ raise PermissionDenied(
+ _("You don't have the permission to delete this instance of model {app_label}.{model_name}.")
+ .format(app_label=app_label, model_name=model_name))
diff --git a/apps/permission/urls.py b/apps/permission/urls.py
new file mode 100644
index 00000000..c571c520
--- /dev/null
+++ b/apps/permission/urls.py
@@ -0,0 +1,10 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.urls import path
+from permission.views import RightsView
+
+app_name = 'permission'
+urlpatterns = [
+ path('rights', RightsView.as_view(), name="rights"),
+]
diff --git a/apps/permission/views.py b/apps/permission/views.py
index bbd9872f..cbd26a19 100644
--- a/apps/permission/views.py
+++ b/apps/permission/views.py
@@ -1,11 +1,60 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
+from datetime import date
-from permission.backends import PermissionBackend
+from django.forms import HiddenInput
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import UpdateView, TemplateView
+from member.models import Role, Membership
+
+from .backends import PermissionBackend
class ProtectQuerysetMixin:
+ """
+ This is a View class decorator and not a proper View class.
+ Ensure that the user has the right to see or update objects.
+ Display 404 error if the user can't see an object, remove the fields the user can't
+ update on an update form (useful if the user can't change only specified fields).
+ """
def get_queryset(self, **kwargs):
qs = super().get_queryset(**kwargs)
-
return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view"))
+
+ def get_form(self, form_class=None):
+ form = super().get_form(form_class)
+
+ if not isinstance(self, UpdateView):
+ return form
+
+ # If we are in an UpdateView, we display only the fields the user has right to see.
+ # No worry if the user change the hidden fields: a 403 error will be performed if the user tries to make
+ # a custom request.
+ # We could also delete the field, but some views might be affected.
+ for key in form.base_fields:
+ if not PermissionBackend.check_perm(self.request.user, "wei.change_weiregistration_" + key, self.object):
+ form.fields[key].widget = HiddenInput()
+
+ return form
+
+
+class RightsView(TemplateView):
+ template_name = "permission/all_rights.html"
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+
+ context["title"] = _("All rights")
+ roles = Role.objects.all()
+ context["roles"] = roles
+ if self.request.user.is_authenticated:
+ active_memberships = Membership.objects.filter(user=self.request.user,
+ date_start__lte=date.today(),
+ date_end__gte=date.today()).all()
+ else:
+ active_memberships = Membership.objects.none()
+
+ for role in roles:
+ role.clubs = [membership.club for membership in active_memberships if role in membership.roles.all()]
+
+ return context
diff --git a/apps/registration/forms.py b/apps/registration/forms.py
index cba5c2ae..46559487 100644
--- a/apps/registration/forms.py
+++ b/apps/registration/forms.py
@@ -27,6 +27,15 @@ class SignUpForm(UserCreationForm):
fields = ('first_name', 'last_name', 'username', 'email', )
+class WEISignupForm(forms.Form):
+ wei_registration = forms.BooleanField(
+ label=_("Register to the WEI"),
+ required=False,
+ help_text=_("Check this case if you want to register to the WEI. If you hesitate, you will be able to register"
+ " later, after validating your account in the Kfet."),
+ )
+
+
class ValidationForm(forms.Form):
"""
Validate the inscription of the new users and pay memberships.
diff --git a/apps/registration/views.py b/apps/registration/views.py
index 35391b05..2c91a604 100644
--- a/apps/registration/views.py
+++ b/apps/registration/views.py
@@ -11,12 +11,12 @@ from django.urls import reverse_lazy
from django.utils.http import urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _
from django.views import View
-from django.views.generic import CreateView, TemplateView, DetailView, FormView
+from django.views.generic import CreateView, TemplateView, DetailView
from django.views.generic.edit import FormMixin
from django_tables2 import SingleTableView
from member.forms import ProfileForm
from member.models import Membership, Club, Role
-from note.models import SpecialTransaction, NoteSpecial
+from note.models import SpecialTransaction
from note.templatetags.pretty_money import pretty_money
from permission.backends import PermissionBackend
from permission.views import ProtectQuerysetMixin
@@ -32,13 +32,13 @@ class UserCreateView(CreateView):
"""
form_class = SignUpForm
- success_url = reverse_lazy('registration:email_validation_sent')
template_name = 'registration/signup.html'
second_form = ProfileForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["profile_form"] = self.second_form()
+ del context["profile_form"].fields["section"]
return context
@@ -67,6 +67,9 @@ class UserCreateView(CreateView):
return super().form_valid(form)
+ def get_success_url(self):
+ return reverse_lazy('registration:email_validation_sent')
+
class UserValidateView(TemplateView):
"""
@@ -112,7 +115,7 @@ class UserValidateView(TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['user'] = self.get_user(self.kwargs["uidb64"])
+ context['user_object'] = self.get_user(self.kwargs["uidb64"])
context['login_url'] = resolve_url(settings.LOGIN_URL)
if self.validlink:
context['validlink'] = True
@@ -263,17 +266,17 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
fee += kfet_fee
if soge:
- # Fill payment information if Société Générale pays the inscription
- credit_type = NoteSpecial.objects.get(special_type="Virement bancaire")
- credit_amount = fee
- bank = "Société générale"
+ # If the bank pays, then we don't credit now. Treasurers will validate the transaction
+ # and credit the note later.
+ credit_type = None
- print("OK")
+ if credit_type is None:
+ credit_amount = 0
if join_Kfet and not join_BDE:
form.add_error('join_Kfet', _("You must join BDE club before joining Kfet club."))
- if fee > credit_amount:
+ if fee > credit_amount and not soge:
# Check if the user credits enough money
form.add_error('credit_type',
_("The entered amount is not enough for the memberships, should be at least {}")
@@ -295,10 +298,9 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
ret = super().form_valid(form)
user.is_active = user.profile.email_confirmed or user.is_superuser
user.profile.registration_valid = True
- # Store if Société générale paid for next years
- user.profile.soge = soge
user.save()
user.profile.save()
+ user.refresh_from_db()
if credit_type is not None and credit_amount > 0:
# Credit the note
@@ -316,21 +318,29 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
if join_BDE:
# Create membership for the user to the BDE starting today
- membership = Membership.objects.create(
+ membership = Membership(
club=bde,
user=user,
fee=bde_fee,
)
+ if soge:
+ membership._soge = True
+ membership.save()
+ membership.refresh_from_db()
membership.roles.add(Role.objects.get(name="Adhérent BDE"))
membership.save()
if join_Kfet:
# Create membership for the user to the Kfet starting today
- membership = Membership.objects.create(
+ membership = Membership(
club=kfet,
user=user,
fee=kfet_fee,
)
+ if soge:
+ membership._soge = True
+ membership.save()
+ membership.refresh_from_db()
membership.roles.add(Role.objects.get(name="Adhérent Kfet"))
membership.save()
diff --git a/apps/scripts b/apps/scripts
index b9fdced3..f0aa4269 160000
--- a/apps/scripts
+++ b/apps/scripts
@@ -1 +1 @@
-Subproject commit b9fdced3c2ce34168b8f0d6004a20a69ca16e0de
+Subproject commit f0aa426950b9b867bf99233795e260871be2cb99
diff --git a/apps/treasury/admin.py b/apps/treasury/admin.py
index abeec3e3..9c8aaf2e 100644
--- a/apps/treasury/admin.py
+++ b/apps/treasury/admin.py
@@ -3,7 +3,7 @@
from django.contrib import admin
-from .models import RemittanceType, Remittance
+from .models import RemittanceType, Remittance, SogeCredit
@admin.register(RemittanceType)
@@ -25,3 +25,6 @@ class RemittanceAdmin(admin.ModelAdmin):
if not obj:
return True
return not obj.closed and super().has_change_permission(request, obj)
+
+
+admin.site.register(SogeCredit)
diff --git a/apps/treasury/api/serializers.py b/apps/treasury/api/serializers.py
index f1bbef75..0acb0aa1 100644
--- a/apps/treasury/api/serializers.py
+++ b/apps/treasury/api/serializers.py
@@ -4,7 +4,7 @@
from rest_framework import serializers
from note.api.serializers import SpecialTransactionSerializer
-from ..models import Invoice, Product, RemittanceType, Remittance
+from ..models import Invoice, Product, RemittanceType, Remittance, SogeCredit
class ProductSerializer(serializers.ModelSerializer):
@@ -60,3 +60,14 @@ class RemittanceSerializer(serializers.ModelSerializer):
def get_transactions(self, obj):
return serializers.ListSerializer(child=SpecialTransactionSerializer()).to_representation(obj.transactions)
+
+
+class SogeCreditSerializer(serializers.ModelSerializer):
+ """
+ REST API Serializer for SogeCredit types.
+ The djangorestframework plugin will analyse the model `SogeCredit` and parse all fields in the API.
+ """
+
+ class Meta:
+ model = SogeCredit
+ fields = '__all__'
diff --git a/apps/treasury/api/urls.py b/apps/treasury/api/urls.py
index 30ac00e1..70d81f77 100644
--- a/apps/treasury/api/urls.py
+++ b/apps/treasury/api/urls.py
@@ -1,7 +1,7 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
-from .views import InvoiceViewSet, ProductViewSet, RemittanceViewSet, RemittanceTypeViewSet
+from .views import InvoiceViewSet, ProductViewSet, RemittanceViewSet, RemittanceTypeViewSet, SogeCreditViewSet
def register_treasury_urls(router, path):
@@ -12,3 +12,4 @@ def register_treasury_urls(router, path):
router.register(path + '/product', ProductViewSet)
router.register(path + '/remittance_type', RemittanceTypeViewSet)
router.register(path + '/remittance', RemittanceViewSet)
+ router.register(path + '/soge_credit', SogeCreditViewSet)
diff --git a/apps/treasury/api/views.py b/apps/treasury/api/views.py
index 7a70fd24..ee97e6ac 100644
--- a/apps/treasury/api/views.py
+++ b/apps/treasury/api/views.py
@@ -5,8 +5,9 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from api.viewsets import ReadProtectedModelViewSet
-from .serializers import InvoiceSerializer, ProductSerializer, RemittanceTypeSerializer, RemittanceSerializer
-from ..models import Invoice, Product, RemittanceType, Remittance
+from .serializers import InvoiceSerializer, ProductSerializer, RemittanceTypeSerializer, RemittanceSerializer,\
+ SogeCreditSerializer
+from ..models import Invoice, Product, RemittanceType, Remittance, SogeCredit
class InvoiceViewSet(ReadProtectedModelViewSet):
@@ -39,7 +40,7 @@ class RemittanceTypeViewSet(ReadProtectedModelViewSet):
The djangorestframework plugin will get all `RemittanceType` objects, serialize it to JSON with the given serializer
then render it on /api/treasury/remittance_type/
"""
- queryset = RemittanceType.objects.all()
+ queryset = RemittanceType.objects
serializer_class = RemittanceTypeSerializer
@@ -49,5 +50,15 @@ class RemittanceViewSet(ReadProtectedModelViewSet):
The djangorestframework plugin will get all `Remittance` objects, serialize it to JSON with the given serializer,
then render it on /api/treasury/remittance/
"""
- queryset = Remittance.objects.all()
+ queryset = Remittance.objects
serializer_class = RemittanceSerializer
+
+
+class SogeCreditViewSet(ReadProtectedModelViewSet):
+ """
+ REST API View set.
+ The djangorestframework plugin will get all `SogeCredit` objects, serialize it to JSON with the given serializer,
+ then render it on /api/treasury/soge_credit/
+ """
+ queryset = SogeCredit.objects
+ serializer_class = SogeCreditSerializer
diff --git a/apps/treasury/models.py b/apps/treasury/models.py
index ca1da3a4..5628504b 100644
--- a/apps/treasury/models.py
+++ b/apps/treasury/models.py
@@ -1,11 +1,13 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
+from datetime import datetime
+from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
-from note.models import NoteSpecial, SpecialTransaction
+from note.models import NoteSpecial, SpecialTransaction, MembershipTransaction
class Invoice(models.Model):
@@ -207,3 +209,101 @@ class SpecialTransactionProxy(models.Model):
class Meta:
verbose_name = _("special transaction proxy")
verbose_name_plural = _("special transaction proxies")
+
+
+class SogeCredit(models.Model):
+ """
+ Manage the credits from the Société générale.
+ """
+ user = models.OneToOneField(
+ User,
+ on_delete=models.PROTECT,
+ verbose_name=_("user"),
+ )
+
+ transactions = models.ManyToManyField(
+ MembershipTransaction,
+ related_name="+",
+ verbose_name=_("membership transactions"),
+ )
+
+ credit_transaction = models.OneToOneField(
+ SpecialTransaction,
+ on_delete=models.SET_NULL,
+ verbose_name=_("credit transaction"),
+ null=True,
+ )
+
+ @property
+ def valid(self):
+ return self.credit_transaction is not None
+
+ @property
+ def amount(self):
+ return sum(transaction.total for transaction in self.transactions.all())
+
+ def invalidate(self):
+ """
+ Invalidating a Société générale delete the transaction of the bank if it was already created.
+ Treasurers must know what they do, With Great Power Comes Great Responsibility...
+ """
+ if self.valid:
+ self.credit_transaction.valid = False
+ self.credit_transaction._force_save = True
+ self.credit_transaction.save()
+ self.credit_transaction._force_delete = True
+ self.credit_transaction.delete()
+ self.credit_transaction = None
+ for transaction in self.transactions.all():
+ transaction.valid = False
+ transaction._force_save = True
+ transaction.save()
+
+ def validate(self, force=False):
+ if self.valid and not force:
+ # The credit is already done
+ return
+
+ # First invalidate all transaction and delete the credit if already did (and force mode)
+ self.invalidate()
+ self.credit_transaction = SpecialTransaction.objects.create(
+ source=NoteSpecial.objects.get(special_type="Virement bancaire"),
+ destination=self.user.note,
+ quantity=1,
+ amount=self.amount,
+ reason="Crédit société générale",
+ last_name=self.user.last_name,
+ first_name=self.user.first_name,
+ bank="Société générale",
+ )
+ self.save()
+
+ for transaction in self.transactions.all():
+ transaction.valid = True
+ transaction._force_save = True
+ transaction.created_at = datetime.now()
+ transaction.save()
+
+ def delete(self, **kwargs):
+ """
+ Deleting a SogeCredit is equivalent to say that the Société générale didn't pay.
+ Treasurers must know what they do, this is difficult to undo this operation.
+ With Great Power Comes Great Responsibility...
+ """
+
+ total_fee = sum(transaction.total for transaction in self.transactions.all() if not transaction.valid)
+ if self.user.note.balance < total_fee:
+ raise ValidationError(_("This user doesn't have enough money to pay the memberships with its note. "
+ "Please ask her/him to credit the note before invalidating this credit."))
+
+ self.invalidate()
+ for transaction in self.transactions.all():
+ transaction._force_save = True
+ transaction.valid = True
+ transaction.created_at = datetime.now()
+ transaction.save()
+ super().delete(**kwargs)
+
+ class Meta:
+ verbose_name = _("Credit from the Société générale")
+ verbose_name_plural = _("Credits from the Société générale")
diff --git a/apps/treasury/tables.py b/apps/treasury/tables.py
index 1ecc04db..9f4e43e6 100644
--- a/apps/treasury/tables.py
+++ b/apps/treasury/tables.py
@@ -7,7 +7,7 @@ from django_tables2 import A
from note.models import SpecialTransaction
from note.templatetags.pretty_money import pretty_money
-from .models import Invoice, Remittance
+from .models import Invoice, Remittance, SogeCredit
class InvoiceTable(tables.Table):
@@ -101,3 +101,28 @@ class SpecialTransactionTable(tables.Table):
model = SpecialTransaction
template_name = 'django_tables2/bootstrap4.html'
fields = ('id', 'source', 'destination', 'last_name', 'first_name', 'bank', 'amount', 'reason',)
+
+
+class SogeCreditTable(tables.Table):
+ user = tables.LinkColumn(
+ 'treasury:manage_soge_credit',
+ args=[A('pk')],
+ )
+
+ amount = tables.Column(
+ verbose_name=_("Amount"),
+ )
+
+ valid = tables.Column(
+ verbose_name=_("Valid"),
+ )
+
+ def render_amount(self, value):
+ return pretty_money(value)
+
+ def render_valid(self, value):
+ return _("Yes") if value else _("No")
+
+ class Meta:
+ model = SogeCredit
+ fields = ('user', 'amount', 'valid', )
diff --git a/apps/treasury/urls.py b/apps/treasury/urls.py
index d44cc414..8606fb5b 100644
--- a/apps/treasury/urls.py
+++ b/apps/treasury/urls.py
@@ -4,7 +4,8 @@
from django.urls import path
from .views import InvoiceCreateView, InvoiceListView, InvoiceUpdateView, InvoiceRenderView, RemittanceListView,\
- RemittanceCreateView, RemittanceUpdateView, LinkTransactionToRemittanceView, UnlinkTransactionToRemittanceView
+ RemittanceCreateView, RemittanceUpdateView, LinkTransactionToRemittanceView, UnlinkTransactionToRemittanceView,\
+ SogeCreditListView, SogeCreditManageView
app_name = 'treasury'
urlpatterns = [
@@ -21,4 +22,7 @@ urlpatterns = [
path('remittance/link_transaction/%(request_path)s
was not found on the server."
+msgstr ""
+
+#: templates/500.html:6
+msgid "Server error"
+msgstr ""
+
+#: templates/500.html:7
+msgid ""
+"Sorry, an error occurred when processing your request. An email has been "
+"sent to webmasters with the detail of the error, and this will be fixed "
+"soon. You can now drink a beer."
+msgstr ""
+
#: templates/activity/activity_detail.html:29
msgid "creater"
msgstr ""
@@ -1064,7 +1521,11 @@ msgstr ""
msgid "Registrations"
msgstr ""
-#: templates/base.html:150
+#: templates/base.html:120
+msgid "Rights"
+msgstr ""
+
+#: templates/base.html:158
msgid ""
"Your e-mail address is not validated. Please check your mail inbox and click "
"on the validation link."
@@ -1082,49 +1543,6 @@ msgid ""
"upgrading."
msgstr ""
-#: templates/cas_server/logged.html:4
-msgid ""
-"Log In Successful
You have successfully logged into the Central "
-"Authentication Service.
For security reasons, please Log Out and Exit "
-"your web browser when you are done accessing services that require "
-"authentication!"
-msgstr ""
-
-#: templates/cas_server/logged.html:8
-msgid "Log me out from all my sessions"
-msgstr ""
-
-#: templates/cas_server/logged.html:14
-msgid "Forget the identity provider"
-msgstr ""
-
-#: templates/cas_server/logged.html:18
-msgid "Logout"
-msgstr ""
-
-#: templates/cas_server/login.html:6
-msgid "Please log in"
-msgstr ""
-
-#: templates/cas_server/login.html:11
-msgid ""
-"If you don't have any Note Kfet account, please follow this link to sign up."
-msgstr ""
-
-#: templates/cas_server/login.html:17
-msgid "Login"
-msgstr ""
-
-#: templates/cas_server/warn.html:9
-msgid "Connect to the service"
-msgstr ""
-
-#: templates/django_filters/rest_framework/crispy_form.html:4
-#: templates/django_filters/rest_framework/form.html:2
-msgid "Field filters"
-msgstr ""
-
#: templates/member/alias_update.html:5
msgid "Add alias"
msgstr ""
@@ -1133,19 +1551,25 @@ msgstr ""
msgid "Club Parent"
msgstr ""
-#: templates/member/club_info.html:29
+#: templates/member/club_info.html:34
msgid "days"
msgstr ""
-#: templates/member/club_info.html:32
+#: templates/member/club_info.html:38 templates/wei/weiclub_info.html:27
msgid "membership fee"
msgstr ""
-#: templates/member/club_info.html:52
+#: templates/member/club_info.html:50 templates/member/profile_info.html:33
+#: templates/treasury/sogecredit_detail.html:18
+#: templates/wei/weiclub_info.html:43
+msgid "balance"
+msgstr ""
+
+#: templates/member/club_info.html:64
msgid "Add member"
msgstr ""
-#: templates/member/club_info.html:59 templates/member/profile_info.html:48
+#: templates/member/club_info.html:71 templates/member/profile_info.html:48
msgid "View Profile"
msgstr ""
@@ -1158,14 +1582,15 @@ msgid "Create club"
msgstr ""
#: templates/member/club_list.html:19
-msgid "club listing "
+msgid "Club listing"
msgstr ""
-#: templates/member/club_tables.html:6
+#: templates/member/club_tables.html:7
msgid "Member of the Club"
msgstr ""
-#: templates/member/club_tables.html:17 templates/member/profile_tables.html:28
+#: templates/member/club_tables.html:20 templates/member/profile_tables.html:28
+#: templates/wei/weiclub_tables.html:105
msgid "Transaction history"
msgstr ""
@@ -1188,6 +1613,7 @@ msgstr ""
#: templates/member/profile_info.html:17
#: templates/registration/future_profile_detail.html:19
+#: templates/wei/weimembership_form.html:21
msgid "username"
msgstr ""
@@ -1201,21 +1627,19 @@ msgstr ""
msgid "Change password"
msgstr ""
-#: templates/member/profile_info.html:33
-msgid "balance"
-msgstr ""
-
#: templates/member/profile_info.html:41
msgid "Manage auth token"
msgstr ""
#: templates/member/profile_tables.html:7
#: templates/registration/future_profile_detail.html:28
+#: templates/wei/weimembership_form.html:30
msgid "This user doesn't have confirmed his/her e-mail address."
msgstr ""
#: templates/member/profile_tables.html:8
#: templates/registration/future_profile_detail.html:29
+#: templates/wei/weimembership_form.html:31
msgid "Click here to resend a validation link."
msgstr ""
@@ -1227,9 +1651,8 @@ msgstr ""
msgid "Save Changes"
msgstr ""
-#: templates/member/user_list.html:14
-#: templates/registration/future_user_list.html:17
-msgid "There is no pending user with this pattern."
+#: templates/member/user_list.html:16
+msgid "There is no user with this pattern."
msgstr ""
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:55
@@ -1314,6 +1737,22 @@ msgstr ""
msgid "Unable to delete button "
msgstr ""
+#: templates/permission/all_rights.html:10
+msgid "Filter with roles that I have in at least one club"
+msgstr ""
+
+#: templates/permission/all_rights.html:21
+msgid "Own this role in the clubs"
+msgstr ""
+
+#: templates/permission/all_rights.html:26
+msgid "Query:"
+msgstr ""
+
+#: templates/permission/all_rights.html:28
+msgid "No associated permission"
+msgstr ""
+
#: templates/registration/email_validation_complete.html:6
msgid "Your email have successfully been validated."
msgstr ""
@@ -1335,6 +1774,7 @@ msgid ""
msgstr ""
#: templates/registration/future_profile_detail.html:56
+#: templates/wei/weiregistration_confirm_delete.html:12
msgid "Delete registration"
msgstr ""
@@ -1343,6 +1783,8 @@ msgid "Validate account"
msgstr ""
#: templates/registration/future_profile_detail.html:71
+#: templates/wei/weimembership_form.html:132
+#: templates/wei/weimembership_form.html:190
msgid "Validate registration"
msgstr ""
@@ -1350,6 +1792,10 @@ msgstr ""
msgid "New user"
msgstr ""
+#: templates/registration/future_user_list.html:17
+msgid "There is no pending user with this pattern."
+msgstr ""
+
#: templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
@@ -1359,7 +1805,7 @@ msgid "Log in again"
msgstr ""
#: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:28
+#: templates/registration/login.html:21
#: templates/registration/password_reset_complete.html:10
msgid "Log in"
msgstr ""
@@ -1372,14 +1818,6 @@ msgid ""
msgstr ""
#: templates/registration/login.html:22
-msgid "You can also register via the central authentification server "
-msgstr ""
-
-#: templates/registration/login.html:23
-msgid "using this link "
-msgstr ""
-
-#: templates/registration/login.html:29
msgid "Forgotten your password or username?"
msgstr ""
@@ -1467,10 +1905,18 @@ msgid "Reset my password"
msgstr ""
#: templates/registration/signup.html:5 templates/registration/signup.html:8
-#: templates/registration/signup.html:14
+#: templates/registration/signup.html:19
msgid "Sign up"
msgstr ""
+#: templates/registration/signup.html:11
+msgid ""
+"If you already signed up, your registration is taken into account. The BDE "
+"must validate your account before your can log in. You have to go to the "
+"Kfet and pay the registration fee. You must also validate your email address "
+"by following the link you received."
+msgstr ""
+
#: templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr ""
@@ -1483,7 +1929,13 @@ msgstr ""
msgid "Remove product"
msgstr ""
-#: templates/treasury/invoice_list.html:21
+#: templates/treasury/invoice_list.html:16
+#: templates/treasury/remittance_list.html:16
+#: templates/treasury/sogecredit_list.html:16
+msgid "Société générale credits"
+msgstr ""
+
+#: templates/treasury/invoice_list.html:24
msgid "New invoice"
msgstr ""
@@ -1508,34 +1960,302 @@ msgstr ""
msgid "There is no transaction linked with this remittance."
msgstr ""
-#: templates/treasury/remittance_list.html:19
+#: templates/treasury/remittance_list.html:22
msgid "Opened remittances"
msgstr ""
-#: templates/treasury/remittance_list.html:24
+#: templates/treasury/remittance_list.html:27
msgid "There is no opened remittance."
msgstr ""
-#: templates/treasury/remittance_list.html:28
+#: templates/treasury/remittance_list.html:31
msgid "New remittance"
msgstr ""
-#: templates/treasury/remittance_list.html:32
+#: templates/treasury/remittance_list.html:35
msgid "Transfers without remittances"
msgstr ""
-#: templates/treasury/remittance_list.html:37
+#: templates/treasury/remittance_list.html:40
msgid "There is no transaction without any linked remittance."
msgstr ""
-#: templates/treasury/remittance_list.html:43
+#: templates/treasury/remittance_list.html:46
msgid "Transfers with opened remittances"
msgstr ""
-#: templates/treasury/remittance_list.html:48
+#: templates/treasury/remittance_list.html:51
msgid "There is no transaction with an opened linked remittance."
msgstr ""
-#: templates/treasury/remittance_list.html:54
+#: templates/treasury/remittance_list.html:57
msgid "Closed remittances"
msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:29
+msgid "total amount"
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:35
+msgid ""
+"Warning: Validating this credit implies that all membership transactions "
+"will be validated."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:36
+msgid ""
+"If you delete this credit, there all membership transactions will be also "
+"validated, but no credit will be operated."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:37
+msgid ""
+"If this credit is validated, then the user won't be able to ask for a credit "
+"from the Société générale."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:38
+msgid "If you think there is an error, please contact the \"respos info\"."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:44
+msgid "This credit is already validated."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:49
+msgid ""
+"Warning: if you don't validate this credit, the note of the user doesn't "
+"have enough money to pay its memberships."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:50
+msgid "Please ask the user to credit its note before deleting this credit."
+msgstr ""
+
+#: templates/treasury/sogecredit_detail.html:64
+msgid "Return to credit list"
+msgstr ""
+
+#: templates/treasury/sogecredit_list.html:26
+msgid "Filter with unvalidated credits only"
+msgstr ""
+
+#: templates/treasury/sogecredit_list.html:36
+msgid "There is no matched user that have asked for a Société générale credit."
+msgstr ""
+
+#: templates/wei/bus_tables.html:16 templates/wei/busteam_tables.html:16
+msgid "Add team"
+msgstr ""
+
+#: templates/wei/bus_tables.html:39
+msgid "Members"
+msgstr ""
+
+#: templates/wei/bus_tables.html:48 templates/wei/busteam_tables.html:52
+#: templates/wei/weimembership_list.html:30
+msgid "View as PDF"
+msgstr ""
+
+#: templates/wei/survey.html:24
+msgid "Next"
+msgstr ""
+
+#: templates/wei/survey_closed.html:16
+msgid "The inscription for this WEI are now closed."
+msgstr ""
+
+#: templates/wei/survey_closed.html:20
+msgid "Return to WEI detail"
+msgstr ""
+
+#: templates/wei/survey_end.html:16
+msgid "The survey is now ended. Your answers have been saved."
+msgstr ""
+
+#: templates/wei/weiclub_info.html:31
+msgid "WEI fee / including BDE and Kfet fee (paid students)"
+msgstr ""
+
+#: templates/wei/weiclub_info.html:36
+msgid "WEI fee / including BDE and Kfet fee (unpaid students)"
+msgstr ""
+
+#: templates/wei/weiclub_info.html:58
+msgid "WEI list"
+msgstr ""
+
+#: templates/wei/weiclub_info.html:71
+msgid "Add bus"
+msgstr ""
+
+#: templates/wei/weiclub_info.html:75
+msgid "View WEI"
+msgstr ""
+
+#: templates/wei/weiclub_list.html:8
+msgid "search WEI"
+msgstr ""
+
+#: templates/wei/weiclub_list.html:12
+msgid "Create WEI"
+msgstr ""
+
+#: templates/wei/weiclub_list.html:19
+msgid "WEI listing"
+msgstr ""
+
+#: templates/wei/weiclub_tables.html:63
+msgid "Register to the WEI! – 1A"
+msgstr ""
+
+#: templates/wei/weiclub_tables.html:65
+msgid "Register to the WEI! – 2A+"
+msgstr ""
+
+#: templates/wei/weiclub_tables.html:67
+msgid "Update my registration"
+msgstr ""
+
+#: templates/wei/weiclub_tables.html:92
+msgid "Members of the WEI"
+msgstr ""
+
+#: templates/wei/weiclub_tables.html:120
+msgid "Unvalidated registrations"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:14
+msgid "Review registration"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:39
+msgid "ENS year"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:83
+msgid "Payment from Société générale"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:87
+msgid "Suggested bus from the survey:"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:92
+msgid "Raw survey information"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:102
+msgid "The algorithm didn't run."
+msgstr ""
+
+#: templates/wei/weimembership_form.html:105
+msgid "caution check given"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:109
+msgid "preferred bus"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:112
+msgid "preferred team"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:115
+msgid "preferred roles"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:123
+#: templates/wei/weiregistration_confirm_delete.html:31
+msgid "Update registration"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:136
+msgid "The registration is already validated and can't be unvalidated."
+msgstr ""
+
+#: templates/wei/weimembership_form.html:137
+msgid "The user joined the bus"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:138
+msgid "in the team"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:139
+msgid "in no team (staff)"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:139
+msgid "with the following roles:"
+msgstr ""
+
+#: templates/wei/weimembership_form.html:144
+msgid ""
+"\n"
+" The WEI will be paid by Société générale. The "
+"membership will be created even if the bank didn't pay the BDE yet.\n"
+" The membership transaction will be created but "
+"will be invalid. You will have to validate it once the bank\n"
+" validated the creation of the account, or to "
+"change the payment method.\n"
+" "
+msgstr ""
+
+#: templates/wei/weimembership_form.html:154
+#, python-format
+msgid ""
+"\n"
+" The note don't have enough money "
+"(%(balance)s, %(pretty_fee)s required). The registration may fail.\n"
+" "
+msgstr ""
+
+#: templates/wei/weimembership_form.html:161
+msgid "The note has enough money, the registration is possible."
+msgstr ""
+
+#: templates/wei/weimembership_form.html:168
+msgid "The user didn't give her/his caution check."
+msgstr ""
+
+#: templates/wei/weimembership_form.html:176
+#, python-format
+msgid ""
+"\n"
+" This user is not a member of the Kfet club. "
+"Please adhere\n"
+" here if he/"
+"she is in her/his first year\n"
+" or here if he/she "
+"was an old member before you validate\n"
+" the registration of the WEI.\n"
+" "
+msgstr ""
+
+#: templates/wei/weimembership_list.html:18
+msgid "There is no membership found with this pattern."
+msgstr ""
+
+#: templates/wei/weimembership_list.html:24
+msgid "View unvalidated registrations..."
+msgstr ""
+
+#: templates/wei/weiregistration_confirm_delete.html:17
+msgid "This registration is already validated and can't be deleted."
+msgstr ""
+
+#: templates/wei/weiregistration_confirm_delete.html:24
+#, python-format
+msgid ""
+"Are you sure you want to delete the registration of %(user)s for the WEI "
+"%(wei_name)s? This action can't be undone."
+msgstr ""
+
+#: templates/wei/weiregistration_list.html:18
+msgid "There is no pre-registration found with this pattern."
+msgstr ""
+
+#: templates/wei/weiregistration_list.html:24
+msgid "View validated memberships..."
+msgstr ""
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 27636a65..65c41e93 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -1,9 +1,14 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR %(request_path)s
was not found on the server."
+msgstr ""
+"The chemin demandé %(request_path)s
n'a pas été trouvé sur le "
+"serveur."
+
+#: templates/500.html:6
+msgid "Server error"
+msgstr "Erreur du serveur"
+
+#: templates/500.html:7
+msgid ""
+"Sorry, an error occurred when processing your request. An email has been "
+"sent to webmasters with the detail of the error, and this will be fixed "
+"soon. You can now drink a beer."
+msgstr ""
+"Désolé, une erreur est survenue lors de l'analyse de votre requête. Un email "
+"a été envoyé aux responsables de la plateforme avec les détails de cette "
+"erreur, qui sera corrigée rapidement. Vous pouvez désormais aller boire une "
+"bière."
#: templates/activity/activity_detail.html:29
msgid "creater"
@@ -1069,15 +1570,21 @@ msgstr "Clubs"
msgid "Registrations"
msgstr "Inscriptions"
-#: templates/base.html:150
+#: templates/base.html:120
+msgid "Rights"
+msgstr "Droits"
+
+#: templates/base.html:158
msgid ""
"Your e-mail address is not validated. Please check your mail inbox and click "
"on the validation link."
msgstr ""
+"Votre adresse e-mail n'est pas validée. Merci de vérifier votre boîte mail "
+"et de cliquer sur le lien de validation."
#: templates/cas_server/base.html:7
msgid "Central Authentication Service"
-msgstr ""
+msgstr "Service Central d'Authentification"
#: templates/cas_server/base.html:43
#, python-format
@@ -1086,51 +1593,9 @@ msgid ""
"%(VERSION)s and the last version is %(LAST_VERSION)s. Please consider "
"upgrading."
msgstr ""
-
-#: templates/cas_server/logged.html:4
-msgid ""
-"Log In Successful
You have successfully logged into the Central "
-"Authentication Service.
For security reasons, please Log Out and Exit "
-"your web browser when you are done accessing services that require "
-"authentication!"
-msgstr ""
-
-#: templates/cas_server/logged.html:8
-msgid "Log me out from all my sessions"
-msgstr ""
-
-#: templates/cas_server/logged.html:14
-msgid "Forget the identity provider"
-msgstr ""
-
-#: templates/cas_server/logged.html:18
-msgid "Logout"
-msgstr ""
-
-#: templates/cas_server/login.html:6
-msgid "Please log in"
-msgstr ""
-
-#: templates/cas_server/login.html:11
-msgid ""
-"If you don't have any Note Kfet account, please follow this link to sign up."
-msgstr ""
-"Si vous n'avez pas de compte Note Kfet, veuillez suivre ce lien pour vous inscrire."
-
-#: templates/cas_server/login.html:17
-msgid "Login"
-msgstr ""
-
-#: templates/cas_server/warn.html:9
-msgid "Connect to the service"
-msgstr ""
-
-#: templates/django_filters/rest_framework/crispy_form.html:4
-#: templates/django_filters/rest_framework/form.html:2
-msgid "Field filters"
-msgstr ""
+"Une nouvelle version de l'application est disponible. Cette instance utilise "
+"la version %(VERSION)s et la dernière version est %(LAST_VERSION)s. Merci de "
+"vous mettre à jour."
#: templates/member/alias_update.html:5
msgid "Add alias"
@@ -1140,19 +1605,25 @@ msgstr "Ajouter un alias"
msgid "Club Parent"
msgstr "Club parent"
-#: templates/member/club_info.html:29
+#: templates/member/club_info.html:34
msgid "days"
msgstr "jours"
-#: templates/member/club_info.html:32
+#: templates/member/club_info.html:38 templates/wei/weiclub_info.html:27
msgid "membership fee"
msgstr "cotisation pour adhérer"
-#: templates/member/club_info.html:52
+#: templates/member/club_info.html:50 templates/member/profile_info.html:33
+#: templates/treasury/sogecredit_detail.html:18
+#: templates/wei/weiclub_info.html:43
+msgid "balance"
+msgstr "solde du compte"
+
+#: templates/member/club_info.html:64
msgid "Add member"
msgstr "Ajouter un membre"
-#: templates/member/club_info.html:59 templates/member/profile_info.html:48
+#: templates/member/club_info.html:71 templates/member/profile_info.html:48
msgid "View Profile"
msgstr "Voir le profil"
@@ -1165,14 +1636,15 @@ msgid "Create club"
msgstr "Créer un club"
#: templates/member/club_list.html:19
-msgid "club listing "
+msgid "Club listing"
msgstr "Liste des clubs"
-#: templates/member/club_tables.html:6
+#: templates/member/club_tables.html:7
msgid "Member of the Club"
msgstr "Membre du club"
-#: templates/member/club_tables.html:17 templates/member/profile_tables.html:28
+#: templates/member/club_tables.html:20 templates/member/profile_tables.html:28
+#: templates/wei/weiclub_tables.html:105
msgid "Transaction history"
msgstr "Historique des transactions"
@@ -1195,6 +1667,7 @@ msgstr "Compte n°"
#: templates/member/profile_info.html:17
#: templates/registration/future_profile_detail.html:19
+#: templates/wei/weimembership_form.html:21
msgid "username"
msgstr "pseudo"
@@ -1208,21 +1681,19 @@ msgstr "mot de passe"
msgid "Change password"
msgstr "Changer le mot de passe"
-#: templates/member/profile_info.html:33
-msgid "balance"
-msgstr "solde du compte"
-
#: templates/member/profile_info.html:41
msgid "Manage auth token"
msgstr "Gérer les jetons d'authentification"
#: templates/member/profile_tables.html:7
#: templates/registration/future_profile_detail.html:28
+#: templates/wei/weimembership_form.html:30
msgid "This user doesn't have confirmed his/her e-mail address."
msgstr "Cet utilisateur n'a pas encore confirmé son adresse e-mail."
#: templates/member/profile_tables.html:8
#: templates/registration/future_profile_detail.html:29
+#: templates/wei/weimembership_form.html:31
msgid "Click here to resend a validation link."
msgstr "Cliquez ici pour renvoyer un lien de validation."
@@ -1234,10 +1705,9 @@ msgstr "Voir mes adhésions"
msgid "Save Changes"
msgstr "Sauvegarder les changements"
-#: templates/member/user_list.html:14
-#: templates/registration/future_user_list.html:17
-msgid "There is no pending user with this pattern."
-msgstr "Il n'y a pas d'inscription en attente avec cette entrée."
+#: templates/member/user_list.html:16
+msgid "There is no user with this pattern."
+msgstr "Il n'y a pas d'utilisateur trouvé avec cette entrée."
#: templates/note/conso_form.html:28 templates/note/transaction_form.html:55
msgid "Select emitters"
@@ -1321,6 +1791,22 @@ msgstr "Le bouton a bien été supprimé"
msgid "Unable to delete button "
msgstr "Impossible de supprimer le bouton "
+#: templates/permission/all_rights.html:10
+msgid "Filter with roles that I have in at least one club"
+msgstr "Filtrer les rôles que je possède dans au moins un club"
+
+#: templates/permission/all_rights.html:21
+msgid "Own this role in the clubs"
+msgstr "Possède ce rôle dans les clubs"
+
+#: templates/permission/all_rights.html:26
+msgid "Query:"
+msgstr "Requête :"
+
+#: templates/permission/all_rights.html:28
+msgid "No associated permission"
+msgstr "Pas de permission associée"
+
#: templates/registration/email_validation_complete.html:6
msgid "Your email have successfully been validated."
msgstr "Votre adresse e-mail a bien été validée."
@@ -1334,17 +1820,19 @@ msgstr "Vous pouvez désormais vous connecter."
msgid ""
"You must pay now your membership in the Kfet to complete your registration."
msgstr ""
-"Vous devez désormais payer votre adhésion à la Kfet pour compléter votre inscription."
+"Vous devez désormais payer votre adhésion à la Kfet pour compléter votre "
+"inscription."
#: templates/registration/email_validation_complete.html:13
msgid ""
"The link was invalid. The token may have expired. Please send us an email to "
"activate your account."
msgstr ""
-"Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter pour "
-"activer votre compte."
+"Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter "
+"pour activer votre compte."
#: templates/registration/future_profile_detail.html:56
+#: templates/wei/weiregistration_confirm_delete.html:12
msgid "Delete registration"
msgstr "Supprimer l'inscription"
@@ -1353,6 +1841,8 @@ msgid "Validate account"
msgstr "Valider le compte"
#: templates/registration/future_profile_detail.html:71
+#: templates/wei/weimembership_form.html:132
+#: templates/wei/weimembership_form.html:190
msgid "Validate registration"
msgstr "Valider l'inscription"
@@ -1360,19 +1850,23 @@ msgstr "Valider l'inscription"
msgid "New user"
msgstr "Nouvel utilisateur"
+#: templates/registration/future_user_list.html:17
+msgid "There is no pending user with this pattern."
+msgstr "Il n'y a pas d'inscription en attente avec cette entrée."
+
#: templates/registration/logged_out.html:8
msgid "Thanks for spending some quality time with the Web site today."
-msgstr ""
+msgstr "Merci d'avoir utilisé la Note Kfet."
#: templates/registration/logged_out.html:9
msgid "Log in again"
-msgstr ""
+msgstr "Se connecter à nouveau"
#: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:28
+#: templates/registration/login.html:21
#: templates/registration/password_reset_complete.html:10
msgid "Log in"
-msgstr ""
+msgstr "Se connecter"
#: templates/registration/login.html:13
#, python-format
@@ -1380,42 +1874,40 @@ msgid ""
"You are authenticated as %(username)s, but are not authorized to access this "
"page. Would you like to login to a different account?"
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 ?"
#: templates/registration/login.html:22
-msgid "You can also register via the central authentification server "
-msgstr ""
-
-#: templates/registration/login.html:23
-msgid "using this link "
-msgstr ""
-
-#: templates/registration/login.html:29
msgid "Forgotten your password or username?"
-msgstr ""
+msgstr "Mot de passe ou pseudo oublié ?"
#: templates/registration/mails/email_validation_email.html:3
msgid "Hi"
-msgstr ""
+msgstr "Bonjour"
#: templates/registration/mails/email_validation_email.html:5
msgid ""
"You recently registered on the Note Kfet. Please click on the link below to "
"confirm your registration."
msgstr ""
+"Vous vous êtes inscrits récemment sur la Note Kfet. Merci de cliquer sur le "
+"lien ci-dessous pour confirmer votre adresse email."
#: templates/registration/mails/email_validation_email.html:9
msgid ""
"This link is only valid for a couple of days, after that you will need to "
"contact us to validate your email."
msgstr ""
+"Ce lien n'est valide que pendant quelques jours. Après cela, vous devrez "
+"nous contacter pour valider votre email."
#: templates/registration/mails/email_validation_email.html:11
msgid ""
"After that, you'll have to wait that someone validates your account before "
"you can log in. You will need to pay your membership in the Kfet."
msgstr ""
-"Après cela, vous devrez attendre que quelqu'un valide votre compte avant "
-"de pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet."
+"Après cela, vous devrez attendre que quelqu'un valide votre compte avant de "
+"pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet."
#: templates/registration/mails/email_validation_email.html:13
msgid "Thanks"
@@ -1438,51 +1930,76 @@ msgstr ""
#: templates/registration/password_change_form.html:11
#: templates/registration/password_reset_confirm.html:12
msgid "Change my password"
-msgstr ""
+msgstr "Changer mon mot de passe"
#: templates/registration/password_reset_complete.html:8
msgid "Your password has been set. You may go ahead and log in now."
msgstr ""
+"Votre mot de passe a été enregistré. Vous pouvez vous connecter dès à "
+"présent."
#: templates/registration/password_reset_confirm.html:9
msgid ""
"Please enter your new password twice so we can verify you typed it in "
"correctly."
msgstr ""
+"Entrer votre nouveau mot de passe, et le confirmer en le renseignant une "
+"seconde fois."
#: templates/registration/password_reset_confirm.html:15
msgid ""
"The password reset link was invalid, possibly because it has already been "
"used. Please request a new password reset."
msgstr ""
+"Le lien de reinitialisation du mot de passe est invalide, il a peut-être été "
+"déjà utilisé. Faites une nouvelle demande."
#: templates/registration/password_reset_done.html:8
msgid ""
"We've emailed you instructions for setting your password, if an account "
"exists with the email you entered. You should receive them shortly."
msgstr ""
+"Nous vous avons envoyé par mail les instructions pour changer votre mot de "
+"passe."
#: templates/registration/password_reset_done.html:9
msgid ""
"If you don't receive an email, please make sure you've entered the address "
"you registered with, and check your spam folder."
msgstr ""
+"Si vous ne recevez pas d'email, vérifiez que vous avez bien utilisé "
+"l'adresse associé à votre compte, et regarder également le dossier spam."
#: templates/registration/password_reset_form.html:8
msgid ""
"Forgotten your password? Enter your email address below, and we'll email "
"instructions for setting a new one."
msgstr ""
+"Mot de passe oublié ? Entrez votre adresse mail ci-dessous, et vous recevrez "
+"les instructions pour choisir un nouveau mot de passe."
#: templates/registration/password_reset_form.html:11
msgid "Reset my password"
-msgstr ""
+msgstr "Réinitialiser mon mot de passe"
#: templates/registration/signup.html:5 templates/registration/signup.html:8
-#: templates/registration/signup.html:14
+#: templates/registration/signup.html:19
msgid "Sign up"
msgstr "Inscription"
+#: templates/registration/signup.html:11
+msgid ""
+"If you already signed up, your registration is taken into account. The BDE "
+"must validate your account before your can log in. You have to go to the "
+"Kfet and pay the registration fee. You must also validate your email address "
+"by following the link you received."
+msgstr ""
+"Si vous vous êtes déjà inscrits, votre inscription a bien été prise en "
+"compte. Le BDE doit d'abord valider votre compte avantque vous puissiez vous "
+"connecter. Vous devez vous rendre à la Kfet et payer les frais d'adhésion. "
+"Vous devez également valider votre adresse email en suivant le lien que vous "
+"avez reçu."
+
#: templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr "Liste des factures"
@@ -1495,7 +2012,13 @@ msgstr "Ajouter produit"
msgid "Remove product"
msgstr "Retirer produit"
-#: templates/treasury/invoice_list.html:21
+#: templates/treasury/invoice_list.html:16
+#: templates/treasury/remittance_list.html:16
+#: templates/treasury/sogecredit_list.html:16
+msgid "Société générale credits"
+msgstr "Crédits de la Société générale"
+
+#: templates/treasury/invoice_list.html:24
msgid "New invoice"
msgstr "Nouvelle facture"
@@ -1520,37 +2043,336 @@ msgstr "Transactions liées"
msgid "There is no transaction linked with this remittance."
msgstr "Il n'y a pas de transaction liée à cette remise."
-#: templates/treasury/remittance_list.html:19
+#: templates/treasury/remittance_list.html:22
msgid "Opened remittances"
msgstr "Remises ouvertes"
-#: templates/treasury/remittance_list.html:24
+#: templates/treasury/remittance_list.html:27
msgid "There is no opened remittance."
msgstr "Il n'y a pas de remise ouverte."
-#: templates/treasury/remittance_list.html:28
+#: templates/treasury/remittance_list.html:31
msgid "New remittance"
msgstr "Nouvelle remise"
-#: templates/treasury/remittance_list.html:32
+#: templates/treasury/remittance_list.html:35
msgid "Transfers without remittances"
msgstr "Transactions sans remise associée"
-#: templates/treasury/remittance_list.html:37
+#: templates/treasury/remittance_list.html:40
msgid "There is no transaction without any linked remittance."
msgstr "Il n'y a pas de transactions sans remise associée."
-#: templates/treasury/remittance_list.html:43
+#: templates/treasury/remittance_list.html:46
msgid "Transfers with opened remittances"
msgstr "Transactions associées à une remise ouverte"
-#: templates/treasury/remittance_list.html:48
+#: templates/treasury/remittance_list.html:51
msgid "There is no transaction with an opened linked remittance."
msgstr "Il n'y a pas de transaction associée à une remise ouverte."
-#: templates/treasury/remittance_list.html:54
+#: templates/treasury/remittance_list.html:57
msgid "Closed remittances"
msgstr "Remises fermées"
-#~ msgid "This membership is already renewed"
-#~ msgstr "Cette adhésion est déjà renouvelée"
+#: templates/treasury/sogecredit_detail.html:29
+msgid "total amount"
+msgstr "montant total"
+
+#: templates/treasury/sogecredit_detail.html:35
+msgid ""
+"Warning: Validating this credit implies that all membership transactions "
+"will be validated."
+msgstr ""
+"Attention : Valider ce crédit implique que les transactions d'adhésion "
+"seront validées."
+
+#: templates/treasury/sogecredit_detail.html:36
+msgid ""
+"If you delete this credit, there all membership transactions will be also "
+"validated, but no credit will be operated."
+msgstr ""
+"Si vous supprimez cette demande de crédit, alors toutes les transactions "
+"d'adhésion seront aussi validées, but il n'y aura pas de transaction de "
+"crédit créée."
+
+#: templates/treasury/sogecredit_detail.html:37
+msgid ""
+"If this credit is validated, then the user won't be able to ask for a credit "
+"from the Société générale."
+msgstr ""
+"Si ce crédit est validé, alors l'utilisateur ne pourra plus demander d'être "
+"crédité par la Société générale à l'avenir."
+
+#: templates/treasury/sogecredit_detail.html:38
+msgid "If you think there is an error, please contact the \"respos info\"."
+msgstr "Si vous pensez qu'il y a une erreur, merci de contacter un respo info."
+
+#: templates/treasury/sogecredit_detail.html:44
+msgid "This credit is already validated."
+msgstr "Ce crédit a déjà été validé."
+
+#: templates/treasury/sogecredit_detail.html:49
+msgid ""
+"Warning: if you don't validate this credit, the note of the user doesn't "
+"have enough money to pay its memberships."
+msgstr ""
+"Attention : si vous ne validez pas ce crédit, la note de l'utilisateur n'a "
+"pas assez d'argent pour payer les adhésions."
+
+#: templates/treasury/sogecredit_detail.html:50
+msgid "Please ask the user to credit its note before deleting this credit."
+msgstr ""
+"Merci de demander à l'utilisateur de recharger sa note avant de supprimer la "
+"demande de crédit."
+
+#: templates/treasury/sogecredit_detail.html:64
+msgid "Return to credit list"
+msgstr "Retour à la liste des crédits"
+
+#: templates/treasury/sogecredit_list.html:26
+msgid "Filter with unvalidated credits only"
+msgstr "Filtrer avec uniquement les crédits non valides"
+
+#: templates/treasury/sogecredit_list.html:36
+msgid "There is no matched user that have asked for a Société générale credit."
+msgstr ""
+"Il n'y a pas d'utilisateur trouvé ayant demandé un crédit de la Société "
+"générale."
+
+#: templates/wei/bus_tables.html:16 templates/wei/busteam_tables.html:16
+msgid "Add team"
+msgstr "Ajouter une équipe"
+
+#: templates/wei/bus_tables.html:39
+msgid "Members"
+msgstr "Membres"
+
+#: templates/wei/bus_tables.html:48 templates/wei/busteam_tables.html:52
+#: templates/wei/weimembership_list.html:30
+msgid "View as PDF"
+msgstr "Télécharger au format PDF"
+
+#: templates/wei/survey.html:24
+msgid "Next"
+msgstr "Suivant"
+
+#: templates/wei/survey_closed.html:16
+msgid "The inscription for this WEI are now closed."
+msgstr "Les inscriptions pour le WEI sont fermées."
+
+#: templates/wei/survey_closed.html:20
+msgid "Return to WEI detail"
+msgstr "Retour aux détails du WEI"
+
+#: templates/wei/survey_end.html:16
+msgid "The survey is now ended. Your answers have been saved."
+msgstr ""
+"Le sondage est désormais terminé, vos réponses ont bien été enregistrées."
+
+#: templates/wei/weiclub_info.html:31
+msgid "WEI fee / including BDE and Kfet fee (paid students)"
+msgstr "Prix du WEI / incluant l'adhésion BDE/Kfet (élèves)"
+
+#: templates/wei/weiclub_info.html:36
+msgid "WEI fee / including BDE and Kfet fee (unpaid students)"
+msgstr "Prix du WEI / incluant l'adhésion BDE/Kfet (étudiants)"
+
+#: templates/wei/weiclub_info.html:58
+msgid "WEI list"
+msgstr "Liste des WEI"
+
+#: templates/wei/weiclub_info.html:71
+msgid "Add bus"
+msgstr "Ajouter un bus"
+
+#: templates/wei/weiclub_info.html:75
+msgid "View WEI"
+msgstr "Voir le WEI"
+
+#: templates/wei/weiclub_list.html:8
+msgid "search WEI"
+msgstr "Chercher un WEI"
+
+#: templates/wei/weiclub_list.html:12
+msgid "Create WEI"
+msgstr "Créer un WEI"
+
+#: templates/wei/weiclub_list.html:19
+msgid "WEI listing"
+msgstr "Liste des WEI"
+
+#: templates/wei/weiclub_tables.html:63
+msgid "Register to the WEI! – 1A"
+msgstr "M'inscrire au WEI ! – 1A"
+
+#: templates/wei/weiclub_tables.html:65
+msgid "Register to the WEI! – 2A+"
+msgstr "M'inscrire au WEI ! – 2A+"
+
+#: templates/wei/weiclub_tables.html:67
+msgid "Update my registration"
+msgstr "Mettre à jour mon inscription"
+
+#: templates/wei/weiclub_tables.html:92
+msgid "Members of the WEI"
+msgstr "Membres du WEI"
+
+#: templates/wei/weiclub_tables.html:120
+msgid "Unvalidated registrations"
+msgstr "Inscriptions non validées"
+
+#: templates/wei/weimembership_form.html:14
+msgid "Review registration"
+msgstr "Vérifier l'inscription"
+
+#: templates/wei/weimembership_form.html:39
+msgid "ENS year"
+msgstr "Année à l'ENS"
+
+#: templates/wei/weimembership_form.html:83
+msgid "Payment from Société générale"
+msgstr "Paiement de la Société générale"
+
+#: templates/wei/weimembership_form.html:87
+msgid "Suggested bus from the survey:"
+msgstr "Bus suggéré par le sondage :"
+
+#: templates/wei/weimembership_form.html:92
+msgid "Raw survey information"
+msgstr "Informations brutes du sondage"
+
+#: templates/wei/weimembership_form.html:102
+msgid "The algorithm didn't run."
+msgstr "L'algorithme n'a pas été exécuté."
+
+#: templates/wei/weimembership_form.html:105
+msgid "caution check given"
+msgstr "chèque de caution donné"
+
+#: templates/wei/weimembership_form.html:109
+msgid "preferred bus"
+msgstr "bus préféré"
+
+#: templates/wei/weimembership_form.html:112
+msgid "preferred team"
+msgstr "équipe préférée"
+
+#: templates/wei/weimembership_form.html:115
+msgid "preferred roles"
+msgstr "rôles préférés"
+
+#: templates/wei/weimembership_form.html:123
+#: templates/wei/weiregistration_confirm_delete.html:31
+msgid "Update registration"
+msgstr "Mettre à jour l'inscription"
+
+#: templates/wei/weimembership_form.html:136
+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:137
+msgid "The user joined the bus"
+msgstr "L'utilisateur a rejoint le bus"
+
+#: templates/wei/weimembership_form.html:138
+msgid "in the team"
+msgstr "dans l'équipe"
+
+#: templates/wei/weimembership_form.html:139
+msgid "in no team (staff)"
+msgstr "dans aucune équipe (staff)"
+
+#: templates/wei/weimembership_form.html:139
+msgid "with the following roles:"
+msgstr "avec les rôles suivants :"
+
+#: templates/wei/weimembership_form.html:144
+msgid ""
+"\n"
+" The WEI will be paid by Société générale. The "
+"membership will be created even if the bank didn't pay the BDE yet.\n"
+" The membership transaction will be created but "
+"will be invalid. You will have to validate it once the bank\n"
+" validated the creation of the account, or to "
+"change the payment method.\n"
+" "
+msgstr ""
+"\n"
+"Le WEI va être payé par la Société générale. L'adhésion sera créée même si "
+"la banque n'a pas encore payé le BDE.\n"
+"La transaction d'adhésion sera créée mais invalide. Vous devrez la valider "
+"une fois que la banque\n"
+"aura validé la création du compte, ou bien changer de moyen de paiement.\n"
+" "
+
+#: templates/wei/weimembership_form.html:154
+#, python-format
+msgid ""
+"\n"
+" The note don't have enough money "
+"(%(balance)s, %(pretty_fee)s required). The registration may fail.\n"
+" "
+msgstr ""
+"\n"
+"La note n'a pas assez d'argent (%(balance)s, %(pretty_fee)s requis). "
+"L'inscription va échouer.\n"
+" "
+
+#: templates/wei/weimembership_form.html:161
+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:168
+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:176
+#, python-format
+msgid ""
+"\n"
+" This user is not a member of the Kfet club. "
+"Please adhere\n"
+" here if he/"
+"she is in her/his first year\n"
+" or here if he/she "
+"was an old member before you validate\n"
+" the registration of the WEI.\n"
+" "
+msgstr ""
+"\n"
+"Cet utilisateur n'est pas membre du club Kfet. Merci de le faire adhérer\n"
+"ici s'iel est en première année\n"
+"ou ici s'iel est un ancien membre avant de "
+"valider\n"
+"l'inscription au WEI.\n"
+" "
+
+#: templates/wei/weimembership_list.html:18
+msgid "There is no membership found with this pattern."
+msgstr "Il n'y a pas d'adhésion trouvée avec cette entrée."
+
+#: templates/wei/weimembership_list.html:24
+msgid "View unvalidated registrations..."
+msgstr "Voir les inscriptions non validées ..."
+
+#: templates/wei/weiregistration_confirm_delete.html:17
+msgid "This registration is already validated and can't be deleted."
+msgstr "L'inscription a déjà été validée et ne peut pas être supprimée."
+
+#: templates/wei/weiregistration_confirm_delete.html:24
+#, python-format
+msgid ""
+"Are you sure you want to delete the registration of %(user)s for the WEI "
+"%(wei_name)s? This action can't be undone."
+msgstr ""
+"Êtes-vous sûr de vouloir supprimer l'inscription de %(user)s pour le WEI "
+"%(wei_name)s ? Cette action ne pourra pas être annulée."
+
+#: templates/wei/weiregistration_list.html:18
+msgid "There is no pre-registration found with this pattern."
+msgstr "Il n'y a pas de pré-inscription en attente avec cette entrée."
+
+#: templates/wei/weiregistration_list.html:24
+msgid "View validated memberships..."
+msgstr "Voir les adhésions validées ..."
diff --git a/note_kfet/inputs.py b/note_kfet/inputs.py
index b3cccbce..1a17d5ac 100644
--- a/note_kfet/inputs.py
+++ b/note_kfet/inputs.py
@@ -3,7 +3,7 @@
from json import dumps as json_dumps
-from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput
+from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput, Widget
class AmountInput(NumberInput):
@@ -41,6 +41,29 @@ class Autocomplete(TextInput):
return ""
+class ColorWidget(Widget):
+ """
+ Pulled from django-colorfield.
+ Select a color.
+ """
+ template_name = 'colorfield/color.html'
+
+ class Media:
+ js = [
+ 'colorfield/jscolor/jscolor.min.js',
+ 'colorfield/colorfield.js',
+ ]
+
+ def format_value(self, value):
+ if value is None:
+ value = 0xFFFFFF
+ return "#{:06X}".format(value)
+
+ def value_from_datadict(self, data, files, name):
+ val = super().value_from_datadict(data, files, name)
+ return int(val[1:], 16)
+
+
"""
The remaining of this file comes from the project `django-bootstrap-datepicker-plus` available on Github:
https://github.com/monim67/django-bootstrap-datepicker-plus
diff --git a/note_kfet/settings/__init__.py b/note_kfet/settings/__init__.py
index 1ab06b9c..73aae469 100644
--- a/note_kfet/settings/__init__.py
+++ b/note_kfet/settings/__init__.py
@@ -39,41 +39,20 @@ else:
from .development import *
try:
- #in secrets.py defines everything you want
+ # in secrets.py defines everything you want
from .secrets import *
+
INSTALLED_APPS += OPTIONAL_APPS
except ImportError:
pass
-if "cas" in INSTALLED_APPS:
- MIDDLEWARE += ['cas.middleware.CASMiddleware']
+if "cas_server" in INSTALLED_APPS:
# CAS Settings
- CAS_SERVER_URL = "https://" + os.getenv("NOTE_URL", "note.example.com") + "/cas/"
CAS_AUTO_CREATE_USER = False
CAS_LOGO_URL = "/static/img/Saperlistpopette.png"
CAS_FAVICON_URL = "/static/favicon/favicon-32x32.png"
- CAS_SHOW_SERVICE_MESSAGES = True
CAS_SHOW_POWERED = False
- CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT = False
- CAS_PROVIDE_URL_TO_LOGOUT = True
- CAS_INFO_MESSAGES = {
- "cas_explained": {
- "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."
- ),
- "discardable": True,
- "type": "info", # one of info, success, info, warning, danger
- },
- }
-
- CAS_INFO_MESSAGES_ORDER = [
- 'cas_explained',
- ]
- AUTHENTICATION_BACKENDS += ('cas.backends.CASBackend',)
-
if "logs" in INSTALLED_APPS:
MIDDLEWARE += ('note_kfet.middlewares.SessionMiddleware',)
diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py
index 283f8e56..5ed8b1d8 100644
--- a/note_kfet/settings/base.py
+++ b/note_kfet/settings/base.py
@@ -62,6 +62,7 @@ INSTALLED_APPS = [
'permission',
'registration',
'treasury',
+ 'wei',
]
LOGIN_REDIRECT_URL = '/note/transfer/'
diff --git a/note_kfet/settings/development.py b/note_kfet/settings/development.py
index 66ad4fd4..0a0c21e1 100644
--- a/note_kfet/settings/development.py
+++ b/note_kfet/settings/development.py
@@ -62,10 +62,6 @@ CSRF_COOKIE_HTTPONLY = False
X_FRAME_OPTIONS = 'DENY'
SESSION_COOKIE_AGE = 60 * 60 * 3
-# CAS Client settings
-# Can be modified in secrets.py
-CAS_SERVER_URL = "http://localhost:8000/cas/"
-
STATIC_ROOT = '' # not needed in development settings
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')]
diff --git a/note_kfet/settings/production.py b/note_kfet/settings/production.py
index 5be8a3b8..7b8d37ef 100644
--- a/note_kfet/settings/production.py
+++ b/note_kfet/settings/production.py
@@ -51,6 +51,3 @@ CSRF_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = False
X_FRAME_OPTIONS = 'DENY'
SESSION_COOKIE_AGE = 60 * 60 * 3
-
-# CAS Client settings
-CAS_SERVER_URL = "https://" + os.getenv("NOTE_URL", "note.example.com") + "/cas/"
diff --git a/note_kfet/urls.py b/note_kfet/urls.py
index 90d44a07..9717087a 100644
--- a/note_kfet/urls.py
+++ b/note_kfet/urls.py
@@ -5,6 +5,7 @@ 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
@@ -19,14 +20,16 @@ urlpatterns = [
path('registration/', include('registration.urls')),
path('activity/', include('activity.urls')),
path('treasury/', include('treasury.urls')),
+ path('wei/', include('wei.urls')),
# 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),
+ 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')),
+ path('permission/', include('permission.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
@@ -44,3 +47,11 @@ if "debug_toolbar" in settings.INSTALLED_APPS:
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
+
+
+handler400 = bad_request
+handler403 = permission_denied
+
+# Only displayed in production, when debug mode is set to False
+handler404 = page_not_found
+handler500 = server_error
diff --git a/requirements/cas.txt b/requirements/cas.txt
index d468d2d5..c7c696fb 100644
--- a/requirements/cas.txt
+++ b/requirements/cas.txt
@@ -1,2 +1 @@
-django-cas-client==1.5.3
django-cas-server==1.1.0
diff --git a/static/colorfield/colorfield.js b/static/colorfield/colorfield.js
new file mode 100644
index 00000000..a3c2de62
--- /dev/null
+++ b/static/colorfield/colorfield.js
@@ -0,0 +1,12 @@
+/** global: django */
+
+window.onload = function() {
+ if (typeof(django) !== 'undefined' && typeof(django.jQuery) !== 'undefined') {
+ (function($) {
+ // add colopicker to inlines added dynamically
+ $(document).on('formset:added', function onFormsetAdded(event, row) {
+ jscolor.installByClassName('jscolor');
+ });
+ }(django.jQuery));
+ }
+};
\ No newline at end of file
diff --git a/static/colorfield/jscolor/jscolor.js b/static/colorfield/jscolor/jscolor.js
new file mode 100755
index 00000000..dbbd2342
--- /dev/null
+++ b/static/colorfield/jscolor/jscolor.js
@@ -0,0 +1,1855 @@
+/**
+ * jscolor - JavaScript Color Picker
+ *
+ * @link http://jscolor.com
+ * @license For open source use: GPLv3
+ * For commercial use: JSColor Commercial License
+ * @author Jan Odvarko
+ * @version 2.0.5
+ *
+ * See usage examples at http://jscolor.com/examples/
+ */
+
+
+"use strict";
+
+
+if (!window.jscolor) { window.jscolor = (function () {
+
+
+var jsc = {
+
+
+ register : function () {
+ jsc.attachDOMReadyEvent(jsc.init);
+ jsc.attachEvent(document, 'mousedown', jsc.onDocumentMouseDown);
+ jsc.attachEvent(document, 'touchstart', jsc.onDocumentTouchStart);
+ jsc.attachEvent(window, 'resize', jsc.onWindowResize);
+ },
+
+
+ init : function () {
+ if (jsc.jscolor.lookupClass) {
+ jsc.jscolor.installByClassName(jsc.jscolor.lookupClass);
+ }
+ },
+
+
+ tryInstallOnElements : function (elms, className) {
+ var matchClass = new RegExp('(^|\\s)(' + className + ')(\\s*(\\{[^}]*\\})|\\s|$)', 'i');
+
+ for (var i = 0; i < elms.length; i += 1) {
+ if (elms[i].type !== undefined && elms[i].type.toLowerCase() == 'color') {
+ if (jsc.isColorAttrSupported) {
+ // skip inputs of type 'color' if supported by the browser
+ continue;
+ }
+ }
+ var m;
+ if (!elms[i].jscolor && elms[i].className && (m = elms[i].className.match(matchClass))) {
+ var targetElm = elms[i];
+ var optsStr = null;
+
+ var dataOptions = jsc.getDataAttr(targetElm, 'jscolor');
+ if (dataOptions !== null) {
+ optsStr = dataOptions;
+ } else if (m[4]) {
+ optsStr = m[4];
+ }
+
+ var opts = {};
+ if (optsStr) {
+ try {
+ opts = (new Function ('return (' + optsStr + ')'))();
+ } catch(eParseError) {
+ jsc.warn('Error parsing jscolor options: ' + eParseError + ':\n' + optsStr);
+ }
+ }
+ targetElm.jscolor = new jsc.jscolor(targetElm, opts);
+ }
+ }
+ },
+
+
+ isColorAttrSupported : (function () {
+ var elm = document.createElement('input');
+ if (elm.setAttribute) {
+ elm.setAttribute('type', 'color');
+ if (elm.type.toLowerCase() == 'color') {
+ return true;
+ }
+ }
+ return false;
+ })(),
+
+
+ isCanvasSupported : (function () {
+ var elm = document.createElement('canvas');
+ return !!(elm.getContext && elm.getContext('2d'));
+ })(),
+
+
+ fetchElement : function (mixed) {
+ return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
+ },
+
+
+ isElementType : function (elm, type) {
+ return elm.nodeName.toLowerCase() === type.toLowerCase();
+ },
+
+
+ getDataAttr : function (el, name) {
+ var attrName = 'data-' + name;
+ var attrValue = el.getAttribute(attrName);
+ if (attrValue !== null) {
+ return attrValue;
+ }
+ return null;
+ },
+
+
+ attachEvent : function (el, evnt, func) {
+ if (el.addEventListener) {
+ el.addEventListener(evnt, func, false);
+ } else if (el.attachEvent) {
+ el.attachEvent('on' + evnt, func);
+ }
+ },
+
+
+ detachEvent : function (el, evnt, func) {
+ if (el.removeEventListener) {
+ el.removeEventListener(evnt, func, false);
+ } else if (el.detachEvent) {
+ el.detachEvent('on' + evnt, func);
+ }
+ },
+
+
+ _attachedGroupEvents : {},
+
+
+ attachGroupEvent : function (groupName, el, evnt, func) {
+ if (!jsc._attachedGroupEvents.hasOwnProperty(groupName)) {
+ jsc._attachedGroupEvents[groupName] = [];
+ }
+ jsc._attachedGroupEvents[groupName].push([el, evnt, func]);
+ jsc.attachEvent(el, evnt, func);
+ },
+
+
+ detachGroupEvents : function (groupName) {
+ if (jsc._attachedGroupEvents.hasOwnProperty(groupName)) {
+ for (var i = 0; i < jsc._attachedGroupEvents[groupName].length; i += 1) {
+ var evt = jsc._attachedGroupEvents[groupName][i];
+ jsc.detachEvent(evt[0], evt[1], evt[2]);
+ }
+ delete jsc._attachedGroupEvents[groupName];
+ }
+ },
+
+
+ attachDOMReadyEvent : function (func) {
+ var fired = false;
+ var fireOnce = function () {
+ if (!fired) {
+ fired = true;
+ func();
+ }
+ };
+
+ if (document.readyState === 'complete') {
+ setTimeout(fireOnce, 1); // async
+ return;
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener('DOMContentLoaded', fireOnce, false);
+
+ // Fallback
+ window.addEventListener('load', fireOnce, false);
+
+ } else if (document.attachEvent) {
+ // IE
+ document.attachEvent('onreadystatechange', function () {
+ if (document.readyState === 'complete') {
+ document.detachEvent('onreadystatechange', arguments.callee);
+ fireOnce();
+ }
+ })
+
+ // Fallback
+ window.attachEvent('onload', fireOnce);
+
+ // IE7/8
+ if (document.documentElement.doScroll && window == window.top) {
+ var tryScroll = function () {
+ if (!document.body) { return; }
+ try {
+ document.documentElement.doScroll('left');
+ fireOnce();
+ } catch (e) {
+ setTimeout(tryScroll, 1);
+ }
+ };
+ tryScroll();
+ }
+ }
+ },
+
+
+ warn : function (msg) {
+ if (window.console && window.console.warn) {
+ window.console.warn(msg);
+ }
+ },
+
+
+ preventDefault : function (e) {
+ if (e.preventDefault) { e.preventDefault(); }
+ e.returnValue = false;
+ },
+
+
+ captureTarget : function (target) {
+ // IE
+ if (target.setCapture) {
+ jsc._capturedTarget = target;
+ jsc._capturedTarget.setCapture();
+ }
+ },
+
+
+ releaseTarget : function () {
+ // IE
+ if (jsc._capturedTarget) {
+ jsc._capturedTarget.releaseCapture();
+ jsc._capturedTarget = null;
+ }
+ },
+
+
+ fireEvent : function (el, evnt) {
+ if (!el) {
+ return;
+ }
+ if (document.createEvent) {
+ var ev = document.createEvent('HTMLEvents');
+ ev.initEvent(evnt, true, true);
+ el.dispatchEvent(ev);
+ } else if (document.createEventObject) {
+ var ev = document.createEventObject();
+ el.fireEvent('on' + evnt, ev);
+ } else if (el['on' + evnt]) { // alternatively use the traditional event model
+ el['on' + evnt]();
+ }
+ },
+
+
+ classNameToList : function (className) {
+ return className.replace(/^\s+|\s+$/g, '').split(/\s+/);
+ },
+
+
+ // The className parameter (str) can only contain a single class name
+ hasClass : function (elm, className) {
+ if (!className) {
+ return false;
+ }
+ return -1 != (' ' + elm.className.replace(/\s+/g, ' ') + ' ').indexOf(' ' + className + ' ');
+ },
+
+
+ // The className parameter (str) can contain multiple class names separated by whitespace
+ setClass : function (elm, className) {
+ var classList = jsc.classNameToList(className);
+ for (var i = 0; i < classList.length; i += 1) {
+ if (!jsc.hasClass(elm, classList[i])) {
+ elm.className += (elm.className ? ' ' : '') + classList[i];
+ }
+ }
+ },
+
+
+ // The className parameter (str) can contain multiple class names separated by whitespace
+ unsetClass : function (elm, className) {
+ var classList = jsc.classNameToList(className);
+ for (var i = 0; i < classList.length; i += 1) {
+ var repl = new RegExp(
+ '^\\s*' + classList[i] + '\\s*|' +
+ '\\s*' + classList[i] + '\\s*$|' +
+ '\\s+' + classList[i] + '(\\s+)',
+ 'g'
+ );
+ elm.className = elm.className.replace(repl, '$1');
+ }
+ },
+
+
+ getStyle : function (elm) {
+ return window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle;
+ },
+
+
+ setStyle : (function () {
+ var helper = document.createElement('div');
+ var getSupportedProp = function (names) {
+ for (var i = 0; i < names.length; i += 1) {
+ if (names[i] in helper.style) {
+ return names[i];
+ }
+ }
+ };
+ var props = {
+ borderRadius: getSupportedProp(['borderRadius', 'MozBorderRadius', 'webkitBorderRadius']),
+ boxShadow: getSupportedProp(['boxShadow', 'MozBoxShadow', 'webkitBoxShadow'])
+ };
+ return function (elm, prop, value) {
+ switch (prop.toLowerCase()) {
+ case 'opacity':
+ var alphaOpacity = Math.round(parseFloat(value) * 100);
+ elm.style.opacity = value;
+ elm.style.filter = 'alpha(opacity=' + alphaOpacity + ')';
+ break;
+ default:
+ elm.style[props[prop]] = value;
+ break;
+ }
+ };
+ })(),
+
+
+ setBorderRadius : function (elm, value) {
+ jsc.setStyle(elm, 'borderRadius', value || '0');
+ },
+
+
+ setBoxShadow : function (elm, value) {
+ jsc.setStyle(elm, 'boxShadow', value || 'none');
+ },
+
+
+ getElementPos : function (e, relativeToViewport) {
+ var x=0, y=0;
+ var rect = e.getBoundingClientRect();
+ x = rect.left;
+ y = rect.top;
+ if (!relativeToViewport) {
+ var viewPos = jsc.getViewPos();
+ x += viewPos[0];
+ y += viewPos[1];
+ }
+ return [x, y];
+ },
+
+
+ getElementSize : function (e) {
+ return [e.offsetWidth, e.offsetHeight];
+ },
+
+
+ // get pointer's X/Y coordinates relative to viewport
+ getAbsPointerPos : function (e) {
+ if (!e) { e = window.event; }
+ var x = 0, y = 0;
+ if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) {
+ // touch devices
+ x = e.changedTouches[0].clientX;
+ y = e.changedTouches[0].clientY;
+ } else if (typeof e.clientX === 'number') {
+ x = e.clientX;
+ y = e.clientY;
+ }
+ return { x: x, y: y };
+ },
+
+
+ // get pointer's X/Y coordinates relative to target element
+ getRelPointerPos : function (e) {
+ if (!e) { e = window.event; }
+ var target = e.target || e.srcElement;
+ var targetRect = target.getBoundingClientRect();
+
+ var x = 0, y = 0;
+
+ var clientX = 0, clientY = 0;
+ if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) {
+ // touch devices
+ clientX = e.changedTouches[0].clientX;
+ clientY = e.changedTouches[0].clientY;
+ } else if (typeof e.clientX === 'number') {
+ clientX = e.clientX;
+ clientY = e.clientY;
+ }
+
+ x = clientX - targetRect.left;
+ y = clientY - targetRect.top;
+ return { x: x, y: y };
+ },
+
+
+ getViewPos : function () {
+ var doc = document.documentElement;
+ return [
+ (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0),
+ (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
+ ];
+ },
+
+
+ getViewSize : function () {
+ var doc = document.documentElement;
+ return [
+ (window.innerWidth || doc.clientWidth),
+ (window.innerHeight || doc.clientHeight),
+ ];
+ },
+
+
+ redrawPosition : function () {
+
+ if (jsc.picker && jsc.picker.owner) {
+ var thisObj = jsc.picker.owner;
+
+ var tp, vp;
+
+ if (thisObj.fixed) {
+ // Fixed elements are positioned relative to viewport,
+ // therefore we can ignore the scroll offset
+ tp = jsc.getElementPos(thisObj.targetElement, true); // target pos
+ vp = [0, 0]; // view pos
+ } else {
+ tp = jsc.getElementPos(thisObj.targetElement); // target pos
+ vp = jsc.getViewPos(); // view pos
+ }
+
+ var ts = jsc.getElementSize(thisObj.targetElement); // target size
+ var vs = jsc.getViewSize(); // view size
+ var ps = jsc.getPickerOuterDims(thisObj); // picker size
+ var a, b, c;
+ switch (thisObj.position.toLowerCase()) {
+ case 'left': a=1; b=0; c=-1; break;
+ case 'right':a=1; b=0; c=1; break;
+ case 'top': a=0; b=1; c=-1; break;
+ default: a=0; b=1; c=1; break;
+ }
+ var l = (ts[b]+ps[b])/2;
+
+ // compute picker position
+ if (!thisObj.smartPosition) {
+ var pp = [
+ tp[a],
+ tp[b]+ts[b]-l+l*c
+ ];
+ } else {
+ var pp = [
+ -vp[a]+tp[a]+ps[a] > vs[a] ?
+ (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
+ tp[a],
+ -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
+ (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
+ (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
+ ];
+ }
+
+ var x = pp[a];
+ var y = pp[b];
+ var positionValue = thisObj.fixed ? 'fixed' : 'absolute';
+ var contractShadow =
+ (pp[0] + ps[0] > tp[0] || pp[0] < tp[0] + ts[0]) &&
+ (pp[1] + ps[1] < tp[1] + ts[1]);
+
+ jsc._drawPosition(thisObj, x, y, positionValue, contractShadow);
+ }
+ },
+
+
+ _drawPosition : function (thisObj, x, y, positionValue, contractShadow) {
+ var vShadow = contractShadow ? 0 : thisObj.shadowBlur; // px
+
+ jsc.picker.wrap.style.position = positionValue;
+ jsc.picker.wrap.style.left = x + 'px';
+ jsc.picker.wrap.style.top = y + 'px';
+
+ jsc.setBoxShadow(
+ jsc.picker.boxS,
+ thisObj.shadow ?
+ new jsc.BoxShadow(0, vShadow, thisObj.shadowBlur, 0, thisObj.shadowColor) :
+ null);
+ },
+
+
+ getPickerDims : function (thisObj) {
+ var displaySlider = !!jsc.getSliderComponent(thisObj);
+ var dims = [
+ 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.width +
+ (displaySlider ? 2 * thisObj.insetWidth + jsc.getPadToSliderPadding(thisObj) + thisObj.sliderSize : 0),
+ 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.height +
+ (thisObj.closable ? 2 * thisObj.insetWidth + thisObj.padding + thisObj.buttonHeight : 0)
+ ];
+ return dims;
+ },
+
+
+ getPickerOuterDims : function (thisObj) {
+ var dims = jsc.getPickerDims(thisObj);
+ return [
+ dims[0] + 2 * thisObj.borderWidth,
+ dims[1] + 2 * thisObj.borderWidth
+ ];
+ },
+
+
+ getPadToSliderPadding : function (thisObj) {
+ return Math.max(thisObj.padding, 1.5 * (2 * thisObj.pointerBorderWidth + thisObj.pointerThickness));
+ },
+
+
+ getPadYComponent : function (thisObj) {
+ switch (thisObj.mode.charAt(1).toLowerCase()) {
+ case 'v': return 'v'; break;
+ }
+ return 's';
+ },
+
+
+ getSliderComponent : function (thisObj) {
+ if (thisObj.mode.length > 2) {
+ switch (thisObj.mode.charAt(2).toLowerCase()) {
+ case 's': return 's'; break;
+ case 'v': return 'v'; break;
+ }
+ }
+ return null;
+ },
+
+
+ onDocumentMouseDown : function (e) {
+ if (!e) { e = window.event; }
+ var target = e.target || e.srcElement;
+
+ if (target._jscLinkedInstance) {
+ if (target._jscLinkedInstance.showOnClick) {
+ target._jscLinkedInstance.show();
+ }
+ } else if (target._jscControlName) {
+ jsc.onControlPointerStart(e, target, target._jscControlName, 'mouse');
+ } else {
+ // Mouse is outside the picker controls -> hide the color picker!
+ if (jsc.picker && jsc.picker.owner) {
+ jsc.picker.owner.hide();
+ }
+ }
+ },
+
+
+ onDocumentTouchStart : function (e) {
+ if (!e) { e = window.event; }
+ var target = e.target || e.srcElement;
+
+ if (target._jscLinkedInstance) {
+ if (target._jscLinkedInstance.showOnClick) {
+ target._jscLinkedInstance.show();
+ }
+ } else if (target._jscControlName) {
+ jsc.onControlPointerStart(e, target, target._jscControlName, 'touch');
+ } else {
+ if (jsc.picker && jsc.picker.owner) {
+ jsc.picker.owner.hide();
+ }
+ }
+ },
+
+
+ onWindowResize : function (e) {
+ jsc.redrawPosition();
+ },
+
+
+ onParentScroll : function (e) {
+ // hide the picker when one of the parent elements is scrolled
+ if (jsc.picker && jsc.picker.owner) {
+ jsc.picker.owner.hide();
+ }
+ },
+
+
+ _pointerMoveEvent : {
+ mouse: 'mousemove',
+ touch: 'touchmove'
+ },
+ _pointerEndEvent : {
+ mouse: 'mouseup',
+ touch: 'touchend'
+ },
+
+
+ _pointerOrigin : null,
+ _capturedTarget : null,
+
+
+ onControlPointerStart : function (e, target, controlName, pointerType) {
+ var thisObj = target._jscInstance;
+
+ jsc.preventDefault(e);
+ jsc.captureTarget(target);
+
+ var registerDragEvents = function (doc, offset) {
+ jsc.attachGroupEvent('drag', doc, jsc._pointerMoveEvent[pointerType],
+ jsc.onDocumentPointerMove(e, target, controlName, pointerType, offset));
+ jsc.attachGroupEvent('drag', doc, jsc._pointerEndEvent[pointerType],
+ jsc.onDocumentPointerEnd(e, target, controlName, pointerType));
+ };
+
+ registerDragEvents(document, [0, 0]);
+
+ if (window.parent && window.frameElement) {
+ var rect = window.frameElement.getBoundingClientRect();
+ var ofs = [-rect.left, -rect.top];
+ registerDragEvents(window.parent.window.document, ofs);
+ }
+
+ var abs = jsc.getAbsPointerPos(e);
+ var rel = jsc.getRelPointerPos(e);
+ jsc._pointerOrigin = {
+ x: abs.x - rel.x,
+ y: abs.y - rel.y
+ };
+
+ switch (controlName) {
+ case 'pad':
+ // if the slider is at the bottom, move it up
+ switch (jsc.getSliderComponent(thisObj)) {
+ case 's': if (thisObj.hsv[1] === 0) { thisObj.fromHSV(null, 100, null); }; break;
+ case 'v': if (thisObj.hsv[2] === 0) { thisObj.fromHSV(null, null, 100); }; break;
+ }
+ jsc.setPad(thisObj, e, 0, 0);
+ break;
+
+ case 'sld':
+ jsc.setSld(thisObj, e, 0);
+ break;
+ }
+
+ jsc.dispatchFineChange(thisObj);
+ },
+
+
+ onDocumentPointerMove : function (e, target, controlName, pointerType, offset) {
+ return function (e) {
+ var thisObj = target._jscInstance;
+ switch (controlName) {
+ case 'pad':
+ if (!e) { e = window.event; }
+ jsc.setPad(thisObj, e, offset[0], offset[1]);
+ jsc.dispatchFineChange(thisObj);
+ break;
+
+ case 'sld':
+ if (!e) { e = window.event; }
+ jsc.setSld(thisObj, e, offset[1]);
+ jsc.dispatchFineChange(thisObj);
+ break;
+ }
+ }
+ },
+
+
+ onDocumentPointerEnd : function (e, target, controlName, pointerType) {
+ return function (e) {
+ var thisObj = target._jscInstance;
+ jsc.detachGroupEvents('drag');
+ jsc.releaseTarget();
+ // Always dispatch changes after detaching outstanding mouse handlers,
+ // in case some user interaction will occur in user's onchange callback
+ // that would intrude with current mouse events
+ jsc.dispatchChange(thisObj);
+ };
+ },
+
+
+ dispatchChange : function (thisObj) {
+ if (thisObj.valueElement) {
+ if (jsc.isElementType(thisObj.valueElement, 'input')) {
+ jsc.fireEvent(thisObj.valueElement, 'change');
+ }
+ }
+ },
+
+
+ dispatchFineChange : function (thisObj) {
+ if (thisObj.onFineChange) {
+ var callback;
+ if (typeof thisObj.onFineChange === 'string') {
+ callback = new Function (thisObj.onFineChange);
+ } else {
+ callback = thisObj.onFineChange;
+ }
+ callback.call(thisObj);
+ }
+ },
+
+
+ setPad : function (thisObj, e, ofsX, ofsY) {
+ var pointerAbs = jsc.getAbsPointerPos(e);
+ var x = ofsX + pointerAbs.x - jsc._pointerOrigin.x - thisObj.padding - thisObj.insetWidth;
+ var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth;
+
+ var xVal = x * (360 / (thisObj.width - 1));
+ var yVal = 100 - (y * (100 / (thisObj.height - 1)));
+
+ switch (jsc.getPadYComponent(thisObj)) {
+ case 's': thisObj.fromHSV(xVal, yVal, null, jsc.leaveSld); break;
+ case 'v': thisObj.fromHSV(xVal, null, yVal, jsc.leaveSld); break;
+ }
+ },
+
+
+ setSld : function (thisObj, e, ofsY) {
+ var pointerAbs = jsc.getAbsPointerPos(e);
+ var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth;
+
+ var yVal = 100 - (y * (100 / (thisObj.height - 1)));
+
+ switch (jsc.getSliderComponent(thisObj)) {
+ case 's': thisObj.fromHSV(null, yVal, null, jsc.leavePad); break;
+ case 'v': thisObj.fromHSV(null, null, yVal, jsc.leavePad); break;
+ }
+ },
+
+
+ _vmlNS : 'jsc_vml_',
+ _vmlCSS : 'jsc_vml_css_',
+ _vmlReady : false,
+
+
+ initVML : function () {
+ if (!jsc._vmlReady) {
+ // init VML namespace
+ var doc = document;
+ if (!doc.namespaces[jsc._vmlNS]) {
+ doc.namespaces.add(jsc._vmlNS, 'urn:schemas-microsoft-com:vml');
+ }
+ if (!doc.styleSheets[jsc._vmlCSS]) {
+ var tags = ['shape', 'shapetype', 'group', 'background', 'path', 'formulas', 'handles', 'fill', 'stroke', 'shadow', 'textbox', 'textpath', 'imagedata', 'line', 'polyline', 'curve', 'rect', 'roundrect', 'oval', 'arc', 'image'];
+ var ss = doc.createStyleSheet();
+ ss.owningElement.id = jsc._vmlCSS;
+ for (var i = 0; i < tags.length; i += 1) {
+ ss.addRule(jsc._vmlNS + '\\:' + tags[i], 'behavior:url(#default#VML);');
+ }
+ }
+ jsc._vmlReady = true;
+ }
+ },
+
+
+ createPalette : function () {
+
+ var paletteObj = {
+ elm: null,
+ draw: null
+ };
+
+ if (jsc.isCanvasSupported) {
+ // Canvas implementation for modern browsers
+
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('2d');
+
+ var drawFunc = function (width, height, type) {
+ canvas.width = width;
+ canvas.height = height;
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ var hGrad = ctx.createLinearGradient(0, 0, canvas.width, 0);
+ hGrad.addColorStop(0 / 6, '#F00');
+ hGrad.addColorStop(1 / 6, '#FF0');
+ hGrad.addColorStop(2 / 6, '#0F0');
+ hGrad.addColorStop(3 / 6, '#0FF');
+ hGrad.addColorStop(4 / 6, '#00F');
+ hGrad.addColorStop(5 / 6, '#F0F');
+ hGrad.addColorStop(6 / 6, '#F00');
+
+ ctx.fillStyle = hGrad;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ var vGrad = ctx.createLinearGradient(0, 0, 0, canvas.height);
+ switch (type.toLowerCase()) {
+ case 's':
+ vGrad.addColorStop(0, 'rgba(255,255,255,0)');
+ vGrad.addColorStop(1, 'rgba(255,255,255,1)');
+ break;
+ case 'v':
+ vGrad.addColorStop(0, 'rgba(0,0,0,0)');
+ vGrad.addColorStop(1, 'rgba(0,0,0,1)');
+ break;
+ }
+ ctx.fillStyle = vGrad;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ };
+
+ paletteObj.elm = canvas;
+ paletteObj.draw = drawFunc;
+
+ } else {
+ // VML fallback for IE 7 and 8
+
+ jsc.initVML();
+
+ var vmlContainer = document.createElement('div');
+ vmlContainer.style.position = 'relative';
+ vmlContainer.style.overflow = 'hidden';
+
+ var hGrad = document.createElement(jsc._vmlNS + ':fill');
+ hGrad.type = 'gradient';
+ hGrad.method = 'linear';
+ hGrad.angle = '90';
+ hGrad.colors = '16.67% #F0F, 33.33% #00F, 50% #0FF, 66.67% #0F0, 83.33% #FF0'
+
+ var hRect = document.createElement(jsc._vmlNS + ':rect');
+ hRect.style.position = 'absolute';
+ hRect.style.left = -1 + 'px';
+ hRect.style.top = -1 + 'px';
+ hRect.stroked = false;
+ hRect.appendChild(hGrad);
+ vmlContainer.appendChild(hRect);
+
+ var vGrad = document.createElement(jsc._vmlNS + ':fill');
+ vGrad.type = 'gradient';
+ vGrad.method = 'linear';
+ vGrad.angle = '180';
+ vGrad.opacity = '0';
+
+ var vRect = document.createElement(jsc._vmlNS + ':rect');
+ vRect.style.position = 'absolute';
+ vRect.style.left = -1 + 'px';
+ vRect.style.top = -1 + 'px';
+ vRect.stroked = false;
+ vRect.appendChild(vGrad);
+ vmlContainer.appendChild(vRect);
+
+ var drawFunc = function (width, height, type) {
+ vmlContainer.style.width = width + 'px';
+ vmlContainer.style.height = height + 'px';
+
+ hRect.style.width =
+ vRect.style.width =
+ (width + 1) + 'px';
+ hRect.style.height =
+ vRect.style.height =
+ (height + 1) + 'px';
+
+ // Colors must be specified during every redraw, otherwise IE won't display
+ // a full gradient during a subsequential redraw
+ hGrad.color = '#F00';
+ hGrad.color2 = '#F00';
+
+ switch (type.toLowerCase()) {
+ case 's':
+ vGrad.color = vGrad.color2 = '#FFF';
+ break;
+ case 'v':
+ vGrad.color = vGrad.color2 = '#000';
+ break;
+ }
+ };
+
+ paletteObj.elm = vmlContainer;
+ paletteObj.draw = drawFunc;
+ }
+
+ return paletteObj;
+ },
+
+
+ createSliderGradient : function () {
+
+ var sliderObj = {
+ elm: null,
+ draw: null
+ };
+
+ if (jsc.isCanvasSupported) {
+ // Canvas implementation for modern browsers
+
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('2d');
+
+ var drawFunc = function (width, height, color1, color2) {
+ canvas.width = width;
+ canvas.height = height;
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ var grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
+ grad.addColorStop(0, color1);
+ grad.addColorStop(1, color2);
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ };
+
+ sliderObj.elm = canvas;
+ sliderObj.draw = drawFunc;
+
+ } else {
+ // VML fallback for IE 7 and 8
+
+ jsc.initVML();
+
+ var vmlContainer = document.createElement('div');
+ vmlContainer.style.position = 'relative';
+ vmlContainer.style.overflow = 'hidden';
+
+ var grad = document.createElement(jsc._vmlNS + ':fill');
+ grad.type = 'gradient';
+ grad.method = 'linear';
+ grad.angle = '180';
+
+ var rect = document.createElement(jsc._vmlNS + ':rect');
+ rect.style.position = 'absolute';
+ rect.style.left = -1 + 'px';
+ rect.style.top = -1 + 'px';
+ rect.stroked = false;
+ rect.appendChild(grad);
+ vmlContainer.appendChild(rect);
+
+ var drawFunc = function (width, height, color1, color2) {
+ vmlContainer.style.width = width + 'px';
+ vmlContainer.style.height = height + 'px';
+
+ rect.style.width = (width + 1) + 'px';
+ rect.style.height = (height + 1) + 'px';
+
+ grad.color = color1;
+ grad.color2 = color2;
+ };
+
+ sliderObj.elm = vmlContainer;
+ sliderObj.draw = drawFunc;
+ }
+
+ return sliderObj;
+ },
+
+
+ leaveValue : 1<<0,
+ leaveStyle : 1<<1,
+ leavePad : 1<<2,
+ leaveSld : 1<<3,
+
+
+ BoxShadow : (function () {
+ var BoxShadow = function (hShadow, vShadow, blur, spread, color, inset) {
+ this.hShadow = hShadow;
+ this.vShadow = vShadow;
+ this.blur = blur;
+ this.spread = spread;
+ this.color = color;
+ this.inset = !!inset;
+ };
+
+ BoxShadow.prototype.toString = function () {
+ var vals = [
+ Math.round(this.hShadow) + 'px',
+ Math.round(this.vShadow) + 'px',
+ Math.round(this.blur) + 'px',
+ Math.round(this.spread) + 'px',
+ this.color
+ ];
+ if (this.inset) {
+ vals.push('inset');
+ }
+ return vals.join(' ');
+ };
+
+ return BoxShadow;
+ })(),
+
+
+ //
+ // Usage:
+ // var myColor = new jscolor({% trans "Bad request" %}
+ {% blocktrans %}Sorry, your request was bad. Don't know what could be wrong. An email has been sent to webmasters with the details of the error. You can now drink a coke.{% endblocktrans %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/403.html b/templates/403.html
new file mode 100644
index 00000000..317865f2
--- /dev/null
+++ b/templates/403.html
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+
+{% load i18n %}
+
+{% block content %}
+ {% trans "Permission denied" %}
+ {% blocktrans %}You don't have the right to perform this request.{% endblocktrans %}
+ {% if exception %}
+ {% trans "Page not found" %}
+ {% blocktrans %}The requested path {{ request_path }}
was not found on the server.{% endblocktrans %}
+ {% if exception != "Resolver404" %}
+ {% trans "Server error" %}
+ {% blocktrans %}Sorry, an error occurred when processing your request. An email has been sent to webmasters with the detail of the error, and this will be fixed soon. You can now drink a beer.{% endblocktrans %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/base.html b/templates/base.html
index 3c2c637f..646f27e9 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -31,8 +31,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous">
-
+
+
{# JQuery, Bootstrap and Turbolinks JavaScript #}
{% endblock %}
diff --git a/templates/member/profile_info.html b/templates/member/profile_info.html
index 74856355..7be10ba1 100644
--- a/templates/member/profile_info.html
+++ b/templates/member/profile_info.html
@@ -17,12 +17,14 @@
+ {% regroup active_memberships by roles as memberships_per_role %}
+ {% for role in roles %}
+
+{% endblock %}
+
+{% block extrajavascript %}
+
+{% endblock %}
diff --git a/templates/registration/email_validation_complete.html b/templates/registration/email_validation_complete.html
index 4835cfa1..b54432f3 100644
--- a/templates/registration/email_validation_complete.html
+++ b/templates/registration/email_validation_complete.html
@@ -4,7 +4,7 @@
{% block content %}
{% if validlink %}
{% trans "Your email have successfully been validated." %}
- {% if user.profile.registration_valid %}
+ {% if user_object.profile.registration_valid %}
{% blocktrans %}You can now log in.{% endblocktrans %}
{% else %}
{% trans "You must pay now your membership in the Kfet to complete your registration." %}
diff --git a/templates/registration/future_profile_detail.html b/templates/registration/future_profile_detail.html
index 8c78fb8d..1d2d08c7 100644
--- a/templates/registration/future_profile_detail.html
+++ b/templates/registration/future_profile_detail.html
@@ -31,13 +31,6 @@
{% endif %}
-
+ {% for permission in role.permissions.permissions.all %}
+
+
+ {% trans "The inscription for this WEI are now closed." %} +
++ {% trans "The survey is now ended. Your answers have been saved." %} +
+LE WEI, c'est cool !
+ ++ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Dapibus ultrices in iaculis nunc sed augue. In hendrerit gravida rutrum quisque non tellus orci + ac. Massa vitae tortor condimentum lacinia quis vel eros. Elit ut aliquam purus sit amet. Aliquam faucibus + purus in massa tempor. Quisque id diam vel quam elementum pulvinar etiam non. Condimentum id venenatis a + condimentum vitae sapien pellentesque habitant. Egestas congue quisque egestas diam in. Vestibulum rhoncus + est pellentesque elit ullamcorper. Massa sed elementum tempus egestas sed sed. Sapien pellentesque habitant + morbi tristique. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare. Sed + adipiscing diam donec adipiscing. Leo integer malesuada nunc vel risus commodo viverra maecenas. +
+ ++ Fusce id velit ut tortor pretium viverra suspendisse. Urna condimentum mattis pellentesque id nibh tortor id + aliquet. Vel facilisis volutpat est velit egestas dui. Turpis egestas sed tempus urna et pharetra pharetra + massa massa. Eget nunc scelerisque viverra mauris in. Etiam dignissim diam quis enim. Urna cursus eget nunc + scelerisque viverra mauris in aliquam sem. Amet porttitor eget dolor morbi non arcu risus quis. Ullamcorper + sit amet risus nullam eget felis. Ullamcorper eget nulla facilisi etiam dignissim diam quis. Enim nulla + aliquet porttitor lacus luctus accumsan tortor. Urna condimentum mattis pellentesque id nibh tortor id. + Feugiat in fermentum posuere urna nec. Risus nec feugiat in fermentum posuere urna nec tincidunt. Porttitor + massa id neque aliquam vestibulum morbi. Diam quis enim lobortis scelerisque. Ornare massa eget egestas + purus. Ut tortor pretium viverra suspendisse. Purus in mollis nunc sed. Tristique magna sit amet purus + gravida. +
+ ++ Ut porttitor leo a diam sollicitudin tempor. Viverra nam libero justo laoreet sit amet cursus sit amet. + Lectus arcu bibendum at varius vel pharetra vel turpis nunc. Vivamus arcu felis bibendum ut tristique et + egestas quis ipsum. Parturient montes nascetur ridiculus mus mauris. A cras semper auctor neque vitae + tempus quam pellentesque. Netus et malesuada fames ac. Mauris in aliquam sem fringilla ut. Sapien + pellentesque habitant morbi tristique. Mauris sit amet massa vitae tortor condimentum. Sagittis + aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc. Amet consectetur adipiscing elit + duis tristique sollicitudin nibh sit. Nunc mattis enim ut tellus elementum. Sapien eget mi proin sed libero + enim. Pulvinar sapien et ligula ullamcorper. Nibh mauris cursus mattis molestie a iaculis at erat + pellentesque. Molestie at elementum eu facilisis. Velit sed ullamcorper morbi tincidunt. Quam vulputate + dignissim suspendisse in est ante. +
+ ++ Id cursus metus aliquam eleifend mi. Eu turpis egestas pretium aenean pharetra magna ac. Faucibus ornare + suspendisse sed nisi lacus sed viverra tellus. Sed vulputate mi sit amet mauris commodo. Lacus laoreet non + curabitur gravida arcu ac. At ultrices mi tempus imperdiet nulla malesuada pellentesque elit eget. Fusce ut + placerat orci nulla pellentesque dignissim. Quis blandit turpis cursus in hac habitasse platea dictumst + quisque. Tellus id interdum velit laoreet id donec ultrices. Risus feugiat in ante metus dictum. Velit ut + tortor pretium viverra suspendisse. Lacus vel facilisis volutpat est velit egestas dui id. Nunc eget lorem + dolor sed viverra ipsum nunc aliquet bibendum. Varius quam quisque id diam vel quam. Orci dapibus ultrices + in iaculis. Neque gravida in fermentum et sollicitudin ac orci. +
+