From b7c382a1a81887ee63ee14db61a8787a4412bde5 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sat, 22 Jul 2017 22:35:01 +0200
Subject: [PATCH 1/8] Basic search structure
---
core/views/__init__.py | 11 ++
matmat/__init__.py | 0
matmat/admin.py | 3 +
matmat/migrations/__init__.py | 0
matmat/models.py | 3 +
matmat/templates/matmat/search_form.jinja | 50 ++++++++
matmat/tests.py | 3 +
matmat/urls.py | 32 +++++
matmat/views.py | 146 ++++++++++++++++++++++
sith/settings.py | 1 +
sith/urls.py | 1 +
11 files changed, 250 insertions(+)
create mode 100644 matmat/__init__.py
create mode 100644 matmat/admin.py
create mode 100644 matmat/migrations/__init__.py
create mode 100644 matmat/models.py
create mode 100644 matmat/templates/matmat/search_form.jinja
create mode 100644 matmat/tests.py
create mode 100644 matmat/urls.py
create mode 100644 matmat/views.py
diff --git a/core/views/__init__.py b/core/views/__init__.py
index 470db647..b8205f57 100644
--- a/core/views/__init__.py
+++ b/core/views/__init__.py
@@ -143,6 +143,17 @@ class CanViewMixin(View):
self.get_queryset = types.MethodType(get_qs, self)
return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
+
+class WasSuscribed(View):
+ """
+ This view check if the user was at least an old subscriber
+ """
+ def dispatch(self, request, *args, **kwargs):
+ if not request.user.was_subscribed:
+ raise PermissionDenied
+ return super(WasSuscribed, self).dispatch(request, *args, **kwargs)
+
+
class TabedViewMixin(View):
"""
This view provide the basic functions for displaying tabs in the template
diff --git a/matmat/__init__.py b/matmat/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/matmat/admin.py b/matmat/admin.py
new file mode 100644
index 00000000..8c38f3f3
--- /dev/null
+++ b/matmat/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/matmat/migrations/__init__.py b/matmat/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/matmat/models.py b/matmat/models.py
new file mode 100644
index 00000000..71a83623
--- /dev/null
+++ b/matmat/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/matmat/templates/matmat/search_form.jinja b/matmat/templates/matmat/search_form.jinja
new file mode 100644
index 00000000..cf0d2862
--- /dev/null
+++ b/matmat/templates/matmat/search_form.jinja
@@ -0,0 +1,50 @@
+{% extends "core/base.jinja" %}
+
+{% block title %}
+{% trans %}Search user{% endtrans %}
+{% endblock %}
+
+{% block content %}
+{% if object_list.exists() %}
+{% trans %}User found{% endtrans %}
+{% for user in object_list %}
+ {{ user }}
+{% endfor %}
+{% endif %}
+{% trans %}Search user{% endtrans %}
+{% trans %}Search by profile{% endtrans %}
+
+{% trans %}Inverted search{% endtrans %}
+
+
+{% trans %}Simple search{% endtrans %}
+ {% csrf_token %}
+
+{% endblock %}
+
+{% block script %}
+{{ super() }}
+{% endblock %}
diff --git a/matmat/tests.py b/matmat/tests.py
new file mode 100644
index 00000000..7ce503c2
--- /dev/null
+++ b/matmat/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/matmat/urls.py b/matmat/urls.py
new file mode 100644
index 00000000..8a637b20
--- /dev/null
+++ b/matmat/urls.py
@@ -0,0 +1,32 @@
+# -*- coding:utf-8 -*
+#
+# Copyright 2017
+# - Sli
+#
+# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
+# http://ae.utbm.fr.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License a published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
+# Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+
+from django.conf.urls import url
+
+from matmat.views import *
+
+urlpatterns = [
+ url(r'^$', SearchFormView.as_view(), name="search"),
+ url(r'^search_reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+]
diff --git a/matmat/views.py b/matmat/views.py
new file mode 100644
index 00000000..a6e63402
--- /dev/null
+++ b/matmat/views.py
@@ -0,0 +1,146 @@
+# -*- coding:utf-8 -*
+#
+# Copyright 2017
+# - Sli
+#
+# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
+# http://ae.utbm.fr.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License a published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
+# Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+
+from django.shortcuts import render
+
+# Create your views here.
+
+from django.shortcuts import get_object_or_404
+from django.views.generic import ListView
+from django.views.generic.edit import FormView
+from django.core.urlresolvers import reverse_lazy, reverse
+from django.utils.translation import ugettext_lazy as _
+from django.views.generic.detail import SingleObjectMixin
+from django.core.exceptions import PermissionDenied
+from django.db import transaction
+from django.forms import CheckboxSelectMultiple
+from django import forms
+
+from core.models import User
+from core.views import WasSuscribed
+from core.views.forms import SelectDate
+from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
+
+# Custom form
+
+
+class SearchForm(forms.ModelForm):
+ class Meta:
+ model = User
+ fields = [
+ 'first_name',
+ 'last_name',
+ 'nick_name',
+ 'sex',
+ 'role',
+ 'department',
+ 'semester',
+ 'promo',
+ 'date_of_birth',
+ 'phone',
+ ]
+ widgets = {
+ 'date_of_birth': SelectDate,
+ 'phone': PhoneNumberInternationalFallbackWidget,
+ # 'sex': CheckboxSelectMultiple,
+ }
+
+ def __init__(self, *args, **kwargs):
+ super(SearchForm, self).__init__(*args, **kwargs)
+ for key in self.fields.keys():
+ self.fields[key].required = False
+ self.fields['sex'].choices.append(("INDIFFERENT", _("Indifferent")))
+
+
+# Views
+
+class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
+ model = User
+ template_name = 'matmat/search_form.jinja'
+
+ def dispatch(self, request, *args, **kwargs):
+ self.form_class = kwargs['form']
+ self.reverse = kwargs['reverse']
+ if 'valid_form' in kwargs.keys():
+ self.valid_form = kwargs['valid_form']
+ else:
+ self.valid_form = None
+
+ self.init_query = self.model.objects
+ if not (request.user.is_board_member or request.user.is_root):
+ self.init_query = self.init_query.exclude(is_subscriber_viewable=False)
+
+ return super(SearchFormListView, self).dispatch(request, *args, **kwargs)
+
+ def post(self, request, *args, **kwargs):
+ return self.get(request, *args, **kwargs)
+
+ def get_context_data(self, **kwargs):
+ self.object = None
+ kwargs = super(SearchFormListView, self).get_context_data(**kwargs)
+ kwargs['form'] = self.form_class()
+ return kwargs
+
+ def get_queryset(self):
+ if self.valid_form is not None:
+ if self.reverse:
+ return self.init_query.filter(phone=self.valid_form['phone']).all()
+ else:
+ q = self.init_query
+ # f = self.valid_form
+ return q.all()
+ else:
+ return self.model.objects.none()
+
+
+class SearchFormView(WasSuscribed, FormView):
+ """
+ Allows users to search inside the user list
+ """
+ form_class = SearchForm
+ reverse = False
+
+ def dispatch(self, request, *args, **kwargs):
+ self.init_query = User.objects
+ kwargs['form'] = self.get_form_class()
+ kwargs['reverse'] = self.reverse
+ return super(SearchFormView, self).dispatch(request, *args, **kwargs)
+
+ def get(self, request, *args, **kwargs):
+ view = SearchFormListView.as_view()
+ return view(request, *args, **kwargs)
+
+ def post(self, request, *args, **kwargs):
+ form = self.get_form()
+ view = SearchFormListView.as_view()
+ if form.is_valid():
+ kwargs['valid_form'] = form.clean()
+ return view(request, *args, **kwargs)
+
+ def get_initial(self):
+ return super(SearchFormView, self).get_initial()
+
+
+class SearchReverseFormView(SearchFormView):
+ reverse = True
diff --git a/sith/settings.py b/sith/settings.py
index d12d3a0b..948c6d2d 100644
--- a/sith/settings.py
+++ b/sith/settings.py
@@ -87,6 +87,7 @@ INSTALLED_APPS = (
'forum',
'stock',
'trombi',
+ 'matmat',
)
MIDDLEWARE_CLASSES = (
diff --git a/sith/urls.py b/sith/urls.py
index 9623ca16..2b744c24 100644
--- a/sith/urls.py
+++ b/sith/urls.py
@@ -67,6 +67,7 @@ urlpatterns = [
url(r'^election/', include('election.urls', namespace="election", app_name="election")),
url(r'^forum/', include('forum.urls', namespace="forum", app_name="forum")),
url(r'^trombi/', include('trombi.urls', namespace="trombi", app_name="trombi")),
+ url(r'^matmatronch/', include('matmat.urls', namespace="matmat", app_name="matmat")),
url(r'^admin/', include(admin.site.urls)),
url(r'^ajax_select/', include(ajax_select_urls)),
url(r'^i18n/', include('django.conf.urls.i18n')),
From 9ff8f02a45913f450ae6e0ed01812377538a1634 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sun, 23 Jul 2017 12:54:12 +0200
Subject: [PATCH 2/8] Form remember last entered values
---
core/templates/core/base.jinja | 2 +-
matmat/templates/matmat/search_form.jinja | 25 +++++++++++-
matmat/urls.py | 3 +-
matmat/views.py | 50 +++++++++++++++--------
4 files changed, 61 insertions(+), 19 deletions(-)
diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja
index 75a0460a..40889d00 100644
--- a/core/templates/core/base.jinja
+++ b/core/templates/core/base.jinja
@@ -88,7 +88,7 @@
{% if not popup %}
{% trans %}Main{% endtrans %}
- {% trans %}Matmatronch{% endtrans %}
+ {% trans %}Matmatronch{% endtrans %}
{% trans %}Wiki{% endtrans %}
{% trans %}SAS{% endtrans %}
{% trans %}Forum{% endtrans %}
diff --git a/matmat/templates/matmat/search_form.jinja b/matmat/templates/matmat/search_form.jinja
index cf0d2862..4c674db9 100644
--- a/matmat/templates/matmat/search_form.jinja
+++ b/matmat/templates/matmat/search_form.jinja
@@ -1,3 +1,4 @@
+{% from "core/macros.jinja" import user_mini_profile, paginate %}
{% extends "core/base.jinja" %}
{% block title %}
@@ -5,11 +6,33 @@
{% endblock %}
{% block content %}
+
{% if object_list.exists() %}
{% trans %}User found{% endtrans %}
{% for user in object_list %}
- {{ user }}
+
+
+
{% endfor %}
+
+{{ paginate(page_obj, paginator) }}
{% endif %}
{% trans %}Search user{% endtrans %}
{% trans %}Search by profile{% endtrans %}
diff --git a/matmat/urls.py b/matmat/urls.py
index 8a637b20..c4885bca 100644
--- a/matmat/urls.py
+++ b/matmat/urls.py
@@ -28,5 +28,6 @@ from matmat.views import *
urlpatterns = [
url(r'^$', SearchFormView.as_view(), name="search"),
- url(r'^search_reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+ url(r'^reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+ url(r'^clear$', SearchClearFormView.as_view(), name="search_clear"),
]
diff --git a/matmat/views.py b/matmat/views.py
index a6e63402..c81ff142 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -22,19 +22,12 @@
#
#
-from django.shortcuts import render
-
-# Create your views here.
-
-from django.shortcuts import get_object_or_404
-from django.views.generic import ListView
+from django.views.generic import ListView, View
from django.views.generic.edit import FormView
-from django.core.urlresolvers import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _
from django.views.generic.detail import SingleObjectMixin
-from django.core.exceptions import PermissionDenied
-from django.db import transaction
-from django.forms import CheckboxSelectMultiple
+from django.http.response import HttpResponseRedirect
+from django.core.urlresolvers import reverse
from django import forms
from core.models import User
@@ -52,7 +45,6 @@ class SearchForm(forms.ModelForm):
'first_name',
'last_name',
'nick_name',
- 'sex',
'role',
'department',
'semester',
@@ -63,21 +55,34 @@ class SearchForm(forms.ModelForm):
widgets = {
'date_of_birth': SelectDate,
'phone': PhoneNumberInternationalFallbackWidget,
- # 'sex': CheckboxSelectMultiple,
}
+ sex = forms.ChoiceField([
+ ("MAN", _("Man")),
+ ("WOMAN", _("Woman")),
+ ("INDIFFERENT", _("Indifferent"))
+ ], widget=forms.RadioSelect, initial="INDIFFERENT")
+
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
for key in self.fields.keys():
self.fields[key].required = False
- self.fields['sex'].choices.append(("INDIFFERENT", _("Indifferent")))
+ @property
+ def cleaned_data_json(self):
+ data = self.cleaned_data
+ for key in data.keys():
+ if key in ('date_of_birth', 'phone') and data[key] is not None:
+ data[key] = str(data[key])
+ return data
# Views
+
class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
model = User
template_name = 'matmat/search_form.jinja'
+ paginate_by = 3
def dispatch(self, request, *args, **kwargs):
self.form_class = kwargs['form']
@@ -99,7 +104,7 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
def get_context_data(self, **kwargs):
self.object = None
kwargs = super(SearchFormListView, self).get_context_data(**kwargs)
- kwargs['form'] = self.form_class()
+ kwargs['form'] = self.form_class
return kwargs
def get_queryset(self):
@@ -122,8 +127,9 @@ class SearchFormView(WasSuscribed, FormView):
reverse = False
def dispatch(self, request, *args, **kwargs):
+ self.session = request.session
self.init_query = User.objects
- kwargs['form'] = self.get_form_class()
+ kwargs['form'] = self.get_form()
kwargs['reverse'] = self.reverse
return super(SearchFormView, self).dispatch(request, *args, **kwargs)
@@ -136,11 +142,23 @@ class SearchFormView(WasSuscribed, FormView):
view = SearchFormListView.as_view()
if form.is_valid():
kwargs['valid_form'] = form.clean()
+ request.session['matmat_search'] = form.cleaned_data_json
return view(request, *args, **kwargs)
def get_initial(self):
- return super(SearchFormView, self).get_initial()
+ return self.session.get('matmat_search', {})
class SearchReverseFormView(SearchFormView):
reverse = True
+
+
+class SearchClearFormView(WasSuscribed, View):
+ """
+ Clear SearchFormView and redirect to it
+ """
+
+ def dispatch(self, request, *args, **kwargs):
+ super(SearchClearFormView, self).dispatch(request, *args, **kwargs)
+ request.session.pop('matmat_search')
+ return HttpResponseRedirect(reverse('matmat:search'))
From 39616874a8dfd21fe31f02631a667e467626fa4f Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sun, 23 Jul 2017 13:24:39 +0200
Subject: [PATCH 3/8] Fix broken pagination by remembering last search
---
matmat/templates/matmat/search_form.jinja | 2 +-
matmat/urls.py | 4 +--
matmat/views.py | 30 +++++++++++++++++------
3 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/matmat/templates/matmat/search_form.jinja b/matmat/templates/matmat/search_form.jinja
index 4c674db9..b01eaaa0 100644
--- a/matmat/templates/matmat/search_form.jinja
+++ b/matmat/templates/matmat/search_form.jinja
@@ -20,7 +20,7 @@
border-color: black;
}
-{% if object_list.exists() %}
+{% if result_exists %}
{% trans %}User found{% endtrans %}
{% for user in object_list %}
diff --git a/matmat/urls.py b/matmat/urls.py
index c4885bca..dfb54dd6 100644
--- a/matmat/urls.py
+++ b/matmat/urls.py
@@ -27,7 +27,7 @@ from django.conf.urls import url
from matmat.views import *
urlpatterns = [
- url(r'^$', SearchFormView.as_view(), name="search"),
- url(r'^reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+ url(r'^search$', SearchFormView.as_view(), name="search"),
+ url(r'^search/reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
url(r'^clear$', SearchClearFormView.as_view(), name="search_clear"),
]
diff --git a/matmat/views.py b/matmat/views.py
index c81ff142..4fcd6a6b 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -21,6 +21,7 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
+from ast import literal_eval
from django.views.generic import ListView, View
from django.views.generic.edit import FormView
@@ -87,6 +88,10 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
def dispatch(self, request, *args, **kwargs):
self.form_class = kwargs['form']
self.reverse = kwargs['reverse']
+ self.session = request.session
+ self.last_search = self.session.get('matmat_search_result', str([]))
+ self.last_search = literal_eval(self.last_search)
+ print(self.last_search)
if 'valid_form' in kwargs.keys():
self.valid_form = kwargs['valid_form']
else:
@@ -105,18 +110,24 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
self.object = None
kwargs = super(SearchFormListView, self).get_context_data(**kwargs)
kwargs['form'] = self.form_class
+ kwargs['result_exists'] = self.result_exists
return kwargs
def get_queryset(self):
+ q = self.init_query
if self.valid_form is not None:
if self.reverse:
- return self.init_query.filter(phone=self.valid_form['phone']).all()
+ q = q.filter(phone=self.valid_form['phone']).all()
else:
- q = self.init_query
- # f = self.valid_form
- return q.all()
+ q = q.all()
else:
- return self.model.objects.none()
+ q = q.filter(pk__in=self.last_search).all()
+ self.result_exists = q.exists()
+ self.last_search = []
+ for user in q:
+ self.last_search.append(user.id)
+ self.session['matmat_search_result'] = str(self.last_search)
+ return q
class SearchFormView(WasSuscribed, FormView):
@@ -142,11 +153,11 @@ class SearchFormView(WasSuscribed, FormView):
view = SearchFormListView.as_view()
if form.is_valid():
kwargs['valid_form'] = form.clean()
- request.session['matmat_search'] = form.cleaned_data_json
+ request.session['matmat_search_form'] = form.cleaned_data_json
return view(request, *args, **kwargs)
def get_initial(self):
- return self.session.get('matmat_search', {})
+ return self.session.get('matmat_search_form', {})
class SearchReverseFormView(SearchFormView):
@@ -160,5 +171,8 @@ class SearchClearFormView(WasSuscribed, View):
def dispatch(self, request, *args, **kwargs):
super(SearchClearFormView, self).dispatch(request, *args, **kwargs)
- request.session.pop('matmat_search')
+ if 'matmat_search_form' in request.session.keys():
+ request.session.pop('matmat_search_form')
+ if 'matmat_search_result' in request.session.keys():
+ request.session.pop('matmat_search_result')
return HttpResponseRedirect(reverse('matmat:search'))
From 349475cd37491ab7d6c0aef6a481cae1b4b74697 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sun, 23 Jul 2017 13:42:13 +0200
Subject: [PATCH 4/8] Functionnal search engine
---
matmat/views.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/matmat/views.py b/matmat/views.py
index 4fcd6a6b..475adfd9 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -91,7 +91,6 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
self.session = request.session
self.last_search = self.session.get('matmat_search_result', str([]))
self.last_search = literal_eval(self.last_search)
- print(self.last_search)
if 'valid_form' in kwargs.keys():
self.valid_form = kwargs['valid_form']
else:
@@ -119,7 +118,11 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
if self.reverse:
q = q.filter(phone=self.valid_form['phone']).all()
else:
- q = q.all()
+ search_dict = {}
+ for key, value in self.valid_form.items():
+ if key != 'phone' and not (value == '' or value is None or value == 'INDIFFERENT'):
+ search_dict[key + "__icontains"] = value
+ q = q.filter(**search_dict).all()
else:
q = q.filter(pk__in=self.last_search).all()
self.result_exists = q.exists()
From 86d62f12e796623568bc13f800903d3df563da61 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sun, 23 Jul 2017 15:03:04 +0200
Subject: [PATCH 5/8] Fully functionnal Matmatronch
---
matmat/templates/matmat/search_form.jinja | 17 +++++----
matmat/urls.py | 5 ++-
matmat/views.py | 46 +++++++++++++++++++----
3 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/matmat/templates/matmat/search_form.jinja b/matmat/templates/matmat/search_form.jinja
index b01eaaa0..dbadcebc 100644
--- a/matmat/templates/matmat/search_form.jinja
+++ b/matmat/templates/matmat/search_form.jinja
@@ -39,7 +39,7 @@
-{% trans %}Simple search{% endtrans %}
+{% trans %}Quick search{% endtrans %}
+
+
+ {{ form.quick.errors }}
+ {{ form.quick.label }}
+ {{ form.quick }}
+
+
+
{% endblock %}
{% block script %}
diff --git a/matmat/urls.py b/matmat/urls.py
index dfb54dd6..b09ea137 100644
--- a/matmat/urls.py
+++ b/matmat/urls.py
@@ -27,7 +27,8 @@ from django.conf.urls import url
from matmat.views import *
urlpatterns = [
- url(r'^search$', SearchFormView.as_view(), name="search"),
- url(r'^search/reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+ url(r'^$', SearchNormalFormView.as_view(), name="search"),
+ url(r'^reverse$', SearchReverseFormView.as_view(), name="search_reverse"),
+ url(r'^quick$', SearchQuickFormView.as_view(), name="search_quick"),
url(r'^clear$', SearchClearFormView.as_view(), name="search_clear"),
]
diff --git a/matmat/views.py b/matmat/views.py
index 475adfd9..384bc504 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -22,6 +22,7 @@
#
#
from ast import literal_eval
+from enum import Enum
from django.views.generic import ListView, View
from django.views.generic.edit import FormView
@@ -34,8 +35,18 @@ from django import forms
from core.models import User
from core.views import WasSuscribed
from core.views.forms import SelectDate
+from core.views import search_user
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
+# Enum to select search type
+
+
+class SearchType(Enum):
+ NORMAL = 1
+ REVERSE = 2
+ QUICK = 3
+
+
# Custom form
@@ -64,6 +75,8 @@ class SearchForm(forms.ModelForm):
("INDIFFERENT", _("Indifferent"))
], widget=forms.RadioSelect, initial="INDIFFERENT")
+ quick = forms.CharField(label=_('Last/First name or nickname'), max_length=255)
+
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
for key in self.fields.keys():
@@ -82,12 +95,13 @@ class SearchForm(forms.ModelForm):
class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
model = User
+ ordering = ["-id"]
+ paginate_by = 12
template_name = 'matmat/search_form.jinja'
- paginate_by = 3
def dispatch(self, request, *args, **kwargs):
self.form_class = kwargs['form']
- self.reverse = kwargs['reverse']
+ self.search_type = kwargs['search_type']
self.session = request.session
self.last_search = self.session.get('matmat_search_result', str([]))
self.last_search = literal_eval(self.last_search)
@@ -97,7 +111,9 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
self.valid_form = None
self.init_query = self.model.objects
+ self.can_see_hidden = True
if not (request.user.is_board_member or request.user.is_root):
+ self.can_see_hidden = False
self.init_query = self.init_query.exclude(is_subscriber_viewable=False)
return super(SearchFormListView, self).dispatch(request, *args, **kwargs)
@@ -115,17 +131,24 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
def get_queryset(self):
q = self.init_query
if self.valid_form is not None:
- if self.reverse:
+ if self.search_type == SearchType.REVERSE:
q = q.filter(phone=self.valid_form['phone']).all()
+ elif self.search_type == SearchType.QUICK:
+ q = search_user(self.valid_form['quick'])
+ if not self.can_see_hidden:
+ q = [user for user in q if user.is_subscriber_viewable]
else:
search_dict = {}
for key, value in self.valid_form.items():
- if key != 'phone' and not (value == '' or value is None or value == 'INDIFFERENT'):
+ if key not in ('phone', 'quick') and not (value == '' or value is None or value == 'INDIFFERENT'):
search_dict[key + "__icontains"] = value
q = q.filter(**search_dict).all()
else:
q = q.filter(pk__in=self.last_search).all()
- self.result_exists = q.exists()
+ if isinstance(q, list):
+ self.result_exists = len(q) > 0
+ else:
+ self.result_exists = q.exists()
self.last_search = []
for user in q:
self.last_search.append(user.id)
@@ -138,13 +161,12 @@ class SearchFormView(WasSuscribed, FormView):
Allows users to search inside the user list
"""
form_class = SearchForm
- reverse = False
def dispatch(self, request, *args, **kwargs):
self.session = request.session
self.init_query = User.objects
kwargs['form'] = self.get_form()
- kwargs['reverse'] = self.reverse
+ kwargs['search_type'] = self.search_type
return super(SearchFormView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
@@ -163,8 +185,16 @@ class SearchFormView(WasSuscribed, FormView):
return self.session.get('matmat_search_form', {})
+class SearchNormalFormView(SearchFormView):
+ search_type = SearchType.NORMAL
+
+
class SearchReverseFormView(SearchFormView):
- reverse = True
+ search_type = SearchType.REVERSE
+
+
+class SearchQuickFormView(SearchFormView):
+ search_type = SearchType.QUICK
class SearchClearFormView(WasSuscribed, View):
From dc571836ae2a484626ad4d2a435869e5d56ca745 Mon Sep 17 00:00:00 2001
From: klmp200
Date: Sun, 23 Jul 2017 16:50:45 +0200
Subject: [PATCH 6/8] Fixed issues with department and sex form
---
matmat/templates/matmat/search_form.jinja | 2 ++
matmat/views.py | 12 +++++++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/matmat/templates/matmat/search_form.jinja b/matmat/templates/matmat/search_form.jinja
index dbadcebc..148a0469 100644
--- a/matmat/templates/matmat/search_form.jinja
+++ b/matmat/templates/matmat/search_form.jinja
@@ -56,6 +56,7 @@
{{ form.phone.errors }}
{{ form.phone.label }}
{{ form.phone }}
+ {{ form.sex.as_hidden() }}
@@ -65,6 +66,7 @@
{{ form.quick.errors }}
{{ form.quick.label }}
+ {{ form.sex.as_hidden() }}
{{ form.quick }}
diff --git a/matmat/views.py b/matmat/views.py
index 384bc504..b6422ae0 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -134,8 +134,11 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
if self.search_type == SearchType.REVERSE:
q = q.filter(phone=self.valid_form['phone']).all()
elif self.search_type == SearchType.QUICK:
- q = search_user(self.valid_form['quick'])
- if not self.can_see_hidden:
+ if self.valid_form['quick'].strip():
+ q = search_user(self.valid_form['quick'])
+ else:
+ q = []
+ if not self.can_see_hidden and len(q) > 0:
q = [user for user in q if user.is_subscriber_viewable]
else:
search_dict = {}
@@ -182,7 +185,10 @@ class SearchFormView(WasSuscribed, FormView):
return view(request, *args, **kwargs)
def get_initial(self):
- return self.session.get('matmat_search_form', {})
+ init = self.session.get('matmat_search_form', {})
+ if not init:
+ init['department'] = ''
+ return init
class SearchNormalFormView(SearchFormView):
From a9e23920ee5060be077f0d74aa68eb21bb55791e Mon Sep 17 00:00:00 2001
From: klmp200
Date: Mon, 24 Jul 2017 12:33:34 +0200
Subject: [PATCH 7/8] Matmat renames
---
core/views/__init__.py | 4 ++--
matmat/urls.py | 2 +-
matmat/views.py | 10 +++++-----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/core/views/__init__.py b/core/views/__init__.py
index b8205f57..c27470f5 100644
--- a/core/views/__init__.py
+++ b/core/views/__init__.py
@@ -144,14 +144,14 @@ class CanViewMixin(View):
return super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
-class WasSuscribed(View):
+class FormerSubscriberMixin(View):
"""
This view check if the user was at least an old subscriber
"""
def dispatch(self, request, *args, **kwargs):
if not request.user.was_subscribed:
raise PermissionDenied
- return super(WasSuscribed, self).dispatch(request, *args, **kwargs)
+ return super(FormerSubscriberMixin, self).dispatch(request, *args, **kwargs)
class TabedViewMixin(View):
diff --git a/matmat/urls.py b/matmat/urls.py
index b09ea137..24557952 100644
--- a/matmat/urls.py
+++ b/matmat/urls.py
@@ -1,7 +1,7 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
-# - Sli
+# - Sli
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
diff --git a/matmat/views.py b/matmat/views.py
index b6422ae0..46b46013 100644
--- a/matmat/views.py
+++ b/matmat/views.py
@@ -1,7 +1,7 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
-# - Sli
+# - Sli
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
@@ -33,7 +33,7 @@ from django.core.urlresolvers import reverse
from django import forms
from core.models import User
-from core.views import WasSuscribed
+from core.views import FormerSubscriberMixin
from core.views.forms import SelectDate
from core.views import search_user
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
@@ -93,7 +93,7 @@ class SearchForm(forms.ModelForm):
# Views
-class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
+class SearchFormListView(FormerSubscriberMixin, SingleObjectMixin, ListView):
model = User
ordering = ["-id"]
paginate_by = 12
@@ -159,7 +159,7 @@ class SearchFormListView(WasSuscribed, SingleObjectMixin, ListView):
return q
-class SearchFormView(WasSuscribed, FormView):
+class SearchFormView(FormerSubscriberMixin, FormView):
"""
Allows users to search inside the user list
"""
@@ -203,7 +203,7 @@ class SearchQuickFormView(SearchFormView):
search_type = SearchType.QUICK
-class SearchClearFormView(WasSuscribed, View):
+class SearchClearFormView(FormerSubscriberMixin, View):
"""
Clear SearchFormView and redirect to it
"""
From 0f408d9d89520da86d3d0f3a78dd1855e269b2ca Mon Sep 17 00:00:00 2001
From: klmp200
Date: Tue, 15 Aug 2017 18:08:32 +0200
Subject: [PATCH 8/8] Translations
---
locale/fr/LC_MESSAGES/django.po | 279 ++++++++++++++++++--------------
1 file changed, 155 insertions(+), 124 deletions(-)
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 60bf7060..654ad066 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-08-15 02:08+0200\n"
+"POT-Creation-Date: 2017-08-15 18:05+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia \n"
"Language-Team: AE info \n"
@@ -18,8 +18,8 @@ msgstr ""
#: accounting/models.py:61 accounting/models.py:110 accounting/models.py:138
#: accounting/models.py:197 club/models.py:44
-#: core/templates/core/base.jinja:233 counter/models.py:108
-#: counter/models.py:134 counter/models.py:178 forum/models.py:49
+#: core/templates/core/base.jinja:233 counter/models.py:113
+#: counter/models.py:139 counter/models.py:183 forum/models.py:49
#: launderette/models.py:38 launderette/models.py:84 launderette/models.py:110
#: stock/models.py:38 stock/models.py:54 stock/models.py:77 stock/models.py:97
msgid "name"
@@ -66,8 +66,8 @@ msgid "account number"
msgstr "numero de compte"
#: accounting/models.py:113 accounting/models.py:139 club/models.py:187
-#: com/models.py:65 com/models.py:156 counter/models.py:143
-#: counter/models.py:179 trombi/models.py:149
+#: com/models.py:65 com/models.py:156 counter/models.py:148
+#: counter/models.py:184 trombi/models.py:149
msgid "club"
msgstr "club"
@@ -88,12 +88,12 @@ msgstr "Compte club"
msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s"
-#: accounting/models.py:195 club/models.py:188 counter/models.py:455
+#: accounting/models.py:195 club/models.py:188 counter/models.py:463
#: election/models.py:16 launderette/models.py:148
msgid "start date"
msgstr "date de début"
-#: accounting/models.py:196 club/models.py:189 counter/models.py:456
+#: accounting/models.py:196 club/models.py:189 counter/models.py:464
#: election/models.py:17
msgid "end date"
msgstr "date de fin"
@@ -107,7 +107,7 @@ msgid "club account"
msgstr "compte club"
#: accounting/models.py:200 accounting/models.py:257 counter/models.py:53
-#: counter/models.py:292
+#: counter/models.py:297
msgid "amount"
msgstr "montant"
@@ -128,17 +128,17 @@ msgid "journal"
msgstr "classeur"
#: accounting/models.py:258 core/models.py:628 core/models.py:1003
-#: core/models.py:1044 counter/models.py:295 counter/models.py:344
-#: counter/models.py:473 eboutic/models.py:39 eboutic/models.py:73
+#: core/models.py:1044 counter/models.py:300 counter/models.py:349
+#: counter/models.py:481 eboutic/models.py:39 eboutic/models.py:73
#: forum/models.py:239 forum/models.py:314 stock/models.py:76
msgid "date"
msgstr "date"
-#: accounting/models.py:259 counter/models.py:474 stock/models.py:79
+#: accounting/models.py:259 counter/models.py:482 stock/models.py:79
msgid "comment"
msgstr "commentaire"
-#: accounting/models.py:260 counter/models.py:296 counter/models.py:345
+#: accounting/models.py:260 counter/models.py:301 counter/models.py:350
#: subscription/models.py:55
msgid "payment method"
msgstr "méthode de paiement"
@@ -164,7 +164,7 @@ msgid "accounting type"
msgstr "type comptable"
#: accounting/models.py:269 accounting/models.py:371 accounting/models.py:398
-#: accounting/models.py:422 counter/models.py:336
+#: accounting/models.py:422 counter/models.py:341
msgid "label"
msgstr "étiquette"
@@ -206,7 +206,7 @@ msgstr "Compte"
msgid "Company"
msgstr "Entreprise"
-#: accounting/models.py:271 sith/settings.py:365
+#: accounting/models.py:271 sith/settings.py:366
#: stock/templates/stock/shopping_list_items.jinja:37
msgid "Other"
msgstr "Autre"
@@ -253,7 +253,7 @@ msgstr ""
"Vous devez fournir soit un type comptable simplifié ou un type comptable "
"standard"
-#: accounting/models.py:366 counter/models.py:138
+#: accounting/models.py:366 counter/models.py:143
msgid "code"
msgstr "code"
@@ -854,7 +854,7 @@ msgstr "Vous ne pouvez pas faire de boucles dans les clubs"
msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà."
-#: club/models.py:186 counter/models.py:453 counter/models.py:471
+#: club/models.py:186 counter/models.py:461 counter/models.py:479
#: eboutic/models.py:38 eboutic/models.py:72 election/models.py:140
#: launderette/models.py:114 launderette/models.py:152 sas/models.py:158
#: trombi/models.py:148
@@ -866,8 +866,8 @@ msgstr "nom d'utilisateur"
msgid "role"
msgstr "rôle"
-#: club/models.py:192 core/models.py:64 counter/models.py:109
-#: counter/models.py:135 election/models.py:13 election/models.py:93
+#: club/models.py:192 core/models.py:64 counter/models.py:114
+#: counter/models.py:140 election/models.py:13 election/models.py:93
#: election/models.py:141 forum/models.py:50 forum/models.py:186
msgid "description"
msgstr "description"
@@ -1587,11 +1587,11 @@ msgstr "blouse"
msgid "sex"
msgstr "sexe"
-#: core/models.py:167
+#: core/models.py:167 matmat/views.py:73
msgid "Man"
msgstr "Homme"
-#: core/models.py:167
+#: core/models.py:167 matmat/views.py:74
msgid "Woman"
msgstr "Femme"
@@ -1910,6 +1910,9 @@ msgid "Logout"
msgstr "Déconnexion"
#: core/templates/core/base.jinja:67 core/templates/core/base.jinja.py:68
+#: matmat/templates/matmat/search_form.jinja:50
+#: matmat/templates/matmat/search_form.jinja:60
+#: matmat/templates/matmat/search_form.jinja:71
msgid "Search"
msgstr "Recherche"
@@ -2886,136 +2889,136 @@ msgstr "client"
msgid "customers"
msgstr "clients"
-#: counter/models.py:85 counter/templates/counter/counter_click.jinja:48
+#: counter/models.py:90 counter/templates/counter/counter_click.jinja:48
#: counter/templates/counter/counter_click.jinja:82
msgid "Not enough money"
msgstr "Solde insuffisant"
-#: counter/models.py:113 counter/models.py:136
+#: counter/models.py:118 counter/models.py:141
msgid "product type"
msgstr "type du produit"
-#: counter/models.py:139
+#: counter/models.py:144
msgid "purchase price"
msgstr "prix d'achat"
-#: counter/models.py:140
+#: counter/models.py:145
msgid "selling price"
msgstr "prix de vente"
-#: counter/models.py:141
+#: counter/models.py:146
msgid "special selling price"
msgstr "prix de vente spécial"
-#: counter/models.py:142
+#: counter/models.py:147
msgid "icon"
msgstr "icône"
-#: counter/models.py:144
+#: counter/models.py:149
msgid "limit age"
msgstr "âge limite"
-#: counter/models.py:145
+#: counter/models.py:150
msgid "tray price"
msgstr "prix plateau"
-#: counter/models.py:146
+#: counter/models.py:151
msgid "parent product"
msgstr "produit parent"
-#: counter/models.py:148
+#: counter/models.py:153
msgid "buying groups"
msgstr "groupe d'achat"
-#: counter/models.py:149 election/models.py:36
+#: counter/models.py:154 election/models.py:36
msgid "archived"
msgstr "archivé"
-#: counter/models.py:152 counter/models.py:556
+#: counter/models.py:157 counter/models.py:564
msgid "product"
msgstr "produit"
-#: counter/models.py:180
+#: counter/models.py:185
msgid "products"
msgstr "produits"
-#: counter/models.py:181
+#: counter/models.py:186
msgid "counter type"
msgstr "type de comptoir"
-#: counter/models.py:183
+#: counter/models.py:188
msgid "Bar"
msgstr "Bar"
-#: counter/models.py:183
+#: counter/models.py:188
msgid "Office"
msgstr "Bureau"
-#: counter/models.py:183 counter/templates/counter/counter_list.jinja:11
+#: counter/models.py:188 counter/templates/counter/counter_list.jinja:11
#: eboutic/templates/eboutic/eboutic_main.jinja:4
#: eboutic/templates/eboutic/eboutic_main.jinja:24
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:8
#: eboutic/templates/eboutic/eboutic_payment_result.jinja:4
-#: sith/settings.py:364 sith/settings.py:372
+#: sith/settings.py:365 sith/settings.py:373
msgid "Eboutic"
msgstr "Eboutic"
-#: counter/models.py:184
+#: counter/models.py:189
msgid "sellers"
msgstr "vendeurs"
-#: counter/models.py:187 launderette/models.py:151
+#: counter/models.py:192 launderette/models.py:151
msgid "token"
msgstr "jeton"
-#: counter/models.py:190 counter/models.py:454 counter/models.py:472
+#: counter/models.py:195 counter/models.py:462 counter/models.py:480
#: launderette/models.py:39 stock/models.py:39
msgid "counter"
msgstr "comptoir"
-#: counter/models.py:298
+#: counter/models.py:303
msgid "bank"
msgstr "banque"
-#: counter/models.py:300 counter/models.py:347
+#: counter/models.py:305 counter/models.py:352
msgid "is validated"
msgstr "est validé"
-#: counter/models.py:303
+#: counter/models.py:308
msgid "refilling"
msgstr "rechargement"
-#: counter/models.py:340 eboutic/models.py:129
+#: counter/models.py:345 eboutic/models.py:129
msgid "unit price"
msgstr "prix unitaire"
-#: counter/models.py:341 counter/models.py:545 eboutic/models.py:130
+#: counter/models.py:346 counter/models.py:553 eboutic/models.py:130
msgid "quantity"
msgstr "quantité"
-#: counter/models.py:346
+#: counter/models.py:351
msgid "Sith account"
msgstr "Compte utilisateur"
-#: counter/models.py:346 sith/settings.py:357 sith/settings.py:362
-#: sith/settings.py:384
+#: counter/models.py:351 sith/settings.py:358 sith/settings.py:363
+#: sith/settings.py:385
msgid "Credit card"
msgstr "Carte bancaire"
-#: counter/models.py:350
+#: counter/models.py:355
msgid "selling"
msgstr "vente"
-#: counter/models.py:369
+#: counter/models.py:374
msgid "Unknown event"
msgstr "Événement inconnu"
-#: counter/models.py:370
+#: counter/models.py:375
#, python-format
msgid "Eticket bought for the event %(event)s"
msgstr "Eticket acheté pour l'événement %(event)s"
-#: counter/models.py:372 counter/models.py:384
+#: counter/models.py:377 counter/models.py:389
#, python-format
msgid ""
"You bought an eticket for the event %(event)s.\n"
@@ -3024,51 +3027,51 @@ msgstr ""
"Vous avez acheté un Eticket pour l'événement %(event)s.\n"
"Vous pouvez le télécharger sur cette page: %(url)s"
-#: counter/models.py:457
+#: counter/models.py:465
msgid "last activity date"
msgstr "dernière activité"
-#: counter/models.py:460
+#: counter/models.py:468
msgid "permanency"
msgstr "permanence"
-#: counter/models.py:475
+#: counter/models.py:483
msgid "emptied"
msgstr "coffre vidée"
-#: counter/models.py:478
+#: counter/models.py:486
msgid "cash register summary"
msgstr "relevé de caisse"
-#: counter/models.py:543
+#: counter/models.py:551
msgid "cash summary"
msgstr "relevé"
-#: counter/models.py:544
+#: counter/models.py:552
msgid "value"
msgstr "valeur"
-#: counter/models.py:546
+#: counter/models.py:554
msgid "check"
msgstr "chèque"
-#: counter/models.py:549
+#: counter/models.py:557
msgid "cash register summary item"
msgstr "élément de relevé de caisse"
-#: counter/models.py:557
+#: counter/models.py:565
msgid "banner"
msgstr "bannière"
-#: counter/models.py:558
+#: counter/models.py:566
msgid "event date"
msgstr "date de l'événement"
-#: counter/models.py:559
+#: counter/models.py:567
msgid "event title"
msgstr "titre de l'événement"
-#: counter/models.py:560
+#: counter/models.py:568
msgid "secret"
msgstr "secret"
@@ -3801,10 +3804,6 @@ msgstr "Appliquer les droits et le club propriétaire récursivement"
msgid "%(author)s said"
msgstr "Citation de %(author)s"
-#: fuck.py:32
-msgid "Record regularization"
-msgstr "Régularization des consignes"
-
#: launderette/models.py:42
#: launderette/templates/launderette/launderette_book.jinja:5
#: launderette/templates/launderette/launderette_book_choose.jinja:4
@@ -3861,12 +3860,12 @@ msgid "Washing and drying"
msgstr "Lavage et séchage"
#: launderette/templates/launderette/launderette_book.jinja:27
-#: sith/settings.py:532
+#: sith/settings.py:534
msgid "Washing"
msgstr "Lavage"
#: launderette/templates/launderette/launderette_book.jinja:31
-#: sith/settings.py:532
+#: sith/settings.py:534
msgid "Drying"
msgstr "Séchage"
@@ -3917,6 +3916,35 @@ msgstr "L'utilisateur n'a pas réservé de créneau"
msgid "Token not found"
msgstr "Jeton non trouvé"
+#: matmat/templates/matmat/search_form.jinja:5
+#: matmat/templates/matmat/search_form.jinja:37
+msgid "Search user"
+msgstr "Rechercher un utilisateur"
+
+#: matmat/templates/matmat/search_form.jinja:24
+msgid "User found"
+msgstr "Utilisateur trouvé"
+
+#: matmat/templates/matmat/search_form.jinja:38
+msgid "Search by profile"
+msgstr "Recherche par profile"
+
+#: matmat/templates/matmat/search_form.jinja:52
+msgid "Inverted search"
+msgstr "Recherche inversée"
+
+#: matmat/templates/matmat/search_form.jinja:63
+msgid "Quick search"
+msgstr "Recherche rapide"
+
+#: matmat/views.py:75
+msgid "Indifferent"
+msgstr "Indifferent"
+
+#: matmat/views.py:78
+msgid "Last/First name or nickname"
+msgstr "Nom de famille, prénom ou surnom"
+
#: rootplace/templates/rootplace/merge.jinja:8
msgid "Merge two users"
msgstr "Fusionner deux utilisateurs"
@@ -4008,217 +4036,217 @@ msgstr "Erreur de création de l'album %(album)s : %(msg)s"
msgid "Add user"
msgstr "Ajouter une personne"
-#: sith/settings.py:209
+#: sith/settings.py:210
msgid "English"
msgstr "Anglais"
-#: sith/settings.py:210
+#: sith/settings.py:211
msgid "French"
msgstr "Français"
-#: sith/settings.py:338
+#: sith/settings.py:339
msgid "TC"
msgstr "TC"
-#: sith/settings.py:339
+#: sith/settings.py:340
msgid "IMSI"
msgstr "IMSI"
-#: sith/settings.py:340
+#: sith/settings.py:341
msgid "IMAP"
msgstr "IMAP"
-#: sith/settings.py:341
+#: sith/settings.py:342
msgid "INFO"
msgstr "INFO"
-#: sith/settings.py:342
+#: sith/settings.py:343
msgid "GI"
msgstr "GI"
-#: sith/settings.py:343
+#: sith/settings.py:344
msgid "E"
msgstr "E"
-#: sith/settings.py:344
+#: sith/settings.py:345
msgid "EE"
msgstr "EE"
-#: sith/settings.py:345
+#: sith/settings.py:346
msgid "GESC"
msgstr "GESC"
-#: sith/settings.py:346
+#: sith/settings.py:347
msgid "GMC"
msgstr "GMC"
-#: sith/settings.py:347
+#: sith/settings.py:348
msgid "MC"
msgstr "MC"
-#: sith/settings.py:348
+#: sith/settings.py:349
msgid "EDIM"
msgstr "EDIM"
-#: sith/settings.py:349
+#: sith/settings.py:350
msgid "Humanities"
msgstr "Humanités"
-#: sith/settings.py:350
+#: sith/settings.py:351
msgid "N/A"
msgstr "N/A"
-#: sith/settings.py:354 sith/settings.py:361 sith/settings.py:382
+#: sith/settings.py:355 sith/settings.py:362 sith/settings.py:383
msgid "Check"
msgstr "Chèque"
-#: sith/settings.py:355 sith/settings.py:363 sith/settings.py:383
+#: sith/settings.py:356 sith/settings.py:364 sith/settings.py:384
msgid "Cash"
msgstr "Espèces"
-#: sith/settings.py:356
+#: sith/settings.py:357
msgid "Transfert"
msgstr "Virement"
-#: sith/settings.py:369
+#: sith/settings.py:370
msgid "Belfort"
msgstr "Belfort"
-#: sith/settings.py:370
+#: sith/settings.py:371
msgid "Sevenans"
msgstr "Sevenans"
-#: sith/settings.py:371
+#: sith/settings.py:372
msgid "Montbéliard"
msgstr "Montbéliard"
-#: sith/settings.py:425
+#: sith/settings.py:427
msgid "One semester"
msgstr "Un semestre, 15 €"
-#: sith/settings.py:430
+#: sith/settings.py:432
msgid "Two semesters"
msgstr "Deux semestres, 28 €"
-#: sith/settings.py:435
+#: sith/settings.py:437
msgid "Common core cursus"
msgstr "Cursus tronc commun, 45 €"
-#: sith/settings.py:440
+#: sith/settings.py:442
msgid "Branch cursus"
msgstr "Cursus branche, 45 €"
-#: sith/settings.py:445
+#: sith/settings.py:447
msgid "Alternating cursus"
msgstr "Cursus alternant, 30 €"
-#: sith/settings.py:450
+#: sith/settings.py:452
msgid "Honorary member"
msgstr "Membre honoraire, 0 €"
-#: sith/settings.py:455
+#: sith/settings.py:457
msgid "Assidu member"
msgstr "Membre d'Assidu, 0 €"
-#: sith/settings.py:460
+#: sith/settings.py:462
msgid "Amicale/DOCEO member"
msgstr "Membre de l'Amicale/DOCEO, 0 €"
-#: sith/settings.py:465
+#: sith/settings.py:467
msgid "UT network member"
msgstr "Cotisant du réseau UT, 0 €"
-#: sith/settings.py:470
+#: sith/settings.py:472
msgid "CROUS member"
msgstr "Membres du CROUS, 0 €"
-#: sith/settings.py:475
+#: sith/settings.py:477
msgid "Sbarro/ESTA member"
msgstr "Membre de Sbarro ou de l'ESTA, 15 €"
-#: sith/settings.py:497
+#: sith/settings.py:499
msgid "President"
msgstr "Président"
-#: sith/settings.py:498
+#: sith/settings.py:500
msgid "Vice-President"
msgstr "Vice-Président"
-#: sith/settings.py:499
+#: sith/settings.py:501
msgid "Treasurer"
msgstr "Trésorier"
-#: sith/settings.py:500
+#: sith/settings.py:502
msgid "Communication supervisor"
msgstr "Responsable communication"
-#: sith/settings.py:501
+#: sith/settings.py:503
msgid "Secretary"
msgstr "Secrétaire"
-#: sith/settings.py:502
+#: sith/settings.py:504
msgid "IT supervisor"
msgstr "Responsable info"
-#: sith/settings.py:503
+#: sith/settings.py:505
msgid "Board member"
msgstr "Membre du bureau"
-#: sith/settings.py:504
+#: sith/settings.py:506
msgid "Active member"
msgstr "Membre actif"
-#: sith/settings.py:505
+#: sith/settings.py:507
msgid "Curious"
msgstr "Curieux"
-#: sith/settings.py:539
+#: sith/settings.py:541
msgid "A fresh new to be moderated"
msgstr "Une nouvelle toute neuve à modérer"
-#: sith/settings.py:540
+#: sith/settings.py:542
msgid "New files to be moderated"
msgstr "Nouveaux fichiers à modérer"
-#: sith/settings.py:541
+#: sith/settings.py:543
msgid "New pictures/album to be moderated in the SAS"
msgstr "Nouvelles photos/albums à modérer dans le SAS"
-#: sith/settings.py:542
+#: sith/settings.py:544
msgid "You've been identified on some pictures"
msgstr "Vous avez été identifié sur des photos"
-#: sith/settings.py:543
+#: sith/settings.py:545
#, python-format
msgid "You just refilled of %s €"
msgstr "Vous avez rechargé votre compte de %s €"
-#: sith/settings.py:544
+#: sith/settings.py:546
#, python-format
msgid "You just bought %s"
msgstr "Vous avez acheté %s"
-#: sith/settings.py:545
+#: sith/settings.py:547
msgid "You have a notification"
msgstr "Vous avez une notification"
-#: sith/settings.py:549
+#: sith/settings.py:551
msgid "Success!"
msgstr "Succès !"
-#: sith/settings.py:550
+#: sith/settings.py:552
msgid "Fail!"
msgstr "Échec !"
-#: sith/settings.py:551
+#: sith/settings.py:553
msgid "You successfully posted an article in the Weekmail"
msgstr "Article posté avec succès dans le Weekmail"
-#: sith/settings.py:552
+#: sith/settings.py:554
msgid "You successfully edited an article in the Weekmail"
msgstr "Article édité avec succès dans le Weekmail"
-#: sith/settings.py:553
+#: sith/settings.py:555
msgid "You successfully sent the Weekmail"
msgstr "Weekmail envoyé avec succès"
@@ -4787,5 +4815,8 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée."
msgid "Maximum characters: %(max_length)s"
msgstr "Nombre de caractères max: %(max_length)s"
+#~ msgid "Record regularization"
+#~ msgstr "Régularization des consignes"
+
#~ msgid "Logo"
#~ msgstr "Logo"