mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-01 05:21:15 +02:00
Compare commits
48 Commits
a0b920ac94
...
svg_icons
Author | SHA1 | Date | |
---|---|---|---|
466cbd9878 | |||
0bd447b608 | |||
3f3c93d928 | |||
340c90f5d3 | |||
a05dfcbf3d
|
|||
ba3c0fb18d
|
|||
ab69963ea1 | |||
654c01631a
|
|||
d94cc2a7ad
|
|||
69bb38297f
|
|||
9628560d64
|
|||
df3bb71357
|
|||
2a216fd994
|
|||
8dd2619013
|
|||
62431a4910
|
|||
946bc1e497 | |||
d4896bfd76
|
|||
23f46cc598
|
|||
d1a9f21b56 | |||
d809b2595a
|
|||
97803ac983 | |||
b951c4aa05 | |||
69b3d2ac9c
|
|||
f29054558a
|
|||
11dd8adbb7 | |||
d437f2bdbd
|
|||
ac8453b04c
|
|||
6b4d18f4b3 | |||
668cfa71a7 | |||
161db0b00b
|
|||
8638c16b34
|
|||
9583cec3ff
|
|||
1ef25924a0
|
|||
e89383e3f4
|
|||
79a116d9c6
|
|||
aa75ce5c7a
|
|||
a3a9dfc812
|
|||
76531595ad
|
|||
7e6a14296a | |||
780f78b385 | |||
5828a20383 | |||
cea3138daf | |||
b4ed354b73 | |||
5eb3ffca66 | |||
789ca149af | |||
08ba0b263a | |||
4583958f50 | |||
bab394908d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -47,6 +47,7 @@ backups/
|
||||
env/
|
||||
venv/
|
||||
db.sqlite3
|
||||
shell.nix
|
||||
|
||||
# ansibles customs host
|
||||
ansible/host_vars/*.yaml
|
||||
|
@ -12,7 +12,7 @@ RUN apt-get update && \
|
||||
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache ipython3 \
|
||||
python3-bs4 python3-setuptools \
|
||||
uwsgi uwsgi-plugin-python3 \
|
||||
texlive-xetex gettext libjs-bootstrap4 fonts-font-awesome && \
|
||||
texlive-xetex gettext libjs-bootstrap4 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Instal PyPI requirements
|
||||
|
@ -23,7 +23,7 @@ Bien que cela permette de créer une instance sur toutes les distributions,
|
||||
$ sudo apt update
|
||||
$ sudo apt install --no-install-recommends -y \
|
||||
ipython3 python3-setuptools python3-venv python3-dev \
|
||||
texlive-xetex gettext libjs-bootstrap4 fonts-font-awesome git
|
||||
texlive-xetex gettext libjs-bootstrap4 git
|
||||
```
|
||||
|
||||
2. **Clonage du dépot** là où vous voulez :
|
||||
@ -115,7 +115,7 @@ Sinon vous pouvez suivre les étapes décrites ci-dessous.
|
||||
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache ipython3 \
|
||||
python3-bs4 python3-setuptools python3-docutils \
|
||||
memcached uwsgi uwsgi-plugin-python3 \
|
||||
texlive-xetex gettext libjs-bootstrap4 fonts-font-awesome \
|
||||
texlive-xetex gettext libjs-bootstrap4 \
|
||||
nginx python3-venv git acl
|
||||
```
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
note:
|
||||
server_name: note-beta.crans.org
|
||||
git_branch: beta
|
||||
cron_enabled: false
|
||||
email: notekfet2020@lists.crans.org
|
@ -2,5 +2,6 @@
|
||||
note:
|
||||
server_name: note-dev.crans.org
|
||||
git_branch: beta
|
||||
serve_static: false
|
||||
cron_enabled: false
|
||||
email: notekfet2020@lists.crans.org
|
||||
|
@ -2,5 +2,6 @@
|
||||
note:
|
||||
server_name: note.crans.org
|
||||
git_branch: master
|
||||
serve_static: true
|
||||
cron_enabled: true
|
||||
email: notekfet2020@lists.crans.org
|
||||
|
@ -1,6 +1,5 @@
|
||||
[dev]
|
||||
bde-note-dev.adh.crans.org
|
||||
bde-nk20-beta.adh.crans.org
|
||||
|
||||
[prod]
|
||||
bde-note.adh.crans.org
|
||||
|
@ -17,7 +17,6 @@
|
||||
- ipython3
|
||||
|
||||
# Front-end dependencies
|
||||
- fonts-font-awesome
|
||||
- libjs-bootstrap4
|
||||
|
||||
# Python dependencies
|
||||
|
@ -41,6 +41,7 @@ server {
|
||||
# max upload size
|
||||
client_max_body_size 75M; # adjust to taste
|
||||
|
||||
{% if note.serve_static %}
|
||||
# Django media
|
||||
location /media {
|
||||
alias /var/www/note_kfet/media; # your Django project's media files - amend as required
|
||||
@ -50,6 +51,7 @@ server {
|
||||
alias /var/www/note_kfet/static; # your Django project's static files - amend as required
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
location /doc {
|
||||
alias /var/www/documentation; # The documentation of the project
|
||||
}
|
||||
|
@ -28,6 +28,12 @@ class ActivityForm(forms.ModelForm):
|
||||
shuffle(clubs)
|
||||
self.fields["organizer"].widget.attrs["placeholder"] = ", ".join(club.name for club in clubs[:4]) + ", ..."
|
||||
|
||||
def clean_organizer(self):
|
||||
organizer = self.cleaned_data['organizer']
|
||||
if not organizer.note.is_active:
|
||||
self.add_error('organiser', _('The note of this club is inactive.'))
|
||||
return organizer
|
||||
|
||||
def clean_date_end(self):
|
||||
date_end = self.cleaned_data["date_end"]
|
||||
date_start = self.cleaned_data["date_start"]
|
||||
|
@ -1,7 +1,9 @@
|
||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.utils import timezone
|
||||
from django.utils.html import format_html
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import django_tables2 as tables
|
||||
from django_tables2 import A
|
||||
@ -52,8 +54,8 @@ class GuestTable(tables.Table):
|
||||
def render_entry(self, record):
|
||||
if record.has_entry:
|
||||
return str(_("Entered on ") + str(_("{:%Y-%m-%d %H:%M:%S}").format(record.entry.time, )))
|
||||
return format_html('<button id="{id}" class="btn btn-danger btn-sm" onclick="remove_guest(this.id)"> '
|
||||
'{delete_trans}</button>'.format(id=record.id, delete_trans=_("remove").capitalize()))
|
||||
return mark_safe('<button id="{id}" class="btn btn-danger btn-sm" onclick="remove_guest(this.id)"> '
|
||||
'{delete_trans}</button>'.format(id=record.id, delete_trans=_("remove").capitalize()))
|
||||
|
||||
|
||||
def get_row_class(record):
|
||||
@ -91,7 +93,7 @@ class EntryTable(tables.Table):
|
||||
if hasattr(record, 'username'):
|
||||
username = record.username
|
||||
if username != value:
|
||||
return format_html(value + " <em>aka.</em> " + username)
|
||||
return mark_safe(escape(value) + " <em>aka.</em> " + escape(username))
|
||||
return value
|
||||
|
||||
def render_balance(self, value):
|
||||
|
@ -63,7 +63,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
refreshBalance();
|
||||
}
|
||||
|
||||
alias_obj.keyup(reloadTable);
|
||||
alias_obj.keyup(function(event) {
|
||||
let code = event.originalEvent.keyCode
|
||||
if (65 <= code <= 122 || code === 13) {
|
||||
debounce(reloadTable)()
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
|
@ -34,7 +34,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endif %}
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-sm btn-success" href="{% url 'activity:activity_create' %}" data-turbolinks="false">
|
||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i>
|
||||
<svg class="bi bi-calendar-plus" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M4 .5a.5.5 0 0 0-1 0V1H2a2 2 0 0 0-2 2v1h16V3a2 2 0 0 0-2-2h-1V.5a.5.5 0 0 0-1 0V1H4V.5zM16 14V5H0v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2zM8.5 8.5V10H10a.5.5 0 0 1 0 1H8.5v1.5a.5.5 0 0 1-1 0V11H6a.5.5 0 0 1 0-1h1.5V8.5a.5.5 0 0 1 1 0z"/>
|
||||
</svg>
|
||||
{% trans 'New activity' %}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -66,8 +66,8 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
||||
ordering = ('-date_start',)
|
||||
extra_context = {"title": _("Activities")}
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().distinct()
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset(**kwargs).distinct()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
@ -78,9 +78,7 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
||||
prefix='upcoming-',
|
||||
)
|
||||
|
||||
started_activities = Activity.objects\
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Activity, "view"))\
|
||||
.filter(open=True, valid=True).all()
|
||||
started_activities = self.get_queryset().filter(open=True, valid=True).distinct().all()
|
||||
context["started_activities"] = started_activities
|
||||
|
||||
return context
|
||||
@ -145,7 +143,7 @@ class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request, Activity, "view"))\
|
||||
.get(pk=self.kwargs["pk"])
|
||||
.filter(pk=self.kwargs["pk"]).first()
|
||||
form.fields["inviter"].initial = self.request.user.note
|
||||
return form
|
||||
|
||||
@ -192,7 +190,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
.annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\
|
||||
.filter(activity=activity)\
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Guest, "view"))\
|
||||
.order_by('last_name', 'first_name').distinct()
|
||||
.order_by('last_name', 'first_name')
|
||||
|
||||
if "search" in self.request.GET and self.request.GET["search"]:
|
||||
pattern = self.request.GET["search"]
|
||||
@ -206,7 +204,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
)
|
||||
else:
|
||||
guest_qs = guest_qs.none()
|
||||
return guest_qs
|
||||
return guest_qs.distinct()
|
||||
|
||||
def get_invited_note(self, activity):
|
||||
"""
|
||||
|
@ -19,8 +19,8 @@ def create_bde_and_kfet(apps, schema_editor):
|
||||
membership_fee_paid=500,
|
||||
membership_fee_unpaid=500,
|
||||
membership_duration=396,
|
||||
membership_start="2020-08-01",
|
||||
membership_end="2021-09-30",
|
||||
membership_start="2021-08-01",
|
||||
membership_end="2022-09-30",
|
||||
)
|
||||
Club.objects.get_or_create(
|
||||
id=2,
|
||||
@ -31,8 +31,8 @@ def create_bde_and_kfet(apps, schema_editor):
|
||||
membership_fee_paid=3500,
|
||||
membership_fee_unpaid=3500,
|
||||
membership_duration=396,
|
||||
membership_start="2020-08-01",
|
||||
membership_end="2021-09-30",
|
||||
membership_start="2021-08-01",
|
||||
membership_end="2022-09-30",
|
||||
)
|
||||
|
||||
NoteClub.objects.get_or_create(
|
||||
|
@ -413,6 +413,12 @@ class Membership(models.Model):
|
||||
"""
|
||||
Calculate fee and end date before saving the membership and creating the transaction if needed.
|
||||
"""
|
||||
# Ensure that club membership dates are valid
|
||||
old_membership_start = self.club.membership_start
|
||||
self.club.update_membership_dates()
|
||||
if self.club.membership_start != old_membership_start:
|
||||
self.club.save()
|
||||
|
||||
created = not self.pk
|
||||
if not created:
|
||||
for role in self.roles.all():
|
||||
|
@ -31,7 +31,8 @@ class ClubTable(tables.Table):
|
||||
row_attrs = {
|
||||
'class': 'table-row',
|
||||
'id': lambda record: "row-" + str(record.pk),
|
||||
'data-href': lambda record: record.pk
|
||||
'data-href': lambda record: record.pk,
|
||||
'style': 'cursor:pointer',
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +75,8 @@ class UserTable(tables.Table):
|
||||
model = User
|
||||
row_attrs = {
|
||||
'class': 'table-row',
|
||||
'data-href': lambda record: record.pk
|
||||
'data-href': lambda record: record.pk,
|
||||
'style': 'cursor:pointer',
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card-footer">
|
||||
{% if user_object %}
|
||||
<a class="btn btn-sm btn-secondary" href="{% url 'member:user_update_profile' user_object.pk %}">
|
||||
<i class="fa fa-edit"></i> {% trans 'Update Profile' %}
|
||||
<svg class="bi bi-edit" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{% trans 'Update Profile' %}
|
||||
</a>
|
||||
{% url 'member:user_detail' user_object.pk as user_profile_url %}
|
||||
{% if request.path_info != user_profile_url %}
|
||||
@ -59,7 +62,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% if ".change_"|has_perm:club %}
|
||||
<a class="btn btn-sm btn-secondary" href="{% url 'member:club_update' pk=club.pk %}"
|
||||
data-turbolinks="false">
|
||||
<i class="fa fa-edit"></i> {% trans 'Update Profile' %}
|
||||
<svg class="bi bi-edit" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{% trans 'Update Profile' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% url 'member:club_detail' club.pk as club_detail_url %}
|
||||
|
@ -10,7 +10,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="font-weight-bold">
|
||||
<i class="fa fa-users"></i> {% trans "Club managers" %}
|
||||
<svg class="bi bi-users" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
</svg>
|
||||
{% trans "Club managers" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table managers %}
|
||||
@ -23,7 +26,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="stretched-link font-weight-bold" href="{% url 'member:club_members' pk=club.pk %}">
|
||||
<i class="fa fa-users"></i> {% trans "Club members" %}
|
||||
<svg class="bi bi-users" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1H7zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M5.216 14A2.238 2.238 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.325 6.325 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1h4.216z"/>
|
||||
<path d="M4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>
|
||||
</svg>
|
||||
{% trans "Club members" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table member_list %}
|
||||
@ -37,7 +45,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:club.note %}
|
||||
href="{% url 'note:transactions' pk=club.note.pk %}" {% endif %}>
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
<svg class="bi bi-euro" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M4 9.42h1.063C5.4 12.323 7.317 14 10.34 14c.622 0 1.167-.068 1.659-.185v-1.3c-.484.119-1.045.17-1.659.17-2.1 0-3.455-1.198-3.775-3.264h4.017v-.928H6.497v-.936c0-.11 0-.219.008-.329h4.078v-.927H6.618c.388-1.898 1.719-2.985 3.723-2.985.614 0 1.175.05 1.659.177V2.194A6.617 6.617 0 0 0 10.341 2c-2.928 0-4.82 1.569-5.244 4.3H4v.928h1.01v1.265H4v.928z"/>
|
||||
</svg>
|
||||
{% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="history_list">
|
||||
|
@ -47,7 +47,9 @@
|
||||
<dt class="col-xl-6">{% trans 'aliases'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
<a class="badge badge-secondary" href="{% url 'member:club_alias' club.pk %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
<svg class="bi bi-edit" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{% trans 'Manage aliases' %} ({{ club.note.alias.all|length }})
|
||||
</a>
|
||||
</dd>
|
||||
|
@ -11,7 +11,9 @@
|
||||
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
<a class="badge badge-secondary" href="{% url 'password_change' %}">
|
||||
<i class="fa fa-lock"></i>
|
||||
<svg class="bi bi-lock" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/>
|
||||
</svg>
|
||||
{% trans 'Change password' %}
|
||||
</a>
|
||||
</dd>
|
||||
@ -20,7 +22,9 @@
|
||||
<dt class="col-xl-6">{% trans 'aliases'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
<a class="badge badge-secondary" href="{% url 'member:user_alias' user_object.pk %}">
|
||||
<i class="fa fa-edit"></i>
|
||||
<svg class="bi bi-edit" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{% trans 'Manage aliases' %} ({{ user_object.note.alias.all|length }})
|
||||
</a>
|
||||
</dd>
|
||||
@ -52,7 +56,10 @@
|
||||
{% if user_object.pk == user.pk %}
|
||||
<div class="text-center">
|
||||
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
|
||||
<i class="fa fa-cogs"></i>{% trans 'API token' %}
|
||||
<svg class="bi bi-cogs" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
|
||||
</svg>
|
||||
{% trans 'API token' %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -18,7 +18,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="font-weight-bold">
|
||||
<i class="fa fa-users"></i> {% trans "View my memberships" %}
|
||||
<svg class="bi bi-users" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
</svg>
|
||||
{% trans "View my memberships" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table club_list %}
|
||||
@ -29,7 +32,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<a class="stretched-link font-weight-bold text-decoration-none"
|
||||
{% if "note.view_note"|has_perm:user_object.note %}
|
||||
href="{% url 'note:transactions' pk=user_object.note.pk %}" {% endif %}>
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
<svg class="bi bi-euro" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M4 9.42h1.063C5.4 12.323 7.317 14 10.34 14c.622 0 1.167-.068 1.659-.185v-1.3c-.484.119-1.045.17-1.659.17-2.1 0-3.455-1.198-3.775-3.264h4.017v-.928H6.497v-.936c0-.11 0-.219.008-.329h4.078v-.927H6.618c.388-1.898 1.719-2.985 3.723-2.985.614 0 1.175.05 1.659.177V2.194A6.617 6.617 0 0 0 10.341 2c-2.928 0-4.82 1.569-5.244 4.3H4v.928h1.01v1.265H4v.928z"/>
|
||||
</svg>
|
||||
{% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="history_list">
|
||||
|
@ -7,7 +7,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% block content %}
|
||||
{% if can_manage_registrations %}
|
||||
<a class="btn btn-block btn-secondary mb-3" href="{% url 'registration:future_user_list' %}">
|
||||
<i class="fa fa-user-plus"></i> {% trans "Registrations" %}
|
||||
<svg class="bi bi-user-plus" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M1 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M13.5 5a.5.5 0 0 1 .5.5V7h1.5a.5.5 0 0 1 0 1H14v1.5a.5.5 0 0 1-1 0V8h-1.5a.5.5 0 0 1 0-1H13V5.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>
|
||||
{% trans "Registrations" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
|
@ -222,6 +222,13 @@ $(document).ready(function () {
|
||||
})
|
||||
})
|
||||
|
||||
// Make transfer when pressing Enter on the amount section
|
||||
$('#amount, #reason, #last_name, #first_name, #bank').keypress((event) => {
|
||||
if (event.originalEvent.charCode === 13) {
|
||||
$('#btn_transfer').click()
|
||||
}
|
||||
})
|
||||
|
||||
$('#btn_transfer').click(function () {
|
||||
if (LOCK) { return }
|
||||
|
||||
@ -348,14 +355,14 @@ $('#btn_transfer').click(function () {
|
||||
destination_alias: dest.name
|
||||
}).done(function () {
|
||||
addMsg(interpolate(gettext('Transfer of %s from %s to %s failed: %s'),
|
||||
[pretty_money(source.quantity * dest.quantity * amount), source.name, + dest.name, gettext('insufficient funds')]), 'danger', 10000)
|
||||
[pretty_money(source.quantity * dest.quantity * amount), source.name, dest.name, gettext('insufficient funds')]), 'danger', 10000)
|
||||
reset()
|
||||
}).fail(function (err) {
|
||||
const errObj = JSON.parse(err.responseText)
|
||||
let error = errObj.detail ? errObj.detail : errObj.non_field_errors
|
||||
if (!error) { error = err.responseText }
|
||||
addMsg(interpolate(gettext('Transfer of %s from %s to %s failed: %s'),
|
||||
[pretty_money(source.quantity * dest.quantity * amount), source.name, + dest.name, error]), 'danger')
|
||||
[pretty_money(source.quantity * dest.quantity * amount), source.name, dest.name, error]), 'danger')
|
||||
LOCK = false
|
||||
})
|
||||
})
|
||||
|
@ -129,7 +129,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{# Mode switch #}
|
||||
<div class="card-footer border-primary">
|
||||
<a class="btn btn-sm btn-secondary float-left" href="{% url 'note:template_list' %}">
|
||||
<i class="fa fa-edit"></i> {% trans "Edit" %}
|
||||
<svg class="bi bi-edit" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
<div class="btn-group btn-group-toggle float-right" data-toggle="buttons">
|
||||
<label for="single_conso" class="btn btn-sm btn-outline-primary active">
|
||||
|
@ -10,21 +10,25 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
{# bandeau transfert/crédit/débit/activité #}
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons">
|
||||
<label for="type_transfer" class="btn btn-sm btn-outline-primary active">
|
||||
<input type="radio" name="transaction_type" id="type_transfer">
|
||||
{% trans "Transfer" %}
|
||||
</label>
|
||||
{% if "note.notespecial"|not_empty_model_list %}
|
||||
<label for="type_credit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_credit">
|
||||
{% trans "Credit" %}
|
||||
<div class="btn-group btn-block">
|
||||
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons">
|
||||
<label for="type_transfer" class="btn btn-sm btn-outline-primary active">
|
||||
<input type="radio" name="transaction_type" id="type_transfer">
|
||||
{% trans "Transfer" %}
|
||||
</label>
|
||||
<label for="type_debit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_debit">
|
||||
{% trans "Debit" %}
|
||||
</label>
|
||||
{% endif %}
|
||||
{% if "note.notespecial"|not_empty_model_list %}
|
||||
<label for="type_credit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_credit">
|
||||
{% trans "Credit" %}
|
||||
</label>
|
||||
<label for="type_debit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_debit">
|
||||
{% trans "Debit" %}
|
||||
</label>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Add shortcuts for opened activites if necessary #}
|
||||
{% for activity in activities_open %}
|
||||
<a href="{% url "activity:activity_entry" pk=activity.pk %}" class="btn btn-sm btn-outline-primary">
|
||||
{% trans "Entries" %} {{ activity.name }}
|
||||
|
@ -53,7 +53,7 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl
|
||||
# Add a shortcut for entry page for open activities
|
||||
if "activity" in settings.INSTALLED_APPS:
|
||||
from activity.models import Activity
|
||||
activities_open = Activity.objects.filter(open=True).filter(
|
||||
activities_open = Activity.objects.filter(open=True, activity_type__manage_entries=True).filter(
|
||||
PermissionBackend.filter_queryset(self.request, Activity, "view")).distinct().all()
|
||||
context["activities_open"] = [a for a in activities_open
|
||||
if PermissionBackend.check_perm(self.request,
|
||||
|
@ -111,12 +111,12 @@
|
||||
"note",
|
||||
"alias"
|
||||
],
|
||||
"query": "[\"AND\", [\"OR\", {\"note__noteuser__user__memberships__club__name\": \"Kfet\", \"note__noteuser__user__memberships__date_start__lte\": [\"today\"], \"note__noteuser__user__memberships__date_end__gte\": [\"today\"]}, {\"note__noteclub__isnull\": false}], {\"note__is_active\": true}]",
|
||||
"query": "[\"AND\", [\"OR\", {\"note__noteuser__user__memberships__club__name\": \"BDE\", \"note__noteuser__user__memberships__date_start__lte\": [\"today\"], \"note__noteuser__user__memberships__date_end__gte\": [\"today\"]}, {\"note__noteclub__isnull\": false}], {\"note__is_active\": true}]",
|
||||
"type": "view",
|
||||
"mask": 1,
|
||||
"field": "",
|
||||
"permanent": false,
|
||||
"description": "Voir les aliases des notes des clubs et des adhérents du club Kfet"
|
||||
"description": "Voir les aliases des notes des clubs et des adhérents du club BDE"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -3048,6 +3048,7 @@
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
43,
|
||||
51,
|
||||
53,
|
||||
54,
|
||||
|
@ -46,8 +46,8 @@ class SignUpForm(UserCreationForm):
|
||||
|
||||
class DeclareSogeAccountOpenedForm(forms.Form):
|
||||
soge_account = forms.BooleanField(
|
||||
label=_("I declare that I opened or I will open soon a bank account in the Société générale with the BDE \
|
||||
partnership."),
|
||||
label=_("I declare that I opened or I will open soon a bank account in the Société générale with the BDE "
|
||||
"partnership."),
|
||||
help_text=_("Warning: this engages you to open your bank account. If you finally decides to don't open your "
|
||||
"account, you will have to pay the BDE membership."),
|
||||
required=False,
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import datetime
|
||||
from datetime import date
|
||||
|
||||
from django.conf import settings
|
||||
@ -305,8 +305,16 @@ class SogeCredit(models.Model):
|
||||
|
||||
@property
|
||||
def amount(self):
|
||||
return self.credit_transaction.total if self.valid \
|
||||
else sum(transaction.total for transaction in self.transactions.all())
|
||||
if self.valid:
|
||||
return self.credit_transaction.total
|
||||
amount = sum(transaction.total for transaction in self.transactions.all())
|
||||
if 'wei' in settings.INSTALLED_APPS:
|
||||
from wei.models import WEIMembership
|
||||
if not WEIMembership.objects.filter(club__weiclub__year=datetime.date.today().year, user=self.user)\
|
||||
.exists():
|
||||
# 80 € for people that don't go to WEI
|
||||
amount += 8000
|
||||
return amount
|
||||
|
||||
def update_transactions(self):
|
||||
"""
|
||||
@ -323,13 +331,15 @@ class SogeCredit(models.Model):
|
||||
|
||||
if bde_qs.exists():
|
||||
m = bde_qs.get()
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
|
||||
if kfet_qs.exists():
|
||||
m = kfet_qs.get()
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
|
||||
if 'wei' in settings.INSTALLED_APPS:
|
||||
from wei.models import WEIClub
|
||||
@ -337,8 +347,9 @@ class SogeCredit(models.Model):
|
||||
wei_qs = Membership.objects.filter(user=self.user, club=wei, date_start__gte=wei.membership_start)
|
||||
if wei_qs.exists():
|
||||
m = wei_qs.get()
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
|
||||
if m.transaction not in self.transactions.all():
|
||||
self.transactions.add(m.transaction)
|
||||
|
||||
for tr in self.transactions.all():
|
||||
tr.valid = False
|
||||
|
@ -50,15 +50,19 @@ class WEIBusInformation:
|
||||
self.bus.information = d
|
||||
self.bus.save()
|
||||
|
||||
def free_seats(self, surveys: List["WEISurvey"] = None):
|
||||
size = self.bus.size
|
||||
already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
|
||||
def free_seats(self, surveys: List["WEISurvey"] = None, quotas=None):
|
||||
if not quotas:
|
||||
size = self.bus.size
|
||||
already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
|
||||
quotas = {self.bus: size - already_occupied}
|
||||
|
||||
quota = quotas[self.bus]
|
||||
valid_surveys = sum(1 for survey in surveys if survey.information.valid
|
||||
and survey.information.get_selected_bus() == self.bus) if surveys else 0
|
||||
return size - already_occupied - valid_surveys
|
||||
return quota - valid_surveys
|
||||
|
||||
def has_free_seats(self, surveys=None):
|
||||
return self.free_seats(surveys) > 0
|
||||
def has_free_seats(self, surveys=None, quotas=None):
|
||||
return self.free_seats(surveys, quotas) > 0
|
||||
|
||||
|
||||
class WEISurveyAlgorithm:
|
||||
@ -86,14 +90,20 @@ class WEISurveyAlgorithm:
|
||||
"""
|
||||
Queryset of all first year registrations
|
||||
"""
|
||||
return WEIRegistration.objects.filter(wei__year=cls.get_survey_class().get_year(), first_year=True)
|
||||
if not hasattr(cls, '_registrations'):
|
||||
cls._registrations = WEIRegistration.objects.filter(wei__year=cls.get_survey_class().get_year(),
|
||||
first_year=True).all()
|
||||
|
||||
return cls._registrations
|
||||
|
||||
@classmethod
|
||||
def get_buses(cls) -> QuerySet:
|
||||
"""
|
||||
Queryset of all buses of the associated wei.
|
||||
"""
|
||||
return Bus.objects.filter(wei__year=cls.get_survey_class().get_year(), size__gt=0)
|
||||
if not hasattr(cls, '_buses'):
|
||||
cls._buses = Bus.objects.filter(wei__year=cls.get_survey_class().get_year(), size__gt=0).all()
|
||||
return cls._buses
|
||||
|
||||
@classmethod
|
||||
def get_bus_information(cls, bus):
|
||||
@ -135,7 +145,10 @@ class WEISurvey:
|
||||
"""
|
||||
The WEI associated to this kind of survey.
|
||||
"""
|
||||
return WEIClub.objects.get(year=cls.get_year())
|
||||
if not hasattr(cls, '_wei'):
|
||||
cls._wei = WEIClub.objects.get(year=cls.get_year())
|
||||
|
||||
return cls._wei
|
||||
|
||||
@classmethod
|
||||
def get_survey_information_class(cls):
|
||||
@ -210,3 +223,15 @@ class WEISurvey:
|
||||
self.information.selected_bus_pk = None
|
||||
self.information.selected_bus_name = None
|
||||
self.information.valid = False
|
||||
|
||||
@classmethod
|
||||
def clear_cache(cls):
|
||||
"""
|
||||
Clear stored information.
|
||||
"""
|
||||
if hasattr(cls, '_wei'):
|
||||
del cls._wei
|
||||
if hasattr(cls.get_algorithm_class(), '_registrations'):
|
||||
del cls.get_algorithm_class()._registrations
|
||||
if hasattr(cls.get_algorithm_class(), '_buses'):
|
||||
del cls.get_algorithm_class()._buses
|
||||
|
@ -1,13 +1,17 @@
|
||||
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import time
|
||||
from functools import lru_cache
|
||||
from random import Random
|
||||
|
||||
from django import forms
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
|
||||
from ...models import WEIMembership
|
||||
|
||||
WORDS = [
|
||||
'13 organisé', '3ième mi temps', 'Années 2000', 'Apéro', 'BBQ', 'BP', 'Beauf', 'Binge drinking', 'Bon enfant',
|
||||
@ -135,20 +139,41 @@ class WEISurvey2021(WEISurvey):
|
||||
"""
|
||||
return self.information.step == 20
|
||||
|
||||
@classmethod
|
||||
@lru_cache()
|
||||
def word_mean(cls, word):
|
||||
"""
|
||||
Calculate the mid-score given by all buses.
|
||||
"""
|
||||
buses = cls.get_algorithm_class().get_buses()
|
||||
return sum([cls.get_algorithm_class().get_bus_information(bus).scores[word] for bus in buses]) / buses.count()
|
||||
|
||||
@lru_cache()
|
||||
def score(self, bus):
|
||||
if not self.is_complete():
|
||||
raise ValueError("Survey is not ended, can't calculate score")
|
||||
bus_info = self.get_algorithm_class().get_bus_information(bus)
|
||||
return sum(bus_info.scores[getattr(self.information, 'word' + str(i))] for i in range(1, 21)) / 20
|
||||
|
||||
bus_info = self.get_algorithm_class().get_bus_information(bus)
|
||||
# Score is the given score by the bus subtracted to the mid-score of the buses.
|
||||
s = sum(bus_info.scores[getattr(self.information, 'word' + str(i))]
|
||||
- self.word_mean(getattr(self.information, 'word' + str(i))) for i in range(1, 21)) / 20
|
||||
return s
|
||||
|
||||
@lru_cache()
|
||||
def scores_per_bus(self):
|
||||
return {bus: self.score(bus) for bus in self.get_algorithm_class().get_buses()}
|
||||
|
||||
@lru_cache()
|
||||
def ordered_buses(self):
|
||||
values = list(self.scores_per_bus().items())
|
||||
values.sort(key=lambda item: -item[1])
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def clear_cache(cls):
|
||||
cls.word_mean.cache_clear()
|
||||
return super().clear_cache()
|
||||
|
||||
|
||||
class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
|
||||
"""
|
||||
@ -164,19 +189,72 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
|
||||
def get_bus_information_class(cls):
|
||||
return WEIBusInformation2021
|
||||
|
||||
def run_algorithm(self):
|
||||
def run_algorithm(self, display_tqdm=False):
|
||||
"""
|
||||
Gale-Shapley algorithm implementation.
|
||||
We modify it to allow buses to have multiple "weddings".
|
||||
"""
|
||||
surveys = list(self.get_survey_class()(r) for r in self.get_registrations()) # All surveys
|
||||
surveys = [s for s in surveys if s.is_complete()]
|
||||
free_surveys = [s for s in surveys if not s.information.valid] # Remaining surveys
|
||||
surveys = [s for s in surveys if s.is_complete()] # Don't consider invalid surveys
|
||||
# Don't manage hardcoded people
|
||||
surveys = [s for s in surveys if not hasattr(s.information, 'hardcoded') or not s.information.hardcoded]
|
||||
|
||||
# Reset previous algorithm run
|
||||
for survey in surveys:
|
||||
survey.free()
|
||||
survey.save()
|
||||
|
||||
non_men = [s for s in surveys if s.registration.gender != 'male']
|
||||
men = [s for s in surveys if s.registration.gender == 'male']
|
||||
|
||||
quotas = {}
|
||||
registrations = self.get_registrations()
|
||||
non_men_total = registrations.filter(~Q(gender='male')).count()
|
||||
for bus in self.get_buses():
|
||||
free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
|
||||
# Remove hardcoded people
|
||||
free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
|
||||
registration__information_json__icontains="hardcoded").count()
|
||||
quotas[bus] = 4 + int(non_men_total / registrations.count() * free_seats)
|
||||
|
||||
tqdm_obj = None
|
||||
if display_tqdm:
|
||||
from tqdm import tqdm
|
||||
tqdm_obj = tqdm(total=len(non_men), desc="Non-hommes")
|
||||
|
||||
# Repartition for non men people first
|
||||
self.make_repartition(non_men, quotas, tqdm_obj=tqdm_obj)
|
||||
|
||||
quotas = {}
|
||||
for bus in self.get_buses():
|
||||
free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
|
||||
free_seats -= sum(1 for s in non_men if s.information.selected_bus_pk == bus.pk)
|
||||
# Remove hardcoded people
|
||||
free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
|
||||
registration__information_json__icontains="hardcoded").count()
|
||||
quotas[bus] = free_seats
|
||||
|
||||
if display_tqdm:
|
||||
tqdm_obj.close()
|
||||
|
||||
from tqdm import tqdm
|
||||
tqdm_obj = tqdm(total=len(men), desc="Hommes")
|
||||
|
||||
self.make_repartition(men, quotas, tqdm_obj=tqdm_obj)
|
||||
|
||||
if display_tqdm:
|
||||
tqdm_obj.close()
|
||||
|
||||
# Clear cache information after running algorithm
|
||||
WEISurvey2021.clear_cache()
|
||||
|
||||
def make_repartition(self, surveys, quotas=None, tqdm_obj=None):
|
||||
free_surveys = surveys.copy() # Remaining surveys
|
||||
while free_surveys: # Some students are not affected
|
||||
survey = free_surveys[0]
|
||||
buses = survey.ordered_buses() # Preferences of the student
|
||||
for bus, _ignored in buses:
|
||||
if self.get_bus_information(bus).has_free_seats(surveys):
|
||||
for bus, current_score in buses:
|
||||
if self.get_bus_information(bus).has_free_seats(surveys, quotas):
|
||||
# Selected bus has free places. Put student in the bus
|
||||
survey.select_bus(bus)
|
||||
survey.save()
|
||||
@ -184,7 +262,6 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
|
||||
break
|
||||
else:
|
||||
# Current bus has not enough places. Remove the least preferred student from the bus if existing
|
||||
current_score = survey.score(bus)
|
||||
least_preferred_survey = None
|
||||
least_score = -1
|
||||
# Find the least student in the bus that has a lower score than the current student
|
||||
@ -206,6 +283,11 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
|
||||
free_surveys.append(least_preferred_survey)
|
||||
survey.select_bus(bus)
|
||||
survey.save()
|
||||
free_surveys.remove(survey)
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"User {survey.registration.user} has no free seat")
|
||||
|
||||
if tqdm_obj is not None:
|
||||
tqdm_obj.n = len(surveys) - len(free_surveys)
|
||||
tqdm_obj.refresh()
|
||||
|
@ -24,7 +24,15 @@ class Command(BaseCommand):
|
||||
sid = transaction.savepoint()
|
||||
|
||||
algorithm = CurrentSurvey.get_algorithm_class()()
|
||||
algorithm.run_algorithm()
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
del tqdm
|
||||
display_tqdm = True
|
||||
except ImportError:
|
||||
display_tqdm = False
|
||||
|
||||
algorithm.run_algorithm(display_tqdm=display_tqdm)
|
||||
|
||||
output = options['output']
|
||||
registrations = algorithm.get_registrations()
|
||||
@ -34,8 +42,13 @@ class Command(BaseCommand):
|
||||
for bus, members in per_bus.items():
|
||||
output.write(bus.name + "\n")
|
||||
output.write("=" * len(bus.name) + "\n")
|
||||
_order = -1
|
||||
for r in members:
|
||||
output.write(r.user.username + "\n")
|
||||
survey = CurrentSurvey(r)
|
||||
for _order, (b, _score) in enumerate(survey.ordered_buses()):
|
||||
if b == bus:
|
||||
break
|
||||
output.write(f"{r.user.username} ({_order + 1})\n")
|
||||
output.write("\n")
|
||||
|
||||
if not options['doit']:
|
||||
|
@ -29,7 +29,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="font-weight-bold">
|
||||
<i class="fa fa-bus"></i> {% trans "Teams" %}
|
||||
<svg class="bi bi-signpost" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7.293.707A1 1 0 0 0 7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414A1 1 0 0 0 7.293.707z"/>
|
||||
</svg>
|
||||
{% trans "Teams" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table teams %}
|
||||
@ -42,7 +45,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="font-weight-bold">
|
||||
<i class="fa fa-bus"></i> {% trans "Members" %}
|
||||
<svg class="bi bi-signpost" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7.293.707A1 1 0 0 0 7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414A1 1 0 0 0 7.293.707z"/>
|
||||
</svg>
|
||||
{% trans "Members" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table memberships %}
|
||||
@ -51,7 +57,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<hr>
|
||||
|
||||
<a href="{% url 'wei:wei_memberships_bus_pdf' wei_pk=club.pk bus_pk=object.pk %}" data-turbolinks="false">
|
||||
<button class="btn btn-block btn-danger"><i class="fa fa-file-pdf-o"></i> {% trans "View as PDF" %}</button>
|
||||
<button class="btn btn-block btn-danger">
|
||||
<svg class="bi bi-file-pdf" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M5.523 12.424c.14-.082.293-.162.459-.238a7.878 7.878 0 0 1-.45.606c-.28.337-.498.516-.635.572a.266.266 0 0 1-.035.012.282.282 0 0 1-.026-.044c-.056-.11-.054-.216.04-.36.106-.165.319-.354.647-.548zm2.455-1.647c-.119.025-.237.05-.356.078a21.148 21.148 0 0 0 .5-1.05 12.045 12.045 0 0 0 .51.858c-.217.032-.436.07-.654.114zm2.525.939a3.881 3.881 0 0 1-.435-.41c.228.005.434.022.612.054.317.057.466.147.518.209a.095.095 0 0 1 .026.064.436.436 0 0 1-.06.2.307.307 0 0 1-.094.124.107.107 0 0 1-.069.015c-.09-.003-.258-.066-.498-.256zM8.278 6.97c-.04.244-.108.524-.2.829a4.86 4.86 0 0 1-.089-.346c-.076-.353-.087-.63-.046-.822.038-.177.11-.248.196-.283a.517.517 0 0 1 .145-.04c.013.03.028.092.032.198.005.122-.007.277-.038.465z"/>
|
||||
<path fill-rule="evenodd" d="M4 0h5.293A1 1 0 0 1 10 .293L13.707 4a1 1 0 0 1 .293.707V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm5.5 1.5v2a1 1 0 0 0 1 1h2l-3-3zM4.165 13.668c.09.18.23.343.438.419.207.075.412.04.58-.03.318-.13.635-.436.926-.786.333-.401.683-.927 1.021-1.51a11.651 11.651 0 0 1 1.997-.406c.3.383.61.713.91.95.28.22.603.403.934.417a.856.856 0 0 0 .51-.138c.155-.101.27-.247.354-.416.09-.181.145-.37.138-.563a.844.844 0 0 0-.2-.518c-.226-.27-.596-.4-.96-.465a5.76 5.76 0 0 0-1.335-.05 10.954 10.954 0 0 1-.98-1.686c.25-.66.437-1.284.52-1.794.036-.218.055-.426.048-.614a1.238 1.238 0 0 0-.127-.538.7.7 0 0 0-.477-.365c-.202-.043-.41 0-.601.077-.377.15-.576.47-.651.823-.073.34-.04.736.046 1.136.088.406.238.848.43 1.295a19.697 19.697 0 0 1-1.062 2.227 7.662 7.662 0 0 0-1.482.645c-.37.22-.699.48-.897.787-.21.326-.275.714-.08 1.103z"/>
|
||||
</svg>
|
||||
{% trans "View as PDF" %}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -47,7 +47,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="font-weight-bold">
|
||||
<i class="fa fa-bus"></i> {% trans "Teams" %}
|
||||
<svg class="bi bi-signpost" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7.293.707A1 1 0 0 0 7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414A1 1 0 0 0 7.293.707z"/>
|
||||
</svg>
|
||||
{% trans "Teams" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table memberships %}
|
||||
@ -57,7 +60,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
<a href="{% url 'wei:wei_memberships_team_pdf' wei_pk=club.pk bus_pk=object.bus.pk team_pk=object.pk %}"
|
||||
data-turbolinks="false">
|
||||
<button class="btn btn-block btn-danger"><i class="fa fa-file-pdf-o"></i> {% trans "View as PDF" %}</button>
|
||||
<button class="btn btn-block btn-danger">
|
||||
<svg class="bi bi-file-pdf" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M5.523 12.424c.14-.082.293-.162.459-.238a7.878 7.878 0 0 1-.45.606c-.28.337-.498.516-.635.572a.266.266 0 0 1-.035.012.282.282 0 0 1-.026-.044c-.056-.11-.054-.216.04-.36.106-.165.319-.354.647-.548zm2.455-1.647c-.119.025-.237.05-.356.078a21.148 21.148 0 0 0 .5-1.05 12.045 12.045 0 0 0 .51.858c-.217.032-.436.07-.654.114zm2.525.939a3.881 3.881 0 0 1-.435-.41c.228.005.434.022.612.054.317.057.466.147.518.209a.095.095 0 0 1 .026.064.436.436 0 0 1-.06.2.307.307 0 0 1-.094.124.107.107 0 0 1-.069.015c-.09-.003-.258-.066-.498-.256zM8.278 6.97c-.04.244-.108.524-.2.829a4.86 4.86 0 0 1-.089-.346c-.076-.353-.087-.63-.046-.822.038-.177.11-.248.196-.283a.517.517 0 0 1 .145-.04c.013.03.028.092.032.198.005.122-.007.277-.038.465z"/>
|
||||
<path fill-rule="evenodd" d="M4 0h5.293A1 1 0 0 1 10 .293L13.707 4a1 1 0 0 1 .293.707V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm5.5 1.5v2a1 1 0 0 0 1 1h2l-3-3zM4.165 13.668c.09.18.23.343.438.419.207.075.412.04.58-.03.318-.13.635-.436.926-.786.333-.401.683-.927 1.021-1.51a11.651 11.651 0 0 1 1.997-.406c.3.383.61.713.91.95.28.22.603.403.934.417a.856.856 0 0 0 .51-.138c.155-.101.27-.247.354-.416.09-.181.145-.37.138-.563a.844.844 0 0 0-.2-.518c-.226-.27-.596-.4-.96-.465a5.76 5.76 0 0 0-1.335-.05 10.954 10.954 0 0 1-.98-1.686c.25-.66.437-1.284.52-1.794.036-.218.055-.426.048-.614a1.238 1.238 0 0 0-.127-.538.7.7 0 0 0-.477-.365c-.202-.043-.41 0-.601.077-.377.15-.576.47-.651.823-.073.34-.04.736.046 1.136.088.406.238.848.43 1.295a19.697 19.697 0 0 1-1.062 2.227 7.662 7.662 0 0 0-1.482.645c-.37.22-.699.48-.897.787-.21.326-.275.714-.08 1.103z"/>
|
||||
</svg>
|
||||
{% trans "View as PDF" %}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -48,7 +48,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card bg-white mb-3">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<span class="font-weight-bold">
|
||||
<i class="fa fa-bus"></i> {% trans "Buses" %}
|
||||
<svg class="bi bi-signpost" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7.293.707A1 1 0 0 0 7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414A1 1 0 0 0 7.293.707z"/>
|
||||
</svg>
|
||||
{% trans "Buses" %}
|
||||
</span>
|
||||
</div>
|
||||
{% render_table buses %}
|
||||
@ -60,7 +63,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="stretched-link font-weight-bold text-decoration-none"
|
||||
href="{% url "wei:wei_memberships" pk=club.pk %}">
|
||||
<i class="fa fa-users"></i> {% trans "Members of the WEI" %}
|
||||
<svg class="bi bi-users" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1H7zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M5.216 14A2.238 2.238 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.325 6.325 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1h4.216z"/>
|
||||
<path d="M4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>
|
||||
</svg>
|
||||
{% trans "Members of the WEI" %}
|
||||
</a>
|
||||
</div>
|
||||
{% render_table member_list %}
|
||||
@ -72,7 +80,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="stretched-link font-weight-bold text-decoration-none" {% if "note.view_note"|has_perm:club.note %}
|
||||
href="{% url 'note:transactions' pk=club.note.pk %}" {% endif %}>
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
<svg class="bi bi-euro" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M4 9.42h1.063C5.4 12.323 7.317 14 10.34 14c.622 0 1.167-.068 1.659-.185v-1.3c-.484.119-1.045.17-1.659.17-2.1 0-3.455-1.198-3.775-3.264h4.017v-.928H6.497v-.936c0-.11 0-.219.008-.329h4.078v-.927H6.618c.388-1.898 1.719-2.985 3.723-2.985.614 0 1.175.05 1.659.177V2.194A6.617 6.617 0 0 0 10.341 2c-2.928 0-4.82 1.569-5.244 4.3H4v.928h1.01v1.265H4v.928z"/>
|
||||
</svg>
|
||||
{% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="history_list">
|
||||
@ -86,7 +97,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="stretched-link font-weight-bold text-decoration-none"
|
||||
href="{% url 'wei:wei_registrations' pk=club.pk %}">
|
||||
<i class="fa fa-user-plus"></i> {% trans "Unvalidated registrations" %}
|
||||
<svg class="bi bi-user-plus" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M1 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M13.5 5a.5.5 0 0 1 .5.5V7h1.5a.5.5 0 0 1 0 1H14v1.5a.5.5 0 0 1-1 0V8h-1.5a.5.5 0 0 1 0-1H13V5.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>
|
||||
{% trans "Unvalidated registrations" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="history_list">
|
||||
|
@ -28,7 +28,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</a>
|
||||
<hr>
|
||||
<a href="{% url 'wei:wei_memberships_pdf' wei_pk=club.pk %}" data-turbolinks="false">
|
||||
<button class="btn btn-block btn-danger"><i class="fa fa-file-pdf-o"></i> {% trans "View as PDF" %}</button>
|
||||
<button class="btn btn-block btn-danger">
|
||||
<svg class="bi bi-file-pdf" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M5.523 12.424c.14-.082.293-.162.459-.238a7.878 7.878 0 0 1-.45.606c-.28.337-.498.516-.635.572a.266.266 0 0 1-.035.012.282.282 0 0 1-.026-.044c-.056-.11-.054-.216.04-.36.106-.165.319-.354.647-.548zm2.455-1.647c-.119.025-.237.05-.356.078a21.148 21.148 0 0 0 .5-1.05 12.045 12.045 0 0 0 .51.858c-.217.032-.436.07-.654.114zm2.525.939a3.881 3.881 0 0 1-.435-.41c.228.005.434.022.612.054.317.057.466.147.518.209a.095.095 0 0 1 .026.064.436.436 0 0 1-.06.2.307.307 0 0 1-.094.124.107.107 0 0 1-.069.015c-.09-.003-.258-.066-.498-.256zM8.278 6.97c-.04.244-.108.524-.2.829a4.86 4.86 0 0 1-.089-.346c-.076-.353-.087-.63-.046-.822.038-.177.11-.248.196-.283a.517.517 0 0 1 .145-.04c.013.03.028.092.032.198.005.122-.007.277-.038.465z"/>
|
||||
<path fill-rule="evenodd" d="M4 0h5.293A1 1 0 0 1 10 .293L13.707 4a1 1 0 0 1 .293.707V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm5.5 1.5v2a1 1 0 0 0 1 1h2l-3-3zM4.165 13.668c.09.18.23.343.438.419.207.075.412.04.58-.03.318-.13.635-.436.926-.786.333-.401.683-.927 1.021-1.51a11.651 11.651 0 0 1 1.997-.406c.3.383.61.713.91.95.28.22.603.403.934.417a.856.856 0 0 0 .51-.138c.155-.101.27-.247.354-.416.09-.181.145-.37.138-.563a.844.844 0 0 0-.2-.518c-.226-.27-.596-.4-.96-.465a5.76 5.76 0 0 0-1.335-.05 10.954 10.954 0 0 1-.98-1.686c.25-.66.437-1.284.52-1.794.036-.218.055-.426.048-.614a1.238 1.238 0 0 0-.127-.538.7.7 0 0 0-.477-.365c-.202-.043-.41 0-.601.077-.377.15-.576.47-.651.823-.073.34-.04.736.046 1.136.088.406.238.848.43 1.295a19.697 19.697 0 0 1-1.062 2.227 7.662 7.662 0 0 0-1.482.645c-.37.22-.699.48-.897.787-.21.326-.275.714-.08 1.103z"/>
|
||||
</svg>
|
||||
{% trans "View as PDF" %}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,7 +23,7 @@ Sur un Ubuntu/Debian :
|
||||
$ sudo apt update
|
||||
$ sudo apt install --no-install-recommends -y \
|
||||
python3-setuptools python3-venv python3-dev \
|
||||
texlive-xetex gettext libjs-bootstrap4 fonts-font-awesome git
|
||||
texlive-xetex gettext libjs-bootstrap4 git
|
||||
|
||||
Pour Arch Linux :
|
||||
|
||||
|
@ -62,7 +62,7 @@ plus propre. On peut donc installer tout ce dont on a besoin, depuis buster-back
|
||||
$ sudo apt update
|
||||
$ sudo apt install -t buster-backports --no-install-recommends \
|
||||
gettext git ipython3 \ # Dépendances basiques
|
||||
fonts-font-awesome libjs-bootstrap4 \ # Pour l'affichage web
|
||||
libjs-bootstrap4 \ # Pour l'affichage web
|
||||
python3-bs4 python3-django python3-django-crispy-forms python3-django-extensions \
|
||||
python3-django-filters python3-django-oauth-toolkit python3-django-polymorphic \
|
||||
python3-djangorestframework python3-memcache python3-phonenumbers \
|
||||
|
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-09-13 23:26+0200\n"
|
||||
"POT-Creation-Date: 2021-09-28 17:02+0200\n"
|
||||
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
|
||||
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
|
||||
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
|
||||
@ -23,28 +23,32 @@ msgstr ""
|
||||
msgid "activity"
|
||||
msgstr "activité"
|
||||
|
||||
#: apps/activity/forms.py:35 apps/activity/models.py:132
|
||||
#: apps/activity/forms.py:34
|
||||
msgid "The note of this club is inactive."
|
||||
msgstr "La note du club est inactive."
|
||||
|
||||
#: apps/activity/forms.py:41 apps/activity/models.py:132
|
||||
msgid "The end date must be after the start date."
|
||||
msgstr "La date de fin doit être après celle de début."
|
||||
|
||||
#: apps/activity/forms.py:76 apps/activity/models.py:270
|
||||
#: apps/activity/forms.py:82 apps/activity/models.py:270
|
||||
msgid "You can't invite someone once the activity is started."
|
||||
msgstr ""
|
||||
"Vous ne pouvez pas inviter quelqu'un une fois que l'activité a démarré."
|
||||
|
||||
#: apps/activity/forms.py:79 apps/activity/models.py:273
|
||||
#: apps/activity/forms.py:85 apps/activity/models.py:273
|
||||
msgid "This activity is not validated yet."
|
||||
msgstr "Cette activité n'est pas encore validée."
|
||||
|
||||
#: apps/activity/forms.py:89 apps/activity/models.py:281
|
||||
#: apps/activity/forms.py:95 apps/activity/models.py:281
|
||||
msgid "This person has been already invited 5 times this year."
|
||||
msgstr "Cette personne a déjà été invitée 5 fois cette année."
|
||||
|
||||
#: apps/activity/forms.py:93 apps/activity/models.py:285
|
||||
#: apps/activity/forms.py:99 apps/activity/models.py:285
|
||||
msgid "This person is already invited."
|
||||
msgstr "Cette personne est déjà invitée."
|
||||
|
||||
#: apps/activity/forms.py:97 apps/activity/models.py:289
|
||||
#: apps/activity/forms.py:103 apps/activity/models.py:289
|
||||
msgid "You can't invite more than 3 people to this activity."
|
||||
msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité."
|
||||
|
||||
@ -195,7 +199,7 @@ msgstr "Entrée de la note {note} pour l'activité « {activity} »"
|
||||
msgid "Already entered on "
|
||||
msgstr "Déjà rentré le "
|
||||
|
||||
#: apps/activity/models.py:202 apps/activity/tables.py:54
|
||||
#: apps/activity/models.py:202 apps/activity/tables.py:56
|
||||
msgid "{:%Y-%m-%d %H:%M:%S}"
|
||||
msgstr "{:%d/%m/%Y %H:%M:%S}"
|
||||
|
||||
@ -234,48 +238,48 @@ msgstr "invités"
|
||||
msgid "Invitation"
|
||||
msgstr "Invitation"
|
||||
|
||||
#: apps/activity/tables.py:25
|
||||
#: apps/activity/tables.py:27
|
||||
msgid "The activity is currently open."
|
||||
msgstr "Cette activité est actuellement ouverte."
|
||||
|
||||
#: apps/activity/tables.py:26
|
||||
#: apps/activity/tables.py:28
|
||||
msgid "The validation of the activity is pending."
|
||||
msgstr "La validation de cette activité est en attente."
|
||||
|
||||
#: apps/activity/tables.py:41 apps/treasury/tables.py:107
|
||||
#: apps/activity/tables.py:43 apps/treasury/tables.py:107
|
||||
msgid "Remove"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: apps/activity/tables.py:54
|
||||
#: apps/activity/tables.py:56
|
||||
msgid "Entered on "
|
||||
msgstr "Entré le "
|
||||
|
||||
#: apps/activity/tables.py:56
|
||||
#: apps/activity/tables.py:58
|
||||
msgid "remove"
|
||||
msgstr "supprimer"
|
||||
|
||||
#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:199
|
||||
#: apps/activity/tables.py:82 apps/note/forms.py:68 apps/treasury/models.py:199
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: apps/activity/tables.py:82 apps/member/forms.py:186
|
||||
#: apps/registration/forms.py:90 apps/treasury/forms.py:131
|
||||
#: apps/activity/tables.py:84 apps/member/forms.py:186
|
||||
#: apps/registration/forms.py:91 apps/treasury/forms.py:131
|
||||
#: apps/wei/forms/registration.py:104
|
||||
msgid "Last name"
|
||||
msgstr "Nom de famille"
|
||||
|
||||
#: apps/activity/tables.py:84 apps/member/forms.py:191
|
||||
#: apps/note/templates/note/transaction_form.html:134
|
||||
#: apps/registration/forms.py:95 apps/treasury/forms.py:133
|
||||
#: apps/activity/tables.py:86 apps/member/forms.py:191
|
||||
#: apps/note/templates/note/transaction_form.html:138
|
||||
#: apps/registration/forms.py:96 apps/treasury/forms.py:133
|
||||
#: apps/wei/forms/registration.py:109
|
||||
msgid "First name"
|
||||
msgstr "Prénom"
|
||||
|
||||
#: apps/activity/tables.py:86 apps/note/models/notes.py:86
|
||||
#: apps/activity/tables.py:88 apps/note/models/notes.py:86
|
||||
msgid "Note"
|
||||
msgstr "Note"
|
||||
|
||||
#: apps/activity/tables.py:88 apps/member/tables.py:49
|
||||
#: apps/activity/tables.py:90 apps/member/tables.py:49
|
||||
msgid "Balance"
|
||||
msgstr "Solde du compte"
|
||||
|
||||
@ -289,26 +293,26 @@ msgstr "Invité supprimé"
|
||||
|
||||
#: apps/activity/templates/activity/activity_entry.html:14
|
||||
#: apps/note/models/transactions.py:257
|
||||
#: apps/note/templates/note/transaction_form.html:16
|
||||
#: apps/note/templates/note/transaction_form.html:148
|
||||
#: apps/note/templates/note/transaction_form.html:17
|
||||
#: apps/note/templates/note/transaction_form.html:152
|
||||
#: note_kfet/templates/base.html:73
|
||||
msgid "Transfer"
|
||||
msgstr "Virement"
|
||||
|
||||
#: apps/activity/templates/activity/activity_entry.html:18
|
||||
#: apps/note/models/transactions.py:317
|
||||
#: apps/note/templates/note/transaction_form.html:21
|
||||
#: apps/note/templates/note/transaction_form.html:22
|
||||
msgid "Credit"
|
||||
msgstr "Crédit"
|
||||
|
||||
#: apps/activity/templates/activity/activity_entry.html:21
|
||||
#: apps/note/models/transactions.py:317
|
||||
#: apps/note/templates/note/transaction_form.html:25
|
||||
#: apps/note/templates/note/transaction_form.html:26
|
||||
msgid "Debit"
|
||||
msgstr "Débit"
|
||||
|
||||
#: apps/activity/templates/activity/activity_entry.html:27
|
||||
#: apps/note/templates/note/transaction_form.html:30
|
||||
#: apps/note/templates/note/transaction_form.html:34
|
||||
msgid "Entries"
|
||||
msgstr "Entrées"
|
||||
|
||||
@ -548,20 +552,20 @@ msgstr "Cette image ne peut pas être chargée."
|
||||
msgid "An alias with a similar name already exists."
|
||||
msgstr "Un alias avec un nom similaire existe déjà."
|
||||
|
||||
#: apps/member/forms.py:165 apps/registration/forms.py:70
|
||||
#: apps/member/forms.py:165 apps/registration/forms.py:71
|
||||
msgid "Inscription paid by Société Générale"
|
||||
msgstr "Inscription payée par la Société générale"
|
||||
|
||||
#: apps/member/forms.py:167 apps/registration/forms.py:72
|
||||
#: apps/member/forms.py:167 apps/registration/forms.py:73
|
||||
msgid "Check this case if the Société Générale paid the inscription."
|
||||
msgstr "Cochez cette case si la Société Générale a payé l'inscription."
|
||||
|
||||
#: apps/member/forms.py:172 apps/registration/forms.py:77
|
||||
#: apps/member/forms.py:172 apps/registration/forms.py:78
|
||||
#: apps/wei/forms/registration.py:91
|
||||
msgid "Credit type"
|
||||
msgstr "Type de rechargement"
|
||||
|
||||
#: apps/member/forms.py:173 apps/registration/forms.py:78
|
||||
#: apps/member/forms.py:173 apps/registration/forms.py:79
|
||||
#: apps/wei/forms/registration.py:92
|
||||
msgid "No credit"
|
||||
msgstr "Pas de rechargement"
|
||||
@ -570,13 +574,13 @@ msgstr "Pas de rechargement"
|
||||
msgid "You can credit the note of the user."
|
||||
msgstr "Vous pouvez créditer la note de l'utilisateur avant l'adhésion."
|
||||
|
||||
#: apps/member/forms.py:179 apps/registration/forms.py:83
|
||||
#: apps/member/forms.py:179 apps/registration/forms.py:84
|
||||
#: apps/wei/forms/registration.py:97
|
||||
msgid "Credit amount"
|
||||
msgstr "Montant à créditer"
|
||||
|
||||
#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:140
|
||||
#: apps/registration/forms.py:100 apps/treasury/forms.py:135
|
||||
#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:144
|
||||
#: apps/registration/forms.py:101 apps/treasury/forms.py:135
|
||||
#: apps/wei/forms/registration.py:114
|
||||
msgid "Bank"
|
||||
msgstr "Banque"
|
||||
@ -1192,7 +1196,7 @@ msgstr "Modifier le club"
|
||||
msgid "Add new member to the club"
|
||||
msgstr "Ajouter un nouveau membre au club"
|
||||
|
||||
#: apps/member/views.py:642 apps/wei/views.py:956
|
||||
#: apps/member/views.py:642 apps/wei/views.py:973
|
||||
msgid ""
|
||||
"This user don't have enough money to join this club, and can't have a "
|
||||
"negative balance."
|
||||
@ -1247,7 +1251,7 @@ msgstr "Source"
|
||||
msgid "Destination"
|
||||
msgstr "Destination"
|
||||
|
||||
#: apps/note/forms.py:74 apps/note/templates/note/transaction_form.html:119
|
||||
#: apps/note/forms.py:74 apps/note/templates/note/transaction_form.html:123
|
||||
msgid "Reason"
|
||||
msgstr "Raison"
|
||||
|
||||
@ -1498,8 +1502,8 @@ msgstr ""
|
||||
"mode de paiement et un utilisateur ou un club"
|
||||
|
||||
#: apps/note/models/transactions.py:355 apps/note/models/transactions.py:358
|
||||
#: apps/note/models/transactions.py:361 apps/wei/views.py:961
|
||||
#: apps/wei/views.py:965
|
||||
#: apps/note/models/transactions.py:361 apps/wei/views.py:978
|
||||
#: apps/wei/views.py:982
|
||||
msgid "This field is required."
|
||||
msgstr "Ce champ est requis."
|
||||
|
||||
@ -1553,7 +1557,7 @@ msgid "Edit"
|
||||
msgstr "Éditer"
|
||||
|
||||
#: apps/note/templates/note/conso_form.html:22
|
||||
#: apps/note/templates/note/transaction_form.html:44
|
||||
#: apps/note/templates/note/transaction_form.html:48
|
||||
msgid "Please select a note"
|
||||
msgstr "Sélectionnez une note"
|
||||
|
||||
@ -1562,8 +1566,8 @@ msgid "Consum"
|
||||
msgstr "Consommer"
|
||||
|
||||
#: apps/note/templates/note/conso_form.html:43
|
||||
#: apps/note/templates/note/transaction_form.html:65
|
||||
#: apps/note/templates/note/transaction_form.html:92
|
||||
#: apps/note/templates/note/transaction_form.html:69
|
||||
#: apps/note/templates/note/transaction_form.html:96
|
||||
msgid "Name or alias..."
|
||||
msgstr "Pseudo ou alias ..."
|
||||
|
||||
@ -1588,7 +1592,7 @@ msgid "Double consumptions"
|
||||
msgstr "Consommations doubles"
|
||||
|
||||
#: apps/note/templates/note/conso_form.html:154
|
||||
#: apps/note/templates/note/transaction_form.html:159
|
||||
#: apps/note/templates/note/transaction_form.html:163
|
||||
msgid "Recent transactions history"
|
||||
msgstr "Historique des transactions récentes"
|
||||
|
||||
@ -1603,45 +1607,45 @@ msgstr "Historique des transactions récentes"
|
||||
msgid "Mail generated by the Note Kfet on the"
|
||||
msgstr "Mail généré par la Note Kfet le"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:54
|
||||
#: apps/note/templates/note/transaction_form.html:174
|
||||
#: apps/note/templates/note/transaction_form.html:58
|
||||
#: apps/note/templates/note/transaction_form.html:178
|
||||
msgid "Select emitters"
|
||||
msgstr "Sélection des émetteurs"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:69
|
||||
#: apps/note/templates/note/transaction_form.html:73
|
||||
msgid "I am the emitter"
|
||||
msgstr "Je suis l'émetteur"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:81
|
||||
#: apps/note/templates/note/transaction_form.html:176
|
||||
#: apps/note/templates/note/transaction_form.html:85
|
||||
#: apps/note/templates/note/transaction_form.html:180
|
||||
msgid "Select receivers"
|
||||
msgstr "Sélection des destinataires"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:104
|
||||
#: apps/note/templates/note/transaction_form.html:108
|
||||
msgid "Action"
|
||||
msgstr "Action"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:112
|
||||
#: apps/note/templates/note/transaction_form.html:116
|
||||
#: apps/treasury/forms.py:137 apps/treasury/tables.py:67
|
||||
#: apps/treasury/tables.py:132
|
||||
#: apps/treasury/templates/treasury/remittance_form.html:23
|
||||
msgid "Amount"
|
||||
msgstr "Montant"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:128
|
||||
#: apps/note/templates/note/transaction_form.html:132
|
||||
#: apps/treasury/models.py:54
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:173
|
||||
#: apps/note/templates/note/transaction_form.html:177
|
||||
msgid "Select emitter"
|
||||
msgstr "Sélection de l'émetteur"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:175
|
||||
#: apps/note/templates/note/transaction_form.html:179
|
||||
msgid "Select receiver"
|
||||
msgstr "Sélection du destinataire"
|
||||
|
||||
#: apps/note/templates/note/transaction_form.html:177
|
||||
#: apps/note/templates/note/transaction_form.html:181
|
||||
msgid "Transfer type"
|
||||
msgstr "Type de transfert"
|
||||
|
||||
@ -1913,13 +1917,13 @@ msgstr "Cet email est déjà pris."
|
||||
|
||||
#: apps/registration/forms.py:49
|
||||
msgid ""
|
||||
"I declare that I opened or I will open soon a bank account in the Société générale with the BDE "
|
||||
"partnership."
|
||||
"I declare that I opened or I will open soon a bank account in the Société "
|
||||
"générale with the BDE partnership."
|
||||
msgstr ""
|
||||
"Je déclare avoir ouvert ou ouvrir prochainement un compte à la société générale avec le partenariat "
|
||||
"du BDE."
|
||||
"Je déclare avoir ouvert ou ouvrir prochainement un compte à la société "
|
||||
"générale avec le partenariat du BDE."
|
||||
|
||||
#: apps/registration/forms.py:50
|
||||
#: apps/registration/forms.py:51
|
||||
msgid ""
|
||||
"Warning: this engages you to open your bank account. If you finally decides "
|
||||
"to don't open your account, you will have to pay the BDE membership."
|
||||
@ -1927,11 +1931,11 @@ msgstr ""
|
||||
"Attention : cocher cette case vous engage à ouvrir votre compte. Si vous "
|
||||
"décidez de ne pas le faire, vous devrez payer l'adhésion au BDE."
|
||||
|
||||
#: apps/registration/forms.py:58
|
||||
#: apps/registration/forms.py:59
|
||||
msgid "Register to the WEI"
|
||||
msgstr "S'inscrire au WEI"
|
||||
|
||||
#: apps/registration/forms.py:60
|
||||
#: apps/registration/forms.py:61
|
||||
msgid ""
|
||||
"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."
|
||||
@ -1940,11 +1944,11 @@ msgstr ""
|
||||
"pourrez toujours vous inscrire plus tard, après avoir validé votre compte à "
|
||||
"la Kfet."
|
||||
|
||||
#: apps/registration/forms.py:105
|
||||
#: apps/registration/forms.py:106
|
||||
msgid "Join BDE Club"
|
||||
msgstr "Adhérer au club BDE"
|
||||
|
||||
#: apps/registration/forms.py:112
|
||||
#: apps/registration/forms.py:113
|
||||
msgid "Join Kfet Club"
|
||||
msgstr "Adhérer au club Kfet"
|
||||
|
||||
@ -2244,7 +2248,7 @@ msgstr "proxys de transactions spéciales"
|
||||
msgid "credit transaction"
|
||||
msgstr "transaction de crédit"
|
||||
|
||||
#: apps/treasury/models.py:419
|
||||
#: apps/treasury/models.py:430
|
||||
msgid ""
|
||||
"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."
|
||||
@ -2252,16 +2256,16 @@ msgstr ""
|
||||
"Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa "
|
||||
"note. Merci de lui demander de recharger sa note avant d'invalider ce crédit."
|
||||
|
||||
#: apps/treasury/models.py:439
|
||||
#: apps/treasury/models.py:451
|
||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
|
||||
msgid "Credit from the Société générale"
|
||||
msgstr "Crédit de la Société générale"
|
||||
|
||||
#: apps/treasury/models.py:440
|
||||
#: apps/treasury/models.py:452
|
||||
msgid "Credits from the Société générale"
|
||||
msgstr "Crédits de la Société générale"
|
||||
|
||||
#: apps/treasury/models.py:443
|
||||
#: apps/treasury/models.py:455
|
||||
#, python-brace-format
|
||||
msgid "Soge credit for {user}"
|
||||
msgstr "Crédit de la société générale pour l'utilisateur {user}"
|
||||
@ -2559,7 +2563,7 @@ msgstr "Sélectionnez les rôles qui vous intéressent."
|
||||
msgid "This team doesn't belong to the given bus."
|
||||
msgstr "Cette équipe n'appartient pas à ce bus."
|
||||
|
||||
#: apps/wei/forms/surveys/wei2021.py:31
|
||||
#: apps/wei/forms/surveys/wei2021.py:35
|
||||
msgid "Choose a word:"
|
||||
msgstr "Choisissez un mot :"
|
||||
|
||||
@ -2804,11 +2808,11 @@ msgstr "Prix du WEI (étudiants)"
|
||||
msgid "WEI list"
|
||||
msgstr "Liste des WEI"
|
||||
|
||||
#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:523
|
||||
#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:528
|
||||
msgid "Register 1A"
|
||||
msgstr "Inscrire un 1A"
|
||||
|
||||
#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:603
|
||||
#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:614
|
||||
msgid "Register 2A+"
|
||||
msgstr "Inscrire un 2A+"
|
||||
|
||||
@ -2837,8 +2841,8 @@ msgstr "Télécharger au format PDF"
|
||||
|
||||
#: apps/wei/templates/wei/survey.html:11
|
||||
#: apps/wei/templates/wei/survey_closed.html:11
|
||||
#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:1011
|
||||
#: apps/wei/views.py:1066 apps/wei/views.py:1076
|
||||
#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:1028
|
||||
#: apps/wei/views.py:1083 apps/wei/views.py:1093
|
||||
msgid "Survey WEI"
|
||||
msgstr "Questionnaire WEI"
|
||||
|
||||
@ -2883,7 +2887,7 @@ msgstr "Inscriptions non validées"
|
||||
msgid "Attribute buses"
|
||||
msgstr "Répartition dans les bus"
|
||||
|
||||
#: apps/wei/templates/wei/weiclub_list.html:14 apps/wei/views.py:78
|
||||
#: apps/wei/templates/wei/weiclub_list.html:14 apps/wei/views.py:79
|
||||
msgid "Create WEI"
|
||||
msgstr "Créer un WEI"
|
||||
|
||||
@ -3020,67 +3024,67 @@ msgstr "Il n'y a pas de pré-inscription en attente avec cette entrée."
|
||||
msgid "View validated memberships..."
|
||||
msgstr "Voir les adhésions validées ..."
|
||||
|
||||
#: apps/wei/views.py:57
|
||||
#: apps/wei/views.py:58
|
||||
msgid "Search WEI"
|
||||
msgstr "Chercher un WEI"
|
||||
|
||||
#: apps/wei/views.py:108
|
||||
#: apps/wei/views.py:109
|
||||
msgid "WEI Detail"
|
||||
msgstr "Détails du WEI"
|
||||
|
||||
#: apps/wei/views.py:203
|
||||
#: apps/wei/views.py:208
|
||||
msgid "View members of the WEI"
|
||||
msgstr "Voir les membres du WEI"
|
||||
|
||||
#: apps/wei/views.py:231
|
||||
#: apps/wei/views.py:236
|
||||
msgid "Find WEI Membership"
|
||||
msgstr "Trouver une adhésion au WEI"
|
||||
|
||||
#: apps/wei/views.py:241
|
||||
#: apps/wei/views.py:246
|
||||
msgid "View registrations to the WEI"
|
||||
msgstr "Voir les inscriptions au WEI"
|
||||
|
||||
#: apps/wei/views.py:265
|
||||
#: apps/wei/views.py:270
|
||||
msgid "Find WEI Registration"
|
||||
msgstr "Trouver une inscription au WEI"
|
||||
|
||||
#: apps/wei/views.py:276
|
||||
#: apps/wei/views.py:281
|
||||
msgid "Update the WEI"
|
||||
msgstr "Modifier le WEI"
|
||||
|
||||
#: apps/wei/views.py:297
|
||||
#: apps/wei/views.py:302
|
||||
msgid "Create new bus"
|
||||
msgstr "Ajouter un nouveau bus"
|
||||
|
||||
#: apps/wei/views.py:335
|
||||
#: apps/wei/views.py:340
|
||||
msgid "Update bus"
|
||||
msgstr "Modifier le bus"
|
||||
|
||||
#: apps/wei/views.py:367
|
||||
#: apps/wei/views.py:372
|
||||
msgid "Manage bus"
|
||||
msgstr "Gérer le bus"
|
||||
|
||||
#: apps/wei/views.py:394
|
||||
#: apps/wei/views.py:399
|
||||
msgid "Create new team"
|
||||
msgstr "Créer une nouvelle équipe"
|
||||
|
||||
#: apps/wei/views.py:434
|
||||
#: apps/wei/views.py:439
|
||||
msgid "Update team"
|
||||
msgstr "Modifier l'équipe"
|
||||
|
||||
#: apps/wei/views.py:465
|
||||
#: apps/wei/views.py:470
|
||||
msgid "Manage WEI team"
|
||||
msgstr "Gérer l'équipe WEI"
|
||||
|
||||
#: apps/wei/views.py:487
|
||||
#: apps/wei/views.py:492
|
||||
msgid "Register first year student to the WEI"
|
||||
msgstr "Inscrire un 1A au WEI"
|
||||
|
||||
#: apps/wei/views.py:545 apps/wei/views.py:638
|
||||
#: apps/wei/views.py:550 apps/wei/views.py:649
|
||||
msgid "This user is already registered to this WEI."
|
||||
msgstr "Cette personne est déjà inscrite au WEI."
|
||||
|
||||
#: apps/wei/views.py:550
|
||||
#: apps/wei/views.py:555
|
||||
msgid ""
|
||||
"This user can't be in her/his first year since he/she has already "
|
||||
"participated to a WEI."
|
||||
@ -3088,35 +3092,35 @@ msgstr ""
|
||||
"Cet utilisateur ne peut pas être en première année puisqu'il a déjà "
|
||||
"participé à un WEI."
|
||||
|
||||
#: apps/wei/views.py:567
|
||||
#: apps/wei/views.py:578
|
||||
msgid "Register old student to the WEI"
|
||||
msgstr "Inscrire un 2A+ au WEI"
|
||||
|
||||
#: apps/wei/views.py:622 apps/wei/views.py:704
|
||||
#: apps/wei/views.py:633 apps/wei/views.py:721
|
||||
msgid "You already opened an account in the Société générale."
|
||||
msgstr "Vous avez déjà ouvert un compte auprès de la société générale."
|
||||
|
||||
#: apps/wei/views.py:668
|
||||
#: apps/wei/views.py:685
|
||||
msgid "Update WEI Registration"
|
||||
msgstr "Modifier l'inscription WEI"
|
||||
|
||||
#: apps/wei/views.py:778
|
||||
#: apps/wei/views.py:795
|
||||
msgid "Delete WEI registration"
|
||||
msgstr "Supprimer l'inscription WEI"
|
||||
|
||||
#: apps/wei/views.py:789
|
||||
#: apps/wei/views.py:806
|
||||
msgid "You don't have the right to delete this WEI registration."
|
||||
msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI."
|
||||
|
||||
#: apps/wei/views.py:807
|
||||
#: apps/wei/views.py:824
|
||||
msgid "Validate WEI registration"
|
||||
msgstr "Valider l'inscription WEI"
|
||||
|
||||
#: apps/wei/views.py:1169
|
||||
#: apps/wei/views.py:1186
|
||||
msgid "Attribute buses to first year members"
|
||||
msgstr "Répartir les 1A dans les bus"
|
||||
|
||||
#: apps/wei/views.py:1191
|
||||
#: apps/wei/views.py:1211
|
||||
msgid "Attribute bus"
|
||||
msgstr "Attribuer un bus"
|
||||
|
||||
@ -3266,6 +3270,10 @@ msgstr ""
|
||||
msgid "Contact us"
|
||||
msgstr "Nous contacter"
|
||||
|
||||
#: note_kfet/templates/base.html:197
|
||||
msgid "Technical Support"
|
||||
msgstr "Support technique"
|
||||
|
||||
#: note_kfet/templates/base_search.html:15
|
||||
msgid "Search by attribute such as name…"
|
||||
msgstr "Chercher par un attribut tel que le nom …"
|
||||
|
@ -7,8 +7,8 @@
|
||||
* @returns {string}
|
||||
*/
|
||||
function pretty_money (value) {
|
||||
if (value % 100 === 0) { return (value < 0 ? '- ' : '') + Math.round(Math.abs(value) / 100) + ' €' } else {
|
||||
return (value < 0 ? '- ' : '') + Math.round(Math.abs(value) / 100) + '.' +
|
||||
if (value % 100 === 0) { return (value < 0 ? '- ' : '') + Math.floor(Math.abs(value) / 100) + ' €' } else {
|
||||
return (value < 0 ? '- ' : '') + Math.floor(Math.abs(value) / 100) + '.' +
|
||||
(Math.abs(value) % 100 < 10 ? '0' : '') + (Math.abs(value) % 100) + ' €'
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,11 @@ function displayStyle (note) {
|
||||
if (!note) { return '' }
|
||||
const balance = note.balance
|
||||
var css = ''
|
||||
if (balance < -5000) { css += ' text-danger bg-dark' } else if (balance < -1000) { css += ' text-danger' } else if (balance < 0) { css += ' text-warning' } else if (!note.email_confirmed) { css += ' text-white bg-primary' } else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += 'text-white bg-info' }
|
||||
if (balance < -5000) { css += ' text-danger bg-dark' }
|
||||
else if (balance < -1000) { css += ' text-danger' }
|
||||
else if (balance < 0) { css += ' text-warning' }
|
||||
if (!note.email_confirmed) { css += ' bg-primary' }
|
||||
else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += ' bg-info' }
|
||||
return css
|
||||
}
|
||||
|
||||
@ -377,11 +381,11 @@ function de_validate (id, validated, resourcetype) {
|
||||
* @param callback Function to call
|
||||
* @param wait Debounced milliseconds
|
||||
*/
|
||||
function debounce (callback, wait) {
|
||||
let timeout
|
||||
let debounce_timeout
|
||||
function debounce (callback, wait=500) {
|
||||
return (...args) => {
|
||||
const context = this
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => callback.apply(context, args), wait)
|
||||
clearTimeout(debounce_timeout)
|
||||
debounce_timeout = setTimeout(() => callback.apply(context, args), wait)
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<meta name="msapplication-config" content="{% static "favicon/browserconfig.xml" %}">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
{# Bootstrap, Font Awesome and custom CSS #}
|
||||
{# Load CSS #}
|
||||
<link rel="stylesheet" href="{% static "bootstrap4/css/bootstrap.min.css" %}">
|
||||
<link rel="stylesheet" href="{% static "font-awesome/css/font-awesome.min.css" %}">
|
||||
<link rel="stylesheet" href="{% static "css/custom.css" %}">
|
||||
|
||||
{# JQuery, Bootstrap and Turbolinks JavaScript #}
|
||||
@ -64,54 +63,101 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% if "note.transactiontemplate"|not_empty_model_list %}
|
||||
<li class="nav-item">
|
||||
{% url 'note:consos' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-coffee"></i> {% trans 'Consumptions' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-mug" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M1 2a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1h.5A1.5 1.5 0 0 1 16 4.5v7a1.5 1.5 0 0 1-1.5 1.5h-.55a2.5 2.5 0 0 1-2.45 2h-8A2.5 2.5 0 0 1 1 12.5V2zm13 10h.5a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5H14v8z"/>
|
||||
</svg>
|
||||
{% trans 'Consumptions' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated and user|is_member:"Kfet" %}
|
||||
<li class="nav-item">
|
||||
{% url 'note:transfer' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-exchange"></i> {% trans 'Transfer' %} </a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-exchange" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
|
||||
</svg>
|
||||
{% trans 'Transfer' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "auth.user"|model_list_length >= 2 %}
|
||||
<li class="nav-item">
|
||||
{% url 'member:user_list' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-user"></i> {% trans 'Users' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-user" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
</svg>
|
||||
{% trans 'Users' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "member.club"|not_empty_model_list %}
|
||||
<li class="nav-item">
|
||||
{% url 'member:club_list' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-users"></i> {% trans 'Clubs' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-users" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1H7zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M5.216 14A2.238 2.238 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.325 6.325 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1h4.216z"/>
|
||||
<path d="M4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>
|
||||
</svg>
|
||||
{% trans 'Clubs' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "activity.activity"|not_empty_model_list %}
|
||||
<li class="nav-item">
|
||||
{% url 'activity:activity_list' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-calendar" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V5h16V4H0V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>
|
||||
{% trans 'Activities' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "treasury.invoice"|not_empty_model_list %}
|
||||
<li class="nav-item">
|
||||
{% url 'treasury:invoice_list' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-credit-card"></i> {% trans 'Treasury' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-credit-card" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v1H0V4zm0 3v5a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7H0zm3 2h1a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1z"/>
|
||||
</svg>
|
||||
{% trans 'Treasury' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "wei.weiclub"|not_empty_model_list %}
|
||||
<li class="nav-item">
|
||||
{% url 'wei:current_wei_detail' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-bus"></i> {% trans 'WEI' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-signpost" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M7.293.707A1 1 0 0 0 7 1.414V4H2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h5v6h2v-6h3.532a1 1 0 0 0 .768-.36l1.933-2.32a.5.5 0 0 0 0-.64L13.3 4.36a1 1 0 0 0-.768-.36H9V1.414A1 1 0 0 0 7.293.707z"/>
|
||||
</svg>
|
||||
{% trans 'WEI' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
{% url 'permission:rights' as url %}
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-balance-scale"></i> {% trans 'Rights' %}</a>
|
||||
<a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}">
|
||||
<svg class="bi bi-shield" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M8 0c-.69 0-1.843.265-2.928.56-1.11.3-2.229.655-2.887.87a1.54 1.54 0 0 0-1.044 1.262c-.596 4.477.787 7.795 2.465 9.99a11.777 11.777 0 0 0 2.517 2.453c.386.273.744.482 1.048.625.28.132.581.24.829.24s.548-.108.829-.24a7.159 7.159 0 0 0 1.048-.625 11.775 11.775 0 0 0 2.517-2.453c1.678-2.195 3.061-5.513 2.465-9.99a1.541 1.541 0 0 0-1.044-1.263 62.467 62.467 0 0 0-2.887-.87C9.843.266 8.69 0 8 0zm0 5a1.5 1.5 0 0 1 .5 2.915l.385 1.99a.5.5 0 0 1-.491.595h-.788a.5.5 0 0 1-.49-.595l.384-1.99A1.5 1.5 0 0 1 8 5z"/>
|
||||
</svg>
|
||||
{% trans 'Rights' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.user.is_staff and ""|has_perm:user %}
|
||||
<li class="nav-item">
|
||||
<a data-turbolinks="false" class="nav-link" href="{% url 'admin:index' %}"><i class="fa fa-cogs"></i> {% trans 'Admin' %}</a>
|
||||
<a data-turbolinks="false" class="nav-link" href="{% url 'admin:index' %}">
|
||||
<svg class="bi bi-cog" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/>
|
||||
</svg>
|
||||
{% trans 'Admin' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -119,16 +165,25 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-user"></i>
|
||||
<svg class="bi bi-user" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
</svg>
|
||||
<span id="user_balance">{{ request.user.username }} ({{ request.user.note.balance | pretty_money }})</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="navbarDropdownMenuLink">
|
||||
<a class="dropdown-item" href="{% url 'member:user_detail' pk=request.user.pk %}">
|
||||
<i class="fa fa-user"></i> {% trans "My account" %}
|
||||
<svg class="bi bi-user" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
</svg>
|
||||
{% trans "My account" %}
|
||||
</a>
|
||||
<a class="dropdown-item" href="{% url 'logout' %}">
|
||||
<i class="fa fa-sign-out"></i> {% trans "Log out" %}
|
||||
<svg class="bi bi-signout" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M10 12.5a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v2a.5.5 0 0 0 1 0v-2A1.5 1.5 0 0 0 9.5 2h-8A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h8a1.5 1.5 0 0 0 1.5-1.5v-2a.5.5 0 0 0-1 0v2z"/>
|
||||
<path fill-rule="evenodd" d="M15.854 8.354a.5.5 0 0 0 0-.708l-3-3a.5.5 0 0 0-.708.708L14.293 7.5H5.5a.5.5 0 0 0 0 1h8.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3z"/>
|
||||
</svg>
|
||||
{% trans "Log out" %}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
@ -136,14 +191,22 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% if request.path != "/registration/signup/" %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'registration:signup' %}">
|
||||
<i class="fa fa-user-plus"></i> {% trans "Sign up" %}
|
||||
<svg class="bi bi-user-plus" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M1 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
|
||||
<path fill-rule="evenodd" d="M13.5 5a.5.5 0 0 1 .5.5V7h1.5a.5.5 0 0 1 0 1H14v1.5a.5.5 0 0 1-1 0V8h-1.5a.5.5 0 0 1 0-1H13V5.5a.5.5 0 0 1 .5-.5z"/>
|
||||
</svg>
|
||||
{% trans "Sign up" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.path != "/accounts/login/" %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'login' %}">
|
||||
<i class="fa fa-sign-in"></i> {% trans "Log in" %}
|
||||
<svg class="bi bi-login" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M6 3.5a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 0-1 0v2A1.5 1.5 0 0 0 6.5 14h8a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-8A1.5 1.5 0 0 0 5 3.5v2a.5.5 0 0 0 1 0v-2z"/>
|
||||
<path fill-rule="evenodd" d="M11.854 8.354a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H1.5a.5.5 0 0 0 0 1h8.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3z"/>
|
||||
</svg>
|
||||
{% trans "Log in" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -193,6 +256,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<span class="text-muted mr-1">
|
||||
<a href="mailto:{{ "CONTACT_EMAIL" | getenv }}"
|
||||
class="text-muted">{% trans "Contact us" %}</a> —
|
||||
<a href="mailto:{{ "SUPPORT_EMAIL" | getenv }}"
|
||||
class="text-muted">{% trans "Technical Support" %}</a> —
|
||||
</span>
|
||||
{% csrf_token %}
|
||||
<select title="language" name="language"
|
||||
|
@ -35,8 +35,9 @@ urlpatterns = [
|
||||
path('coffee/', include('django_htcpcp_tea.urls')),
|
||||
]
|
||||
|
||||
# During development, serve media files
|
||||
# During development, serve static and media files
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
if "oauth2_provider" in settings.INSTALLED_APPS:
|
||||
|
@ -4,14 +4,14 @@ django-bootstrap-datepicker-plus~=3.0.5
|
||||
django-cas-server~=1.2.0
|
||||
django-colorfield~=0.3.2
|
||||
django-crispy-forms~=1.7.2
|
||||
django-extensions~=2.1.4
|
||||
django-filter~=2.1.0
|
||||
django-extensions>=2.1.4
|
||||
django-filter~=2.1
|
||||
django-htcpcp-tea~=0.3.1
|
||||
django-mailer~=2.0.1
|
||||
django-oauth-toolkit~=1.3.3
|
||||
django-phonenumber-field~=5.0.0
|
||||
django-polymorphic~=2.0.3
|
||||
djangorestframework~=3.9.0
|
||||
django-polymorphic>=2.0.3,<3.0.0
|
||||
djangorestframework>=3.9.0,<3.13.0
|
||||
django-rest-polymorphic~=0.1.9
|
||||
django-tables2~=2.3.1
|
||||
python-memcached~=1.59
|
||||
|
Reference in New Issue
Block a user