1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-02-05 23:03:02 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Yohann D'ANELLO
a9ccf46010 Linters 2020-05-29 21:43:24 +02:00
Yohann D'ANELLO
f567b1a343 Activity list is displayed in the right order 2020-05-29 21:37:44 +02:00
Yohann D'ANELLO
155b2df330 Fix some permissions, users can log in 2020-05-29 21:26:05 +02:00
Yohann D'ANELLO
716232e27f With distinct permissions, we don't need to check ~ 100 000 permissions to check if someone can log in 2020-05-29 21:11:51 +02:00
Yohann D'ANELLO
c62b5f935a Merge remote-tracking branch 'origin/master' into beta-soon
# Conflicts:
#	apps/scripts
2020-05-29 21:11:14 +02:00
Pierre-antoine Comby
f468c2f939 Merge branch 'import_nk15' into 'master'
Import nk15

See merge request bde/nk20!81
2020-05-25 22:09:52 +02:00
Pierre-antoine Comby
7597ad859a Merge branch 'scripts' into 'master'
Scripts

See merge request bde/nk20!80
2020-05-25 12:31:46 +02:00
Pierre-antoine Comby
640d31d200 fix install for python 3.8 2020-05-25 12:27:05 +02:00
Pierre-antoine Comby
79fbe96fe1 updates scripts 2020-05-25 12:26:33 +02:00
Pierre-antoine Comby
424646054f Merge branch 'move_wei' into 'master'
move wei script to wei app

See merge request bde/nk20!79
2020-05-14 15:22:06 +02:00
Pierre-antoine Comby
110ef79951 move wei script to wei app 2020-05-14 15:16:10 +02:00
Yohann D'ANELLO
fdf373d1d5 Merge remote-tracking branch 'origin/master' into import_nk15
# Conflicts:
#	apps/treasury/signals.py
2020-05-07 19:01:23 +02:00
Pierre-antoine Comby
6d27193ac4 update import script 2020-04-18 16:07:45 +02:00
Pierre-antoine Comby
038ddc2ab8 remittance need preciser check (bug during import) 2020-04-18 15:59:59 +02:00
Pierre-antoine Comby
cc97948c24 clean specialTransaction 2020-04-18 15:59:06 +02:00
Pierre-antoine Comby
53748cd534 frenglish -> english 2020-04-18 15:57:11 +02:00
12 changed files with 193 additions and 16 deletions

View File

@ -36,9 +36,7 @@ class ActivityCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
model = Activity
table_class = ActivityTable
def get_queryset(self):
return super().get_queryset().reverse()
ordering = ('-date_start',)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@ -47,7 +45,9 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
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")))
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
prefix='upcoming-',
)
return context

View File

@ -1,6 +1,6 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone
@ -264,6 +264,18 @@ class SpecialTransaction(Transaction):
def type(self):
return _('Credit') if isinstance(self.source, NoteSpecial) else _("Debit")
def is_credit(self):
return isinstance(self.source, NoteSpecial)
def is_debit(self):
return isinstance(self.destination, NoteSpecial)
def clean(self):
# SpecialTransaction are only possible with NoteSpecial object
if self.is_credit() == self.is_debit():
raise(ValidationError(_("A special transaction is only possible between a"
" Note associated to a payment method and a User or a Club")))
class MembershipTransaction(Transaction):
"""

View File

@ -3,6 +3,7 @@
import datetime
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.contenttypes.models import ContentType
@ -36,7 +37,7 @@ class PermissionBackend(ModelBackend):
# Unauthenticated users have no permissions
return Permission.objects.none()
return Permission.objects.annotate(
qs = Permission.objects.annotate(
club=F("rolepermissions__role__membership__club"),
membership=F("rolepermissions__role__membership"),
).filter(
@ -50,7 +51,13 @@ class PermissionBackend(ModelBackend):
& Q(rolepermissions__role__membership__user=user)
& Q(type=t)
& Q(mask__rank__lte=get_current_session().get("permission_mask", 0))
).distinct()
)
if settings.DATABASES[qs.db]["ENGINE"] == 'django.db.backends.postgresql_psycopg2':
qs = qs.distinct('pk', 'club')
else: # SQLite doesn't support distinct fields.
qs = qs.distinct()
return qs
@staticmethod
def permissions(user, model, type):

View File

@ -2192,7 +2192,7 @@
"activity",
"activity"
],
"query": "{\"entry__note__noteuser__user\": [\"user\"]}",
"query": "{\"entries__note__user\": [\"user\"]}",
"type": "view",
"mask": 1,
"field": "",

View File

@ -19,7 +19,7 @@ class ProtectQuerysetMixin:
"""
def get_queryset(self, **kwargs):
qs = super().get_queryset(**kwargs)
return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view"))
return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct()
def get_form(self, form_class=None):
form = super().get_form(form_class)

@ -1 +1 @@
Subproject commit c37a6effc9217e2ffceb631f48b371f87814c1f6
Subproject commit ee54fca89ee247a4ba4af080dd3036d92340eade

View File

@ -191,7 +191,7 @@ class SpecialTransactionProxy(models.Model):
"""
In order to keep modularity, we don't that the Note app depends on the treasury app.
That's why we create a proxy in this app, to link special transactions and remittances.
If it isn't very clean, that makes what we want.
If it isn't very clean, it does what we want.
"""
transaction = models.OneToOneField(

View File

@ -1,7 +1,6 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from note.models import NoteSpecial
from treasury.models import SpecialTransactionProxy, RemittanceType
@ -9,6 +8,10 @@ def save_special_transaction(instance, created, **kwargs):
"""
When a special transaction is created, we create its linked proxy
"""
if created and isinstance(instance.source, NoteSpecial) \
and RemittanceType.objects.filter(note=instance.source).exists():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()
if instance.is_credit():
if created and RemittanceType.objects.filter(note=instance.source).exists():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()
else:
if created and RemittanceType.objects.filter(note=instance.destination).exists():
SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save()

View File

@ -0,0 +1,88 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.management import BaseCommand, CommandError
from django.db.models import Q
from django.db.models.functions import Lower
from wei.models import WEIClub, Bus, BusTeam, WEIMembership
class Command(BaseCommand):
help = "Export WEI registrations."
def add_arguments(self, parser):
parser.add_argument('--bus', '-b', choices=[bus.name for bus in Bus.objects.all()], type=str, default=None,
help='Filter by bus')
parser.add_argument('--team', '-t', choices=[team.name for team in BusTeam.objects.all()], type=str,
default=None, help='Filter by team. Type "none" if you want to select the members '
+ 'that are not in a team.')
parser.add_argument('--year', '-y', type=int, default=None,
help='Select the year of the concerned WEI. Default: last year')
parser.add_argument('--sep', type=str, default='|',
help='Select the CSV separator.')
def handle(self, *args, **options):
year = options["year"]
if year:
try:
wei = WEIClub.objects.get(year=year)
except WEIClub.DoesNotExist:
raise CommandError("The WEI of year {:d} does not exist.".format(year,))
else:
wei = WEIClub.objects.order_by('-year').first()
bus = options["bus"]
if bus:
try:
bus = Bus.objects.filter(wei=wei).get(name=bus)
except Bus.DoesNotExist:
raise CommandError("The bus {} does not exist or does not belong to the WEI {}.".format(bus, wei.name,))
team = options["team"]
if team:
if team.lower() == "none":
team = 0
else:
try:
team = BusTeam.objects.filter(Q(bus=bus) | Q(wei=wei)).get(name=team)
bus = team.bus
except BusTeam.DoesNotExist:
raise CommandError("The bus {} does not exist or does not belong to the bus {} neither the wei {}."
.format(team, bus.name if bus else "<None>", wei.name,))
qs = WEIMembership.objects
qs = qs.filter(club=wei).order_by(
Lower('bus__name'),
Lower('team__name'),
'user__profile__promotion',
Lower('user__last_name'),
Lower('user__first_name'),
).distinct()
if bus:
qs = qs.filter(bus=bus)
if team is not None:
qs = qs.filter(team=team if team else None)
sep = options["sep"]
self.stdout.write("Nom|Prénom|Date de naissance|Genre|Département|Année|Section|Bus|Équipe|Rôles"
.replace(sep, sep))
for membership in qs.all():
user = membership.user
registration = membership.registration
bus = membership.bus
team = membership.team
s = user.last_name
s += sep + user.first_name
s += sep + str(registration.birth_date)
s += sep + registration.get_gender_display()
s += sep + user.profile.get_department_display()
s += sep + str(user.profile.ens_year) + "A"
s += sep + user.profile.section_generated
s += sep + bus.name
s += sep + (team.name if team else "--")
s += sep + ", ".join(role.name for role in membership.roles.filter(~Q(name="Adhérent WEI")).all())
self.stdout.write(s)

View File

@ -0,0 +1,52 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import date
from django.core.management import BaseCommand
from django.db.models import Q
from member.models import Membership, Club
from wei.models import WEIClub
class Command(BaseCommand):
help = "Get mailing list registrations from the last wei. " \
"Usage: manage.py extract_ml_registrations -t {events,art,sport}. " \
"You can write this into a file with a pipe, then paste the document into your mail manager."
def add_arguments(self, parser):
parser.add_argument('--type', '-t', choices=["members", "clubs", "events", "art", "sport"], default="members",
help='Select the type of the mailing list (default members)')
parser.add_argument('--year', '-y', type=int, default=None,
help='Select the year of the concerned WEI. Default: last year')
def handle(self, *args, **options):
if options["type"] == "members":
for membership in Membership.objects.filter(
club__name="BDE",
date_start__lte=date.today(),
date_end__gte=date.today(),
).all():
self.stdout.write(membership.user.email)
return
if options["type"] == "clubs":
for club in Club.objects.all():
self.stdout.write(club.email)
return
if options["year"] is None:
wei = WEIClub.objects.order_by('-year').first()
else:
wei = WEIClub.objects.filter(year=options["year"])
if wei.exists():
wei = wei.get()
else:
wei = WEIClub.objects.order_by('-year').first()
self.stderr.write(self.style.WARNING("Warning: there was no WEI in year " + str(options["year"]) + ". "
+ "Assuming the last WEI (year " + str(wei.year) + ")"))
q = Q(ml_events_registration=True) if options["type"] == "events" else Q(ml_art_registration=True)\
if options["type"] == "art" else Q(ml_sport_registration=True)
registrations = wei.users.filter(q)
for registration in registrations.all():
self.stdout.write(registration.user.email)

View File

@ -0,0 +1,15 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.management import BaseCommand
from wei.forms import CurrentSurvey
class Command(BaseCommand):
help = "Attribute to each first year member a bus for the WEI"
def handle(self, *args, **options):
"""
Run the WEI algorithm to attribute a bus to each first year member.
"""
CurrentSurvey.get_algorithm_class()().run_algorithm()

View File

@ -11,7 +11,7 @@ django-tables2==2.1.0
docutils==0.14
idna==2.8
oauthlib==3.1.0
Pillow==6.1.0
Pillow==7.1.2
python3-openid==3.1.0
pytz==2019.1
requests==2.22.0