Merge branch 'elections' into 'master'

Amélioration des élections

See merge request !79
This commit is contained in:
Skia 2017-06-07 19:41:35 +02:00
commit 99ed1c0c79
11 changed files with 211 additions and 118 deletions

View File

@ -72,3 +72,23 @@
<a href="{{ url("core:user_godfathers_delete", user_id=profile.id, godfather_id=godfather.id, is_father=is_father) }}">{% trans %}Delete{% endtrans %}</a> <a href="{{ url("core:user_godfathers_delete", user_id=profile.id, godfather_id=godfather.id, is_father=is_father) }}">{% trans %}Delete{% endtrans %}</a>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% macro paginate(page_obj, paginator) %}
{% if page_obj.has_previous() %}
<a href="?page={{ page_obj.previous_page_number() }}">{% trans %}Previous{% endtrans %}</a>
{% else %}
<span class="disabled">{% trans %}Previous{% endtrans %}</span>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<span class="active">{{ i }} <span class="sr-only">({% trans %}current{% endtrans %})</span></span>
{% else %}
<a href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next() %}
<a href="?page={{ page_obj.next_page_number() }}">{% trans %}Next{% endtrans %}</a>
{% else %}
<span class="disabled">{% trans %}Next{% endtrans %}</span>
{% endif %}
{% endmacro %}

View File

@ -103,6 +103,7 @@
<h4>{% trans %}Elections{% endtrans %}</h4> <h4>{% trans %}Elections{% endtrans %}</h4>
<ul> <ul>
<li><a href="{{ url('election:list') }}">{% trans %}See available elections{% endtrans %}</a></li> <li><a href="{{ url('election:list') }}">{% trans %}See available elections{% endtrans %}</a></li>
<li><a href="{{ url('election:list_archived') }}">{% trans %}See archived elections{% endtrans %}</a></li>
{%- if user.is_subscribed -%} {%- if user.is_subscribed -%}
<li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li> <li><a href="{{ url('election:create') }}">{% trans %}Create a new election{% endtrans %}</a></li>
{%- endif -%} {%- endif -%}

View File

@ -1,5 +1,5 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import user_profile_link %} {% from 'core/macros.jinja' import user_profile_link, paginate %}
{% block title %} {% block title %}
{% trans %}Cash register summary list{% endtrans %} {% trans %}Cash register summary list{% endtrans %}
@ -57,23 +57,7 @@
</table> </table>
<br> <br>
{% if is_paginated %} {% if is_paginated %}
{% if page_obj.has_previous() %} {{ paginate(page_obj, paginator) }}
<a href="?page={{ page_obj.previous_page_number() }}">{% trans %}Previous{% endtrans %}</a>
{% else %}
<span class="disabled">{% trans %}Previous{% endtrans %}</span>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<span class="active">{{ i }} <span class="sr-only">({% trans %}current{% endtrans %})</span></span>
{% else %}
<a href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next() %}
<a href="?page={{ page_obj.next_page_number() }}">{% trans %}Next{% endtrans %}</a>
{% else %}
<span class="disabled">{% trans %}Next{% endtrans %}</span>
{% endif %}
{% endif %} {% endif %}
{% else %} {% else %}
{% trans %}There is no cash register summary in this website.{% endtrans %} {% trans %}There is no cash register summary in this website.{% endtrans %}

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('election', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='election',
name='archived',
field=models.BooleanField(verbose_name='archived', default=False),
),
]

View File

@ -1,9 +1,7 @@
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.conf import settings
from datetime import timedelta
from core.models import User, Group from core.models import User, Group
@ -18,11 +16,24 @@ class Election(models.Model):
start_date = models.DateTimeField(_('start date'), blank=False) start_date = models.DateTimeField(_('start date'), blank=False)
end_date = models.DateTimeField(_('end date'), blank=False) end_date = models.DateTimeField(_('end date'), blank=False)
edit_groups = models.ManyToManyField(Group, related_name="editable_elections", verbose_name=_("edit groups"), blank=True) edit_groups = models.ManyToManyField(
view_groups = models.ManyToManyField(Group, related_name="viewable_elections", verbose_name=_("view groups"), blank=True) Group, related_name="editable_elections",
vote_groups = models.ManyToManyField(Group, related_name="votable_elections", verbose_name=_("vote groups"), blank=True) verbose_name=_("edit groups"), blank=True)
candidature_groups = models.ManyToManyField(Group, related_name="candidate_elections", verbose_name=_("candidature groups"), blank=True)
view_groups = models.ManyToManyField(
Group, related_name="viewable_elections",
verbose_name=_("view groups"), blank=True)
vote_groups = models.ManyToManyField(
Group, related_name="votable_elections",
verbose_name=_("vote groups"), blank=True)
candidature_groups = models.ManyToManyField(
Group, related_name="candidate_elections",
verbose_name=_("candidature groups"), blank=True)
voters = models.ManyToManyField(User, verbose_name=('voters'), related_name='voted_elections') voters = models.ManyToManyField(User, verbose_name=('voters'), related_name='voted_elections')
archived = models.BooleanField(_("archived"), default=False)
def __str__(self): def __str__(self):
return self.title return self.title
@ -99,8 +110,7 @@ class Role(models.Model):
if total_vote == 0: if total_vote == 0:
results['blank vote'] = {'vote': 0, 'percent': 0} results['blank vote'] = {'vote': 0, 'percent': 0}
else: else:
results['blank vote'] = {'vote': total_vote - non_blank, results['blank vote'] = {'vote': total_vote - non_blank, 'percent': (total_vote - non_blank) * 100 / total_vote}
'percent': (total_vote - non_blank) * 100 / total_vote}
return results return results
@property @property

View File

@ -279,6 +279,7 @@ th {
<a href="{{url('election:update_role', role_id=role.id)}}">{% trans %}Edit{% endtrans %}</a> <a href="{{url('election:update_role', role_id=role.id)}}">{% trans %}Edit{% endtrans %}</a>
<a href="{{url('election:delete_role', role_id=role.id)}}">{% trans %}Delete{% endtrans %}</a> <a href="{{url('election:delete_role', role_id=role.id)}}">{% trans %}Delete{% endtrans %}</a>
{%- endif -%} {%- endif -%}
<br><span>{{ role.description }}</span>
{%- if role.max_choice > 1 and not election.has_voted(user) and election.can_vote(user) %} {%- if role.max_choice > 1 and not election.has_voted(user) and election.can_vote(user) %}
<strong class="role__multiple-choices-label">{% trans %}You may choose up to{% endtrans %} {{ role.max_choice }} {% trans %}people.{% endtrans %}</strong> <strong class="role__multiple-choices-label">{% trans %}You may choose up to{% endtrans %} {{ role.max_choice }} {% trans %}people.{% endtrans %}</strong>
{%- endif %} {%- endif %}
@ -373,6 +374,9 @@ th {
{% endif %} {% endif %}
<a href="{{ url('election:update', election_id=object.id) }}">{% trans %}Edit{% endtrans %}</a> <a href="{{ url('election:update', election_id=object.id) }}">{% trans %}Edit{% endtrans %}</a>
{%- endif %} {%- endif %}
{%- if user.is_root %}
<a href="{{ url('election:delete', election_id=object.id) }}">{% trans %}Delete{% endtrans %}</a>
{%- endif %}
</section> </section>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,5 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import paginate %}
{% block title %} {% block title %}
{%- trans %}Election list{% endtrans %} {%- trans %}Election list{% endtrans %}
@ -44,5 +45,8 @@
<p>{{ election.description }}</p> <p>{{ election.description }}</p>
</section> </section>
{%- endfor %} {%- endfor %}
{% if is_paginated %}
{{ paginate(page_obj, paginator) }}
{% endif %}
{%- endblock %} {%- endblock %}

View File

@ -1,9 +1,7 @@
from django.test import Client, TestCase from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import Group
from django.core.management import call_command from django.core.management import call_command
from django.conf import settings from django.conf import settings
from datetime import date, datetime
from core.models import User, Group from core.models import User, Group
from election.models import Election from election.models import Election
@ -15,8 +13,10 @@ class MainElection(TestCase):
self.election = Election.objects.all().first() self.election = Election.objects.all().first()
self.public_group = Group.objects.get(id=settings.SITH_GROUP_PUBLIC_ID) self.public_group = Group.objects.get(id=settings.SITH_GROUP_PUBLIC_ID)
self.subscriber_group = Group.objects.get(name=settings.SITH_MAIN_MEMBERS_GROUP) self.subscriber_group = Group.objects.get(
self.ae_board_group = Group.objects.get(name=settings.SITH_MAIN_BOARD_GROUP) name=settings.SITH_MAIN_MEMBERS_GROUP)
self.ae_board_group = Group.objects.get(
name=settings.SITH_MAIN_BOARD_GROUP)
self.sli = User.objects.get(username='sli') self.sli = User.objects.get(username='sli')
self.subscriber = User.objects.get(username='subscriber') self.subscriber = User.objects.get(username='subscriber')
self.public = User.objects.get(username='public') self.public = User.objects.get(username='public')
@ -29,9 +29,9 @@ class ElectionDetailTest(MainElection):
self.election.save() self.election.save()
self.client.login(username=self.public.username, password='plop') self.client.login(username=self.public.username, password='plop')
response_get = self.client.get(reverse('election:detail', response_get = self.client.get(reverse('election:detail',
args=str(self.election.id))) args=str(self.election.id)))
response_post = self.client.get(reverse('election:detail', response_post = self.client.get(reverse('election:detail',
args=str(self.election.id))) args=str(self.election.id)))
self.assertTrue(response_get.status_code == 403) self.assertTrue(response_get.status_code == 403)
self.assertTrue(response_post.status_code == 403) self.assertTrue(response_post.status_code == 403)
self.election.view_groups.remove(self.subscriber_group) self.election.view_groups.remove(self.subscriber_group)
@ -41,9 +41,9 @@ class ElectionDetailTest(MainElection):
def test_permisson_granted(self): def test_permisson_granted(self):
self.client.login(username=self.public.username, password='plop') self.client.login(username=self.public.username, password='plop')
response_get = self.client.get(reverse('election:detail', response_get = self.client.get(reverse('election:detail',
args=str(self.election.id))) args=str(self.election.id)))
response_post = self.client.post(reverse('election:detail', response_post = self.client.post(reverse('election:detail',
args=str(self.election.id))) args=str(self.election.id)))
self.assertFalse(response_get.status_code == 403) self.assertFalse(response_get.status_code == 403)
self.assertFalse(response_post.status_code == 403) self.assertFalse(response_post.status_code == 403)
self.assertTrue('La roue tourne' in str(response_get.content)) self.assertTrue('La roue tourne' in str(response_get.content))
@ -53,8 +53,8 @@ class ElectionUpdateView(MainElection):
def test_permission_denied(self): def test_permission_denied(self):
self.client.login(username=self.subscriber.username, password='plop') self.client.login(username=self.subscriber.username, password='plop')
response_get = self.client.get(reverse('election:update', response_get = self.client.get(reverse('election:update',
args=str(self.election.id))) args=str(self.election.id)))
response_post = self.client.post(reverse('election:update', response_post = self.client.post(reverse('election:update',
args=str(self.election.id))) args=str(self.election.id)))
self.assertTrue(response_get.status_code == 403) self.assertTrue(response_get.status_code == 403)
self.assertTrue(response_post.status_code == 403) self.assertTrue(response_post.status_code == 403)

View File

@ -4,8 +4,10 @@ from election.views import *
urlpatterns = [ urlpatterns = [
url(r'^$', ElectionsListView.as_view(), name='list'), url(r'^$', ElectionsListView.as_view(), name='list'),
url(r'^archived$', ElectionListArchivedView.as_view(), name='list_archived'),
url(r'^add$', ElectionCreateView.as_view(), name='create'), url(r'^add$', ElectionCreateView.as_view(), name='create'),
url(r'^(?P<election_id>[0-9]+)/edit$', ElectionUpdateView.as_view(), name='update'), url(r'^(?P<election_id>[0-9]+)/edit$', ElectionUpdateView.as_view(), name='update'),
url(r'^(?P<election_id>[0-9]+)/delete$', ElectionDeleteView.as_view(), name='delete'),
url(r'^(?P<election_id>[0-9]+)/list/add$', ElectionListCreateView.as_view(), name='create_list'), url(r'^(?P<election_id>[0-9]+)/list/add$', ElectionListCreateView.as_view(), name='create_list'),
url(r'^(?P<election_id>[0-9]+)/role/create$', RoleCreateView.as_view(), name='create_role'), url(r'^(?P<election_id>[0-9]+)/role/create$', RoleCreateView.as_view(), name='create_role'),
url(r'^(?P<role_id>[0-9]+)/role/edit$', RoleUpdateView.as_view(), name='update_role'), url(r'^(?P<role_id>[0-9]+)/role/edit$', RoleUpdateView.as_view(), name='update_role'),

View File

@ -1,19 +1,16 @@
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import get_object_or_404
from django.views.generic import ListView, DetailView, RedirectView from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView from django.views.generic.edit import UpdateView, CreateView
from django.core.urlresolvers import reverse_lazy, reverse from django.views.generic.edit import DeleteView, FormView
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.forms.models import modelform_factory from django.core.exceptions import PermissionDenied
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured from django.db import transaction
from django.db import DataError, transaction
from django.forms import CheckboxSelectMultiple from django.forms import CheckboxSelectMultiple
from django.utils import timezone
from django.conf import settings
from django import forms from django import forms
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin from core.views import CanViewMixin, CanEditMixin, CanCreateMixin
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.views.generic.edit import FormMixin
from core.views.forms import SelectDateTime from core.views.forms import SelectDateTime
from election.models import Election, Role, Candidature, ElectionList, Vote from election.models import Election, Role, Candidature, ElectionList, Vote
@ -27,12 +24,14 @@ class LimitedCheckboxField(forms.ModelMultipleChoiceField):
Used to replace ModelMultipleChoiceField but with Used to replace ModelMultipleChoiceField but with
automatic backend verification automatic backend verification
""" """
def __init__(self, queryset, max_choice, required=True, widget=None, label=None,
initial=None, help_text='', *args, **kwargs): def __init__(self, queryset, max_choice, required=True, widget=None,
label=None, initial=None, help_text='', *args, **kwargs):
self.max_choice = max_choice self.max_choice = max_choice
widget = forms.CheckboxSelectMultiple() widget = forms.CheckboxSelectMultiple()
super(LimitedCheckboxField, self).__init__(queryset, None, required, widget, label, super(LimitedCheckboxField,
initial, help_text, *args, **kwargs) self).__init__(queryset, None, required, widget,
label, initial, help_text, *args, **kwargs)
def clean(self, value): def clean(self, value):
qs = super(LimitedCheckboxField, self).clean(value) qs = super(LimitedCheckboxField, self).clean(value)
@ -79,7 +78,8 @@ class VoteForm(forms.Form):
self.fields[role.title] = LimitedCheckboxField(cand, role.max_choice, required=False) self.fields[role.title] = LimitedCheckboxField(cand, role.max_choice, required=False)
else: else:
self.fields[role.title] = forms.ModelChoiceField(cand, required=False, self.fields[role.title] = forms.ModelChoiceField(cand, required=False,
widget=forms.RadioSelect(), empty_label=_("Blank vote")) widget=forms.RadioSelect(),
empty_label=_("Blank vote"))
class RoleForm(forms.ModelForm): class RoleForm(forms.ModelForm):
@ -105,7 +105,7 @@ class RoleForm(forms.ModelForm):
class ElectionListForm(forms.ModelForm): class ElectionListForm(forms.ModelForm):
class Meta: class Meta:
model = ElectionList model = ElectionList
fields = ('title','election') fields = ('title', 'election')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
election_id = kwargs.pop('election_id', None) election_id = kwargs.pop('election_id', None)
@ -117,8 +117,11 @@ class ElectionListForm(forms.ModelForm):
class ElectionForm(forms.ModelForm): class ElectionForm(forms.ModelForm):
class Meta: class Meta:
model = Election model = Election
fields = ['title', 'description', 'start_candidature', 'end_candidature', 'start_date', 'end_date', fields = ['title', 'description', 'archived',
'edit_groups', 'view_groups', 'vote_groups', 'candidature_groups'] 'start_candidature', 'end_candidature',
'start_date', 'end_date',
'edit_groups', 'view_groups',
'vote_groups', 'candidature_groups']
widgets = { widgets = {
'edit_groups': CheckboxSelectMultiple, 'edit_groups': CheckboxSelectMultiple,
'view_groups': CheckboxSelectMultiple, 'view_groups': CheckboxSelectMultiple,
@ -127,10 +130,14 @@ class ElectionForm(forms.ModelForm):
'candidature_groups': CheckboxSelectMultiple 'candidature_groups': CheckboxSelectMultiple
} }
start_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start date"), widget=SelectDateTime, required=True) start_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start date"),
end_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"), widget=SelectDateTime, required=True) widget=SelectDateTime, required=True)
start_candidature = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start candidature"), widget=SelectDateTime, required=True) end_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"),
end_candidature = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End candidature"), widget=SelectDateTime, required=True) widget=SelectDateTime, required=True)
start_candidature = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start candidature"),
widget=SelectDateTime, required=True)
end_candidature = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End candidature"),
widget=SelectDateTime, required=True)
# Display elections # Display elections
@ -138,11 +145,29 @@ class ElectionForm(forms.ModelForm):
class ElectionsListView(CanViewMixin, ListView): class ElectionsListView(CanViewMixin, ListView):
""" """
A list with all responsabilities and their candidates A list of all non archived elections visible
""" """
model = Election model = Election
ordering = ["-id"]
paginate_by = 10
template_name = 'election/election_list.jinja' template_name = 'election/election_list.jinja'
def get_queryset(self):
return super(ElectionsListView, self).get_queryset().filter(archived=False).all()
class ElectionListArchivedView(CanViewMixin, ListView):
"""
A list of all archived elections visible
"""
model = Election
ordering = ["-id"]
paginate_by = 10
template_name = 'election/election_list.jinja'
def get_queryset(self):
return super(ElectionListArchivedView, self).get_queryset().filter(archived=True).all()
class ElectionDetailView(CanViewMixin, DetailView): class ElectionDetailView(CanViewMixin, DetailView):
""" """
@ -277,7 +302,8 @@ class ElectionCreateView(CanCreateMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
""" """
Allow every users that had passed the dispatch to create an election Allow every users that had passed the dispatch
to create an election
""" """
return super(CreateView, self).form_valid(form) return super(CreateView, self).form_valid(form)
@ -372,16 +398,20 @@ class ElectionUpdateView(CanEditMixin, UpdateView):
init = {} init = {}
try: try:
init['start_date'] = self.object.start_date.strftime('%Y-%m-%d %H:%M:%S') init['start_date'] = self.object.start_date.strftime('%Y-%m-%d %H:%M:%S')
except:pass except Exception:
pass
try: try:
init['end_date'] = self.object.end_date.strftime('%Y-%m-%d %H:%M:%S') init['end_date'] = self.object.end_date.strftime('%Y-%m-%d %H:%M:%S')
except:pass except Exception:
pass
try: try:
init['start_candidature'] = self.object.start_candidature.strftime('%Y-%m-%d %H:%M:%S') init['start_candidature'] = self.object.start_candidature.strftime('%Y-%m-%d %H:%M:%S')
except:pass except Exception:
pass
try: try:
init['end_candidature'] = self.object.end_candidature.strftime('%Y-%m-%d %H:%M:%S') init['end_candidature'] = self.object.end_candidature.strftime('%Y-%m-%d %H:%M:%S')
except:pass except Exception:
pass
return init return init
def get_success_url(self, **kwargs): def get_success_url(self, **kwargs):
@ -464,6 +494,20 @@ class RoleUpdateView(CanEditMixin, UpdateView):
# Delete Views # Delete Views
class ElectionDeleteView(DeleteView):
model = Election
template_name = 'core/delete_confirm.jinja'
pk_url_kwarg = 'election_id'
def dispatch(self, request, *args, **kwargs):
if request.user.is_root:
return super(ElectionDeleteView, self).dispatch(request, *args, **kwargs)
raise PermissionDenied
def get_success_url(self, **kwargs):
return reverse_lazy('election:list')
class CandidatureDeleteView(CanEditMixin, DeleteView): class CandidatureDeleteView(CanEditMixin, DeleteView):
model = Candidature model = Candidature
template_name = 'core/delete_confirm.jinja' template_name = 'core/delete_confirm.jinja'

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-06 23:25+0200\n" "POT-Creation-Date: 2017-06-07 17:32+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n" "Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -88,12 +88,12 @@ msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s" msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:192 club/models.py:184 counter/models.py:433 #: accounting/models.py:192 club/models.py:184 counter/models.py:433
#: election/models.py:18 launderette/models.py:144 #: election/models.py:17 launderette/models.py:144
msgid "start date" msgid "start date"
msgstr "date de début" msgstr "date de début"
#: accounting/models.py:193 club/models.py:185 counter/models.py:434 #: accounting/models.py:193 club/models.py:185 counter/models.py:434
#: election/models.py:19 #: election/models.py:18
msgid "end date" msgid "end date"
msgstr "date de fin" msgstr "date de fin"
@ -335,6 +335,7 @@ msgstr "Compte en banque : "
#: counter/templates/counter/last_ops.jinja:59 #: counter/templates/counter/last_ops.jinja:59
#: election/templates/election/election_detail.jinja:280 #: election/templates/election/election_detail.jinja:280
#: election/templates/election/election_detail.jinja:329 #: election/templates/election/election_detail.jinja:329
#: election/templates/election/election_detail.jinja:377
#: forum/templates/forum/macros.jinja:21 forum/templates/forum/macros.jinja:123 #: forum/templates/forum/macros.jinja:21 forum/templates/forum/macros.jinja:123
#: launderette/templates/launderette/launderette_admin.jinja:16 #: launderette/templates/launderette/launderette_admin.jinja:16
#: launderette/views.py:178 sas/templates/sas/album.jinja:26 #: launderette/views.py:178 sas/templates/sas/album.jinja:26
@ -830,19 +831,19 @@ msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà." msgstr "Un club avec ce nom UNIX existe déjà."
#: club/models.py:182 counter/models.py:431 counter/models.py:448 #: club/models.py:182 counter/models.py:431 counter/models.py:448
#: eboutic/models.py:38 eboutic/models.py:71 election/models.py:130 #: eboutic/models.py:38 eboutic/models.py:71 election/models.py:147
#: launderette/models.py:111 launderette/models.py:148 sas/models.py:156 #: launderette/models.py:111 launderette/models.py:148 sas/models.py:156
msgid "user" msgid "user"
msgstr "nom d'utilisateur" msgstr "nom d'utilisateur"
#: club/models.py:186 core/models.py:169 election/models.py:129 #: club/models.py:186 core/models.py:169 election/models.py:145
#: election/models.py:145 #: election/models.py:165
msgid "role" msgid "role"
msgstr "rôle" msgstr "rôle"
#: club/models.py:188 core/models.py:61 counter/models.py:101 #: club/models.py:188 core/models.py:61 counter/models.py:101
#: counter/models.py:126 election/models.py:15 election/models.py:82 #: counter/models.py:126 election/models.py:13 election/models.py:93
#: election/models.py:131 forum/models.py:51 forum/models.py:184 #: election/models.py:148 forum/models.py:51 forum/models.py:184
msgid "description" msgid "description"
msgstr "description" msgstr "description"
@ -1069,6 +1070,7 @@ msgstr "Date de début"
#: club/views.py:196 com/views.py:123 counter/views.py:1020 #: club/views.py:196 com/views.py:123 counter/views.py:1020
#: election/views.py:131 subscription/views.py:50 #: election/views.py:131 subscription/views.py:50
#: election/views.py:149
msgid "End date" msgid "End date"
msgstr "Date de fin" msgstr "Date de fin"
@ -1109,8 +1111,8 @@ msgstr "Hebdomadaire"
msgid "Call" msgid "Call"
msgstr "Appel" msgstr "Appel"
#: com/models.py:60 com/models.py:102 com/models.py:149 election/models.py:14 #: com/models.py:60 com/models.py:102 com/models.py:149 election/models.py:12
#: election/models.py:81 election/models.py:118 forum/models.py:187 #: election/models.py:92 election/models.py:132 forum/models.py:187
#: forum/models.py:234 #: forum/models.py:234
msgid "title" msgid "title"
msgstr "titre" msgstr "titre"
@ -1416,6 +1418,7 @@ msgid "Alert message"
msgstr "Message d'alerte" msgstr "Message d'alerte"
#: com/views.py:122 election/views.py:130 subscription/views.py:47 #: com/views.py:122 election/views.py:130 subscription/views.py:47
#: com/views.py:122 election/views.py:146
msgid "Start date" msgid "Start date"
msgstr "Date de début" msgstr "Date de début"
@ -2145,6 +2148,18 @@ msgstr "Créneau"
msgid "Tokens" msgid "Tokens"
msgstr "Jetons" msgstr "Jetons"
#: core/templates/core/macros.jinja:78 core/templates/core/macros.jinja:80
msgid "Previous"
msgstr "Précédent"
#: core/templates/core/macros.jinja:84
msgid "current"
msgstr "actuel"
#: core/templates/core/macros.jinja:90 core/templates/core/macros.jinja:92
msgid "Next"
msgstr "Suivant"
#: core/templates/core/new_user_email.jinja:2 #: core/templates/core/new_user_email.jinja:2
msgid "" msgid ""
"You're receiving this email because you subscribed to the UTBM student " "You're receiving this email because you subscribed to the UTBM student "
@ -2698,6 +2713,10 @@ msgstr "Élections"
msgid "See available elections" msgid "See available elections"
msgstr "Voir les élections disponibles" msgstr "Voir les élections disponibles"
#: core/templates/core/user_tools.jinja:105
msgid "See archived elections"
msgstr "Voir les élections archivées"
#: core/templates/core/user_tools.jinja:107 #: core/templates/core/user_tools.jinja:107
msgid "Create a new election" msgid "Create a new election"
msgstr "Créer une nouvelle élection" msgstr "Créer une nouvelle élection"
@ -2834,7 +2853,7 @@ msgstr "produit parent"
msgid "buying groups" msgid "buying groups"
msgstr "groupe d'achat" msgstr "groupe d'achat"
#: counter/models.py:140 #: counter/models.py:140 election/models.py:34
msgid "archived" msgid "archived"
msgstr "archivé" msgstr "archivé"
@ -3035,21 +3054,7 @@ msgstr "Coffre vidé"
msgid "yes" msgid "yes"
msgstr "oui" msgstr "oui"
#: counter/templates/counter/cash_summary_list.jinja:61
#: counter/templates/counter/cash_summary_list.jinja:63 #: counter/templates/counter/cash_summary_list.jinja:63
msgid "Previous"
msgstr "Précédent"
#: counter/templates/counter/cash_summary_list.jinja:67
msgid "current"
msgstr "actuel"
#: counter/templates/counter/cash_summary_list.jinja:73
#: counter/templates/counter/cash_summary_list.jinja:75
msgid "Next"
msgstr "Suivant"
#: counter/templates/counter/cash_summary_list.jinja:79
msgid "There is no cash register summary in this website." msgid "There is no cash register summary in this website."
msgstr "Il n'y a pas de relevé de caisse dans ce site web." msgstr "Il n'y a pas de relevé de caisse dans ce site web."
@ -3434,43 +3439,43 @@ msgstr "Retourner à l'eboutic"
msgid "You do not have enough money to buy the basket" msgid "You do not have enough money to buy the basket"
msgstr "Vous n'avez pas assez d'argent pour acheter le panier" msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
#: election/models.py:16 #: election/models.py:15
msgid "start candidature" msgid "start candidature"
msgstr "début des candidatures" msgstr "début des candidatures"
#: election/models.py:17 #: election/models.py:16
msgid "end candidature" msgid "end candidature"
msgstr "fin des candidatures" msgstr "fin des candidatures"
#: election/models.py:21 #: election/models.py:22
msgid "edit groups" msgid "edit groups"
msgstr "groupe d'édition" msgstr "groupe d'édition"
#: election/models.py:22 #: election/models.py:25
msgid "view groups" msgid "view groups"
msgstr "groupe de vue" msgstr "groupe de vue"
#: election/models.py:23 #: election/models.py:28
msgid "vote groups" msgid "vote groups"
msgstr "groupe de vote" msgstr "groupe de vote"
#: election/models.py:24 #: election/models.py:31
msgid "candidature groups" msgid "candidature groups"
msgstr "groupe de candidature" msgstr "groupe de candidature"
#: election/models.py:80 election/models.py:119 #: election/models.py:91 election/models.py:134
msgid "election" msgid "election"
msgstr "élection" msgstr "élection"
#: election/models.py:83 #: election/models.py:94
msgid "max choice" msgid "max choice"
msgstr "nombre de choix maxi" msgstr "nombre de choix maxi"
#: election/models.py:132 #: election/models.py:151
msgid "election list" msgid "election list"
msgstr "liste électorale" msgstr "liste électorale"
#: election/models.py:146 #: election/models.py:167
msgid "candidature" msgid "candidature"
msgstr "candidature" msgstr "candidature"
@ -3498,10 +3503,10 @@ msgstr "Les votes ouvriront "
#: election/templates/election/election_detail.jinja:243 #: election/templates/election/election_detail.jinja:243
#: election/templates/election/election_detail.jinja:247 #: election/templates/election/election_detail.jinja:247
#: election/templates/election/election_list.jinja:31 #: election/templates/election/election_list.jinja:32
#: election/templates/election/election_list.jinja:34 #: election/templates/election/election_list.jinja:35
#: election/templates/election/election_list.jinja:39 #: election/templates/election/election_list.jinja:40
#: election/templates/election/election_list.jinja:42 #: election/templates/election/election_list.jinja:43
#: forum/templates/forum/macros.jinja:137 #: forum/templates/forum/macros.jinja:137
msgid " at " msgid " at "
msgstr " à " msgstr " à "
@ -3518,7 +3523,7 @@ msgstr "Vous avez déjà soumis votre vote."
msgid "You have voted in this election." msgid "You have voted in this election."
msgstr "Vous avez déjà voté pour cette élection." msgstr "Vous avez déjà voté pour cette élection."
#: election/templates/election/election_detail.jinja:266 election/views.py:82 #: election/templates/election/election_detail.jinja:266 election/views.py:90
msgid "Blank vote" msgid "Blank vote"
msgstr "Vote blanc" msgstr "Vote blanc"
@ -3556,44 +3561,44 @@ msgstr "Ajouter une nouvelle liste"
msgid "Add a new role" msgid "Add a new role"
msgstr "Ajouter un nouveau rôle" msgstr "Ajouter un nouveau rôle"
#: election/templates/election/election_list.jinja:4 #: election/templates/election/election_list.jinja:5
msgid "Election list" msgid "Election list"
msgstr "Liste des élections" msgstr "Liste des élections"
#: election/templates/election/election_list.jinja:21 #: election/templates/election/election_list.jinja:22
msgid "Current elections" msgid "Current elections"
msgstr "Élections actuelles" msgstr "Élections actuelles"
#: election/templates/election/election_list.jinja:29 #: election/templates/election/election_list.jinja:30
msgid "Applications open from" msgid "Applications open from"
msgstr "Candidatures ouvertes à partir du" msgstr "Candidatures ouvertes à partir du"
#: election/templates/election/election_list.jinja:32 #: election/templates/election/election_list.jinja:33
#: election/templates/election/election_list.jinja:40 #: election/templates/election/election_list.jinja:41
msgid "to" msgid "to"
msgstr "au" msgstr "au"
#: election/templates/election/election_list.jinja:37 #: election/templates/election/election_list.jinja:38
msgid "Polls open from" msgid "Polls open from"
msgstr "Votes ouverts du" msgstr "Votes ouverts du"
#: election/views.py:44 #: election/views.py:46
msgid "You have selected too much candidates." msgid "You have selected too much candidates."
msgstr "Vous avez sélectionné trop de candidats." msgstr "Vous avez sélectionné trop de candidats."
#: election/views.py:59 #: election/views.py:62
msgid "User to candidate" msgid "User to candidate"
msgstr "Utilisateur se présentant" msgstr "Utilisateur se présentant"
#: election/views.py:102 #: election/views.py:112
msgid "This role already exists for this election" msgid "This role already exists for this election"
msgstr "Ce rôle existe déjà pour cette élection" msgstr "Ce rôle existe déjà pour cette élection"
#: election/views.py:132 #: election/views.py:152
msgid "Start candidature" msgid "Start candidature"
msgstr "Début des candidatures" msgstr "Début des candidatures"
#: election/views.py:133 #: election/views.py:155
msgid "End candidature" msgid "End candidature"
msgstr "Fin des candidatures" msgstr "Fin des candidatures"