Date: Sun, 30 Dec 2018 16:28:03 +0100
Subject: [PATCH 18/73] Paginator styling and go to id feature
---
machines/templates/machines/aff_machines.html | 4 +-
templates/pagination.html | 59 ++++++++++++++-----
2 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html
index 60e1a57a..d5a83ed3 100644
--- a/machines/templates/machines/aff_machines.html
+++ b/machines/templates/machines/aff_machines.html
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if machines_list.paginator %}
- {% include "pagination.html" with list=machines_list %}
+ {% include "pagination.html" with list=machines_list go_to_id="machines" %}
{% endif %}
@@ -215,6 +215,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if machines_list.paginator %}
- {% include "pagination.html" with list=machines_list %}
+ {% include "pagination.html" with list=machines_list go_to_id="machines" %}
{% endif %}
diff --git a/templates/pagination.html b/templates/pagination.html
index cf488c5d..5ecced6d 100644
--- a/templates/pagination.html
+++ b/templates/pagination.html
@@ -23,23 +23,52 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load url_insert_param %}
+{% load i18n %}
{% if list.paginator.num_pages > 1 %}
-
{% endif %}
-
From e1729235780fd9a4523a2534ec39a1a038082370 Mon Sep 17 00:00:00 2001
From: Gabriel Detraz
Date: Sun, 30 Dec 2018 00:18:35 +0100
Subject: [PATCH 19/73] Fix #103
---
topologie/models.py | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/topologie/models.py b/topologie/models.py
index cd191d7e..25a7bda6 100644
--- a/topologie/models.py
+++ b/topologie/models.py
@@ -281,31 +281,18 @@ class Switch(AclMixin, Machine):
def create_ports(self, begin, end):
""" Crée les ports de begin à end si les valeurs données
sont cohérentes. """
-
- s_begin = s_end = 0
- nb_ports = self.ports.count()
- if nb_ports > 0:
- ports = self.ports.order_by('port').values('port')
- s_begin = ports.first().get('port')
- s_end = ports.last().get('port')
-
if end < begin:
raise ValidationError(_("The end port is less than the start"
" port."))
- if end - begin > self.number:
+ ports_to_create = list(range(begin, end + 1))
+ existing_ports = Port.objects.filter(switch=self.switch).values_list('port', flat=True)
+ non_existing_ports = list(set(ports_to_create) - set(existing_ports))
+
+ if len(non_existing_ports) + existing_ports.count() > self.number:
raise ValidationError(_("This switch can't have that many ports."))
- begin_range = range(begin, s_begin)
- end_range = range(s_end+1, end+1)
- for i in itertools.chain(begin_range, end_range):
- port = Port()
- port.switch = self
- port.port = i
- try:
- with transaction.atomic(), reversion.create_revision():
- port.save()
- reversion.set_comment(_("Creation"))
- except IntegrityError:
- ValidationError(_("Creation of an existing port."))
+ with transaction.atomic(), reversion.create_revision():
+ reversion.set_comment(_("Creation"))
+ Port.objects.bulk_create([Port(switch=self.switch, port=port_id) for port_id in non_existing_ports])
def main_interface(self):
""" Returns the 'main' interface of the switch
From 92e6ae45ad22413f370008f5fb5a83b81a77e9ee Mon Sep 17 00:00:00 2001
From: Gabriel Detraz
Date: Sun, 30 Dec 2018 00:34:17 +0100
Subject: [PATCH 20/73] Refactor aussi la fonction du views pour la route
---
topologie/views.py | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/topologie/views.py b/topologie/views.py
index a4db2dc6..d852177d 100644
--- a/topologie/views.py
+++ b/topologie/views.py
@@ -533,19 +533,14 @@ def create_ports(request, switchid):
except Switch.DoesNotExist:
messages.error(request, _("Nonexistent switch"))
return redirect(reverse('topologie:index'))
-
- s_begin = s_end = 0
- nb_ports = switch.ports.count()
- if nb_ports > 0:
- ports = switch.ports.order_by('port').values('port')
- s_begin = ports.first().get('port')
- s_end = ports.last().get('port')
-
+
+ first_port = getattr(switch.ports.order_by('port').first(), 'port', 1)
+ s_begin = first_port
+ s_end = switch.number + first_port - 1
port_form = CreatePortsForm(
request.POST or None,
initial={'begin': s_begin, 'end': s_end}
)
-
if port_form.is_valid():
begin = port_form.cleaned_data['begin']
end = port_form.cleaned_data['end']
From 7ddb627b6b0f780334712146e34dc8cdd73efcea Mon Sep 17 00:00:00 2001
From: klafyvel
Date: Sun, 30 Dec 2018 14:27:41 +0100
Subject: [PATCH 21/73] Do not create an useless list since `set` can be
created from any iterable.
---
topologie/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/topologie/models.py b/topologie/models.py
index 25a7bda6..269516ff 100644
--- a/topologie/models.py
+++ b/topologie/models.py
@@ -284,7 +284,7 @@ class Switch(AclMixin, Machine):
if end < begin:
raise ValidationError(_("The end port is less than the start"
" port."))
- ports_to_create = list(range(begin, end + 1))
+ ports_to_create = range(begin, end + 1)
existing_ports = Port.objects.filter(switch=self.switch).values_list('port', flat=True)
non_existing_ports = list(set(ports_to_create) - set(existing_ports))
From c238a9a2fa2dac6febc8bd5a5b01ac3bd25732cd Mon Sep 17 00:00:00 2001
From: klafyvel
Date: Sun, 30 Dec 2018 14:31:36 +0100
Subject: [PATCH 22/73] Remove useless variable in create_ports and give
explicit name to `s_end`.
---
topologie/views.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/topologie/views.py b/topologie/views.py
index d852177d..89d48b0b 100644
--- a/topologie/views.py
+++ b/topologie/views.py
@@ -535,11 +535,10 @@ def create_ports(request, switchid):
return redirect(reverse('topologie:index'))
first_port = getattr(switch.ports.order_by('port').first(), 'port', 1)
- s_begin = first_port
- s_end = switch.number + first_port - 1
+ last_port = switch.number + first_port - 1
port_form = CreatePortsForm(
request.POST or None,
- initial={'begin': s_begin, 'end': s_end}
+ initial={'begin': first_port, 'end': last_port}
)
if port_form.is_valid():
begin = port_form.cleaned_data['begin']
From 71dc9c9bd1ec3468bc49f712723267b09ef65e7d Mon Sep 17 00:00:00 2001
From: Hugo LEVY-FALK
Date: Tue, 1 Jan 2019 19:32:40 +0100
Subject: [PATCH 23/73] Remove code about radius in OptionalTopology edit form.
---
preferences/forms.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/preferences/forms.py b/preferences/forms.py
index 1126b399..fd052edd 100644
--- a/preferences/forms.py
+++ b/preferences/forms.py
@@ -115,11 +115,6 @@ class EditOptionalTopologieForm(ModelForm):
prefix=prefix,
**kwargs
)
- self.fields['radius_general_policy'].label = _("RADIUS general policy")
- self.fields['vlan_decision_ok'].label = _("VLAN for machines accepted"
- " by RADIUS")
- self.fields['vlan_decision_nok'].label = _("VLAN for machines rejected"
- " by RADIUS")
self.initial['automatic_provision_switchs'] = Switch.objects.filter(automatic_provision=True).order_by('interface__domain__name')
From 21f54486b20e8413153e53d00fa5cab3132307c9 Mon Sep 17 00:00:00 2001
From: Hugo LEVY-FALK
Date: Tue, 1 Jan 2019 20:17:27 +0100
Subject: [PATCH 24/73] Fix switch creation
---
topologie/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/topologie/models.py b/topologie/models.py
index 269516ff..e08a1b21 100644
--- a/topologie/models.py
+++ b/topologie/models.py
@@ -304,7 +304,7 @@ class Switch(AclMixin, Machine):
@cached_property
def get_name(self):
- return self.name or self.main_interface().domain.name
+ return self.name or getattr(self.main_interface(), 'domain', 'Unknown')
@cached_property
def get_radius_key(self):
From c76a5d237679e707b224b7867919a35e7347349d Mon Sep 17 00:00:00 2001
From: Maxime Bombar
Date: Tue, 1 Jan 2019 16:11:02 +0100
Subject: [PATCH 25/73] Prevents from crashing where there is no defined
prefix_v6
---
machines/models.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/machines/models.py b/machines/models.py
index 888e4ac0..1cf840d7 100644
--- a/machines/models.py
+++ b/machines/models.py
@@ -1380,7 +1380,10 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
.filter(interface=self.interface, slaac_ip=True)
.exclude(id=self.id)):
raise ValidationError(_("A SLAAC IP address is already registered."))
- prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8')
+ try:
+ prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8')
+ except AttributeError: # Prevents from crashing when there is no defined prefix_v6
+ prefix_v6 = None
if prefix_v6:
if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] !=
IPv6Address(prefix_v6).exploded[:20]):
From 4ac403ec29fbfc1ec8bec76deeed7b8380948d68 Mon Sep 17 00:00:00 2001
From: Gabriel Detraz
Date: Wed, 2 Jan 2019 15:18:40 +0100
Subject: [PATCH 26/73] Hotfix boostrapform
---
cotisations/templates/cotisations/facture.html | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html
index ff9ed837..8a1a6d7a 100644
--- a/cotisations/templates/cotisations/facture.html
+++ b/cotisations/templates/cotisations/facture.html
@@ -44,8 +44,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% blocktrans %}Current balance: {{ balance }} €{% endblocktrans %}
{% endif %}
+{% if factureform %}
{% bootstrap_form_errors factureform %}
+{% endif %}
+{% if discount_form %}
{% bootstrap_form_errors discount_form %}
+{% endif %}
{% trans "Users general permissions" %}
diff --git a/users/forms.py b/users/forms.py
index effcc60c..d4110dcd 100644
--- a/users/forms.py
+++ b/users/forms.py
@@ -117,6 +117,7 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm):
"""Changement du mot de passe"""
user = super(PassForm, self).save(commit=False)
user.set_password(self.cleaned_data.get("passwd1"))
+ user.set_active()
user.save()
diff --git a/users/models.py b/users/models.py
index e4c25956..c5287fb6 100755
--- a/users/models.py
+++ b/users/models.py
@@ -337,7 +337,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
def set_active(self):
"""Enable this user if he subscribed successfully one time before"""
if self.state == self.STATE_NOT_YET_ACTIVE:
- if self.facture_set.filter(valid=True).filter(Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists():
+ if self.facture_set.filter(valid=True).filter(Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists() or OptionalUser.get_cached_value('all_users_active'):
self.state = self.STATE_ACTIVE
self.save()
From 84889388c9bec59ec1dfd7007d2d86dddfe03cd3 Mon Sep 17 00:00:00 2001
From: Gabriel Detraz
Date: Sat, 5 Jan 2019 20:11:36 +0100
Subject: [PATCH 40/73] Avoid crash when 'email' field is not here
---
users/models.py | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/users/models.py b/users/models.py
index c5287fb6..a2798207 100755
--- a/users/models.py
+++ b/users/models.py
@@ -1026,17 +1026,12 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
):
raise ValidationError("This pseudo is already in use.")
if not self.local_email_enabled and not self.email and not (self.state == self.STATE_ARCHIVE):
- raise ValidationError(
- {'email': (
- _("There is neither a local email address nor an external"
+ raise ValidationError(_("There is neither a local email address nor an external"
" email address for this user.")
- ), }
)
if self.local_email_redirect and not self.email:
- raise ValidationError(
- {'local_email_redirect': (
- _("You can't redirect your local emails if no external email"
- " address has been set.")), }
+ raise ValidationError(_("You can't redirect your local emails if no external email"
+ " address has been set.")
)
def __str__(self):
From 2524c09e8e5036398076e6a2ebb5ba155d0f7a0b Mon Sep 17 00:00:00 2001
From: Grizzly
Date: Mon, 10 Dec 2018 20:50:48 +0000
Subject: [PATCH 41/73] Exclusion d'users, anonymisation machine et domaines
---
users/management/commands/anonymize.py | 114 +++++++++++++++----------
1 file changed, 68 insertions(+), 46 deletions(-)
diff --git a/users/management/commands/anonymize.py b/users/management/commands/anonymize.py
index d2632576..e057cf24 100644
--- a/users/management/commands/anonymize.py
+++ b/users/management/commands/anonymize.py
@@ -1,71 +1,93 @@
from django.core.management.base import BaseCommand
from users.models import User, School, Adherent, Club
+from machines.models import Domain, Machine
from django.db.models import F, Value
+from django.db.models import Q
from django.db.models.functions import Concat
from re2o.login import hashNT, makeSecret
import os, random, string
+from random import randint
class Command(BaseCommand):
- help="Anonymize the data in the database in order to use them on critical servers (dev, personnal...). Every information will be overwritten using non-personnal informations. This script must follow any modification of the database."
+ help="Anonymize the data in the database in order to use them on critical servers (dev, personnal...). Every information will be overwritten using non-personnal informations. This script must follow any modification of the database.\nOptionnal argument: {id|id|id|...} to exclude users from anonymisation"
+
+ def add_arguments(self, parser):
+ parser.add_argument('user_id', nargs='+', type=int, help='User ID')
def handle(self, *args, **kwargs):
+ users_ids = kwargs['user_id']
+ for user_id in users_ids:
+ self.stdout.write("User: {} will not be anonymised".format(User.objects.filter(id=user_id).get().name))
+
+ self.stdout.write(self.style.WARNING('\nDISCLAIMER\nThis function will make your database unusable for production. Are you sure you want to run this ?(doit): '))
+ if(input()=="doit"):
- total = Adherent.objects.count()
- self.stdout.write("Starting anonymizing the {} users data.".format(total))
-
- u = User.objects.all()
- a = Adherent.objects.all()
- c = Club.objects.all()
+ total = Adherent.objects.count()
+ self.stdout.write("Starting anonymizing the {} users data.".format(total))
+
+ u = User.objects.filter(~Q(id__in=users_ids))
+ a = Adherent.objects.filter(~Q(id__in=users_ids))
+ c = Club.objects.filter(~Q(id__in=users_ids))
+ d = Domain.objects.all()
+ m = Machine.objects.filter(~Q(user_id__in=users_ids))
- self.stdout.write('Supression de l\'école...')
- # Create a fake School to put everyone in it.
- ecole = School(name="Ecole des Ninja")
- ecole.save()
- u.update(school=ecole)
- self.stdout.write(self.style.SUCCESS('done ...'))
+ self.stdout.write('Supression de l\'école...')
+ # Create a fake School to put everyone in it.
+ ecole = School(name="Ecole des Ninja")
+ ecole.save()
+ u.update(school=ecole)
+ self.stdout.write(self.style.SUCCESS('done ...'))
- self.stdout.write('Supression des chambres...')
- a.update(room=None)
- c.update(room=None)
- self.stdout.write(self.style.SUCCESS('done ...'))
+ self.stdout.write('Supression des chambres...')
+ a.update(room=None)
+ c.update(room=None)
+ self.stdout.write(self.style.SUCCESS('done ...'))
- self.stdout.write('Supression des mails...')
- u.update(email='example@example.org',
- local_email_redirect = False,
- local_email_enabled=False)
- self.stdout.write(self.style.SUCCESS('done ...'))
+ self.stdout.write('Supression des mails...')
+ u.update(email='example@example.org',
+ local_email_redirect = False,
+ local_email_enabled=False)
+ self.stdout.write(self.style.SUCCESS('done ...'))
- self.stdout.write('Supression des noms, prenoms, pseudo, telephone, commentaire...')
- a.update(name=Concat(Value('name of '), 'id'))
- self.stdout.write(self.style.SUCCESS('done name'))
+ self.stdout.write('Supression des noms, prenoms, pseudo, telephone, commentaire...')
+ a.update(name=Concat(Value('name of '), 'id'))
+ self.stdout.write(self.style.SUCCESS('done name'))
- a.update(surname=Concat(Value('surname of '), 'id'))
- self.stdout.write(self.style.SUCCESS('done surname'))
+ a.update(surname=Concat(Value('surname of '), 'id'))
+ self.stdout.write(self.style.SUCCESS('done surname'))
- u.update(pseudo=F('id'))
- self.stdout.write(self.style.SUCCESS('done pseudo'))
+ u.update(pseudo=F('id'))
+ self.stdout.write(self.style.SUCCESS('done pseudo'))
- a.update(telephone=Concat(Value('phone of '), 'id'))
- self.stdout.write(self.style.SUCCESS('done phone'))
+ a.update(telephone=Concat(Value('phone of '), 'id'))
+ self.stdout.write(self.style.SUCCESS('done phone'))
- a.update(comment=Concat(Value('commentaire of '), 'id'))
- self.stdout.write(self.style.SUCCESS('done ...'))
+ a.update(comment=Concat(Value('commentaire of '), 'id'))
+ self.stdout.write(self.style.SUCCESS('done ...'))
+
+ self.stdout.write('Renommage des machines...')
+ m.update(name=Concat(Value('Machine '),F('id'),Value(' of '),F('user_id')))
+ d.update(name=Concat(Value('Domaine id '),F('id')))
+ self.stdout.write(self.style.SUCCESS('done ...'))
- self.stdout.write('Unification du mot de passe...')
- # Define the password
- chars = string.ascii_letters + string.digits + '!@#$%^&*()'
- taille = 20
- random.seed = (os.urandom(1024))
- password = ""
- for i in range(taille):
- password+=random.choice(chars)
+ self.stdout.write('Unification du mot de passe...')
+ # Define the password
+ chars = string.ascii_letters + string.digits + '!@#$%^&*()'
+ taille = 20
+ random.seed = (os.urandom(1024))
+ password = ""
+ for i in range(taille):
+ password+=random.choice(chars)
- self.stdout.write(self.style.HTTP_NOT_MODIFIED('The password will be: {}'.format(password)))
+ self.stdout.write(self.style.HTTP_NOT_MODIFIED('The password will be: {}'.format(password)))
- u.update(pwd_ntlm = hashNT(password))
- u.update(password = makeSecret(password))
- self.stdout.write(self.style.SUCCESS('done...'))
+ u.update(pwd_ntlm = hashNT(password))
+ u.update(password = makeSecret(password))
+ self.stdout.write(self.style.SUCCESS('done...'))
- self.stdout.write("Data anonymized!")
+ self.stdout.write("Data anonymized!")
+
+ else:
+ self.stdout.write("Anonymisation aborted")
From cbd85ff0eb32ed59af3b90c6ba30e235e2d3db70 Mon Sep 17 00:00:00 2001
From: Grizzly
Date: Wed, 9 Jan 2019 18:14:06 +0000
Subject: [PATCH 42/73] Suppression de l'historique
---
users/management/commands/anonymize.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/users/management/commands/anonymize.py b/users/management/commands/anonymize.py
index e057cf24..a6bce971 100644
--- a/users/management/commands/anonymize.py
+++ b/users/management/commands/anonymize.py
@@ -1,6 +1,7 @@
from django.core.management.base import BaseCommand
from users.models import User, School, Adherent, Club
from machines.models import Domain, Machine
+from reversion.models import Revision
from django.db.models import F, Value
from django.db.models import Q
from django.db.models.functions import Concat
@@ -87,6 +88,10 @@ class Command(BaseCommand):
u.update(password = makeSecret(password))
self.stdout.write(self.style.SUCCESS('done...'))
+ self.stdout.write('Suppression de l\'historique (This may take some time)')
+ Revision.objects.all().delete()
+ self.stdout.write(self.style.SUCCESS('done...'))
+
self.stdout.write("Data anonymized!")
else:
From dc83766b5c1f0080b5c038a6727eb76378d54c2f Mon Sep 17 00:00:00 2001
From: Gabriel Detraz
Date: Thu, 10 Jan 2019 16:10:43 +0100
Subject: [PATCH 43/73] Case insensitive search
---
freeradius_utils/auth.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py
index e605aea5..0e83b610 100644
--- a/freeradius_utils/auth.py
+++ b/freeradius_utils/auth.py
@@ -289,7 +289,7 @@ def check_user_machine_and_register(nas_type, username, mac_address):
Renvoie le mot de passe ntlm de l'user si tout est ok
Utilise pour les authentifications en 802.1X"""
interface = Interface.objects.filter(mac_address=mac_address).first()
- user = User.objects.filter(pseudo=username).first()
+ user = User.objects.filter(pseudo__iexact=username).first()
if not user:
return (False, u"User inconnu", '')
if not user.has_access():
From 4721d8763cbba5e0675af5c68c75e4c74e804831 Mon Sep 17 00:00:00 2001
From: Hugo LEVY-FALK
Date: Fri, 11 Jan 2019 14:10:34 +0100
Subject: [PATCH 44/73] Fix invoice edit page, discount title is only displayed
when needed.
---
cotisations/templates/cotisations/facture.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html
index 8a1a6d7a..efa7b06d 100644
--- a/cotisations/templates/cotisations/facture.html
+++ b/cotisations/templates/cotisations/facture.html
@@ -74,8 +74,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %}
- {% trans "Discount" %}
{% if discount_form %}
+ {% trans "Discount" %}
{% bootstrap_form discount_form %}
{% endif %}
From 2ea0d77eb2349a2946c0475923441701e6513adc Mon Sep 17 00:00:00 2001
From: Hugo LEVY-FALK
Date: Fri, 11 Jan 2019 14:02:32 +0100
Subject: [PATCH 45/73] Fix error message when failing to decode an aes_key.
---
re2o/aes_field.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/re2o/aes_field.py b/re2o/aes_field.py
index 5f50ddd2..eeab5e12 100644
--- a/re2o/aes_field.py
+++ b/re2o/aes_field.py
@@ -82,16 +82,22 @@ class AESEncryptedField(models.CharField):
return None
try:
return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode('utf-8')
- except Exception as e:
- raise ValueError(value)
+ except UnicodeDecodeError as e:
+ raise ValueError(
+ "Could not decode your field %s, your settings.AES_KEY "
+ "is probably wrong." % self.name
+ )
def from_db_value(self, value, *args, **kwargs):
if value is None:
return value
try:
return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode('utf-8')
- except Exception as e:
- raise ValueError(value)
+ except UnicodeDecodeError as e:
+ raise ValueError(
+ "Could not decode your field %s, your settings.AES_KEY "
+ "is probably wrong." % self.name
+ )
def get_prep_value(self, value):
if value is None:
From c92b68872edbce98025beffc0cafce88da6e8223 Mon Sep 17 00:00:00 2001
From: Hugo LEVY-FALK
Date: Fri, 11 Jan 2019 13:43:57 +0100
Subject: [PATCH 46/73] Fix radius options, force to set a vlan when adding a
policy which requires it.
---
preferences/forms.py | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/preferences/forms.py b/preferences/forms.py
index fd052edd..7e644808 100644
--- a/preferences/forms.py
+++ b/preferences/forms.py
@@ -231,6 +231,27 @@ class EditRadiusOptionForm(ModelForm):
model = RadiusOption
fields = '__all__'
+ def clean(self):
+ cleaned_data = super().clean()
+ ignored=('radius_general_policy', 'vlan_decision_ok')
+ fields = (
+ f for f in self.fields.keys()
+ if 'vlan' not in f and f not in ignored
+ )
+ for f in fields:
+ choice = cleaned_data.get(f)
+ vlan = cleaned_data.get(f+'_vlan')
+ if choice == RadiusOption.SET_VLAN and vlan is None:
+ self.add_error(
+ f,
+ _("You chose to set vlan but did not set any VLAN."),
+ )
+ self.add_error(
+ f+'_vlan',
+ _("Please, choose a VLAN."),
+ )
+ return cleaned_data
+
class ServiceForm(ModelForm):
"""Edition, ajout de services sur la page d'accueil"""
From 950272dc189ca88734a84a3f6efc603a809f574f Mon Sep 17 00:00:00 2001
From: Laouen Fernet
Date: Wed, 9 Jan 2019 00:37:45 +0100
Subject: [PATCH 47/73] add translations for api/
---
api/acl.py | 5 ++--
api/authentication.py | 2 +-
api/locale/fr/LC_MESSAGES/django.po | 40 +++++++++++++++++++++++++++++
3 files changed, 44 insertions(+), 3 deletions(-)
create mode 100644 api/locale/fr/LC_MESSAGES/django.po
diff --git a/api/acl.py b/api/acl.py
index 9107a25d..0c336281 100644
--- a/api/acl.py
+++ b/api/acl.py
@@ -28,7 +28,7 @@ done.
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext as _
def _create_api_permission():
@@ -71,4 +71,5 @@ def can_view(user):
'codename': settings.API_PERMISSION_CODENAME
}
can = user.has_perm('%(app_label)s.%(codename)s' % kwargs)
- return can, None if can else _("You cannot see this application.")
+ return can, None if can else _("You don't have the right to see this"
+ " application.")
diff --git a/api/authentication.py b/api/authentication.py
index cbc72b76..d426db24 100644
--- a/api/authentication.py
+++ b/api/authentication.py
@@ -46,6 +46,6 @@ class ExpiringTokenAuthentication(TokenAuthentication):
)
utc_now = datetime.datetime.now(datetime.timezone.utc)
if token.created < utc_now - token_duration:
- raise exceptions.AuthenticationFailed(_('Token has expired'))
+ raise exceptions.AuthenticationFailed(_("The token has expired."))
return token.user, token
diff --git a/api/locale/fr/LC_MESSAGES/django.po b/api/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 00000000..f2d6755e
--- /dev/null
+++ b/api/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,40 @@
+# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
+# se veut agnostique au réseau considéré, de manière à être installable en
+# quelques clics.
+#
+# Copyright © 2018 Maël Kervella
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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 Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.5\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-01-08 23:06+0100\n"
+"PO-Revision-Date: 2019-01-07 01:37+0100\n"
+"Last-Translator: Laouen Fernet \n"
+"Language-Team: \n"
+"Language: fr_FR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: acl.py:74
+msgid "You don't have the right to see this application."
+msgstr "Vous n'avez pas le droit de voir cette application."
+
+#: authentication.py:49
+msgid "The token has expired."
+msgstr "Le jeton a expiré."
From 2012f20352216c73939c92aee3c06ec25b0a54e7 Mon Sep 17 00:00:00 2001
From: Laouen Fernet
Date: Wed, 9 Jan 2019 00:38:53 +0100
Subject: [PATCH 48/73] add translations for cotisations/
---
cotisations/forms.py | 6 +-
cotisations/locale/fr/LC_MESSAGES/django.po | 437 +++++++++++-------
cotisations/models.py | 2 +-
.../payment_methods/note_kfet/views.py | 4 +-
.../templates/cotisations/aff_article.html | 4 +-
.../cotisations/aff_cost_estimate.html | 6 +-
.../cotisations/aff_cotisations.html | 4 +-
.../cotisations/aff_custom_invoice.html | 8 +-
.../templates/cotisations/aff_paiement.html | 4 +-
.../templates/cotisations/control.html | 6 +-
cotisations/templates/cotisations/delete.html | 2 +-
.../templates/cotisations/edit_facture.html | 4 +-
.../templates/cotisations/facture.html | 2 +-
cotisations/templates/cotisations/index.html | 2 +-
.../templates/cotisations/index_article.html | 4 +-
.../templates/cotisations/index_banque.html | 4 +-
.../cotisations/index_cost_estimate.html | 6 +-
.../cotisations/index_custom_invoice.html | 6 +-
.../templates/cotisations/index_paiement.html | 2 +-
.../templates/cotisations/payment.html | 2 +-
.../templates/cotisations/sidebar.html | 20 +-
cotisations/views.py | 8 +-
22 files changed, 323 insertions(+), 220 deletions(-)
diff --git a/cotisations/forms.py b/cotisations/forms.py
index 57bd7355..2eae5287 100644
--- a/cotisations/forms.py
+++ b/cotisations/forms.py
@@ -116,7 +116,7 @@ class DiscountForm(Form):
Form used in oder to create a discount on an invoice.
"""
is_relative = forms.BooleanField(
- label=_("Discount is on percentage"),
+ label=_("Discount is on percentage."),
required=False,
)
discount = forms.DecimalField(
@@ -310,8 +310,8 @@ class RechargeForm(FormRevMixin, Form):
if balance_method.maximum_balance is not None and \
value + self.user.solde > balance_method.maximum_balance:
raise forms.ValidationError(
- _("Requested amount is too high. Your balance can't exceed \
- %(max_online_balance)s €.") % {
+ _("Requested amount is too high. Your balance can't exceed"
+ " %(max_online_balance)s €.") % {
'max_online_balance': balance_method.maximum_balance
}
)
diff --git a/cotisations/locale/fr/LC_MESSAGES/django.po b/cotisations/locale/fr/LC_MESSAGES/django.po
index 15f6a057..2c29dc8d 100644
--- a/cotisations/locale/fr/LC_MESSAGES/django.po
+++ b/cotisations/locale/fr/LC_MESSAGES/django.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-08-18 13:17+0200\n"
+"POT-Creation-Date: 2019-01-12 16:50+0100\n"
"PO-Revision-Date: 2018-03-31 16:09+0002\n"
"Last-Translator: Laouen Fernet \n"
"Language: fr_FR\n"
@@ -33,79 +33,98 @@ msgstr ""
msgid "You don't have the right to view this application."
msgstr "Vous n'avez pas le droit de voir cette application."
-#: forms.py:63 forms.py:274
+#: forms.py:66 forms.py:299
msgid "Select a payment method"
msgstr "Sélectionnez un moyen de paiement"
-#: forms.py:66 models.py:510
+#: forms.py:69 models.py:579
msgid "Member"
msgstr "Adhérent"
-#: forms.py:68
+#: forms.py:71
msgid "Select the proprietary member"
msgstr "Sélectionnez l'adhérent propriétaire"
-#: forms.py:69
+#: forms.py:72
msgid "Validated invoice"
msgstr "Facture validée"
-#: forms.py:82
+#: forms.py:85
msgid "A payment method must be specified."
msgstr "Un moyen de paiement doit être renseigné."
-#: forms.py:96 forms.py:120 templates/cotisations/aff_article.html:33
-#: templates/cotisations/facture.html:61
+#: forms.py:97 templates/cotisations/aff_article.html:33
+#: templates/cotisations/facture.html:67
msgid "Article"
msgstr "Article"
-#: forms.py:100 forms.py:124 templates/cotisations/edit_facture.html:46
+#: forms.py:101 templates/cotisations/edit_facture.html:50
msgid "Quantity"
msgstr "Quantité"
-#: forms.py:154
+#: forms.py:119
+msgid "Discount is on percentage."
+msgstr "La réduction est en pourcentage."
+
+#: forms.py:123 templates/cotisations/facture.html:78
+msgid "Discount"
+msgstr "Réduction"
+
+#: forms.py:140
+#, python-format
+msgid "{}% discount"
+msgstr "{}% de réduction"
+
+#: forms.py:140
+msgid "{}€ discount"
+msgstr "{}€ de réduction"
+
+#: forms.py:179
msgid "Article name"
msgstr "Nom de l'article"
-#: forms.py:164 templates/cotisations/sidebar.html:50
+#: forms.py:189 templates/cotisations/sidebar.html:55
msgid "Available articles"
msgstr "Articles disponibles"
-#: forms.py:192
+#: forms.py:217
msgid "Payment method name"
msgstr "Nom du moyen de paiement"
-#: forms.py:204
+#: forms.py:229
msgid "Available payment methods"
msgstr "Moyens de paiement disponibles"
-#: forms.py:230
+#: forms.py:255
msgid "Bank name"
msgstr "Nom de la banque"
-#: forms.py:242
+#: forms.py:267
msgid "Available banks"
msgstr "Banques disponibles"
-#: forms.py:261
+#: forms.py:286
msgid "Amount"
msgstr "Montant"
-#: forms.py:267 templates/cotisations/aff_cotisations.html:44
+#: forms.py:292 templates/cotisations/aff_cost_estimate.html:42
+#: templates/cotisations/aff_cotisations.html:44
#: templates/cotisations/aff_custom_invoice.html:42
#: templates/cotisations/control.html:66
msgid "Payment method"
msgstr "Moyen de paiement"
-#: forms.py:287
+#: forms.py:313
#, python-format
msgid ""
-"Requested amount is too high. Your balance can't exceed "
+"Requested amount is too high. Your balance can't exceed "
"%(max_online_balance)s €."
msgstr ""
-"Le montant demandé trop grand. Votre solde ne peut excéder "
+"Le montant demandé est trop grand. Votre solde ne peut excéder "
"%(max_online_balance)s €."
-#: models.py:60 templates/cotisations/aff_cotisations.html:48
+#: models.py:60 templates/cotisations/aff_cost_estimate.html:46
+#: templates/cotisations/aff_cotisations.html:48
#: templates/cotisations/aff_custom_invoice.html:46
#: templates/cotisations/control.html:70
msgid "Date"
@@ -133,9 +152,9 @@ msgstr "Peut voir un objet facture"
#: models.py:158
msgid "Can edit all the previous invoices"
-msgstr "Peut modifier toutes les factures existantes"
+msgstr "Peut modifier toutes les factures précédentes"
-#: models.py:160 models.py:305
+#: models.py:160 models.py:373
msgid "invoice"
msgstr "facture"
@@ -156,128 +175,149 @@ msgid ""
"You don't have the right to edit an invoice already controlled or "
"invalidated."
msgstr ""
-"Vous n'avez pas le droit de modifier une facture précedemment contrôlée ou "
+"Vous n'avez pas le droit de modifier une facture précédemment contrôlée ou "
"invalidée."
#: models.py:184
msgid "You don't have the right to delete an invoice."
msgstr "Vous n'avez pas le droit de supprimer une facture."
-#: models.py:186
+#: models.py:187
msgid "You don't have the right to delete this user's invoices."
msgstr "Vous n'avez pas le droit de supprimer les factures de cet utilisateur."
-#: models.py:189
+#: models.py:191
msgid ""
"You don't have the right to delete an invoice already controlled or "
"invalidated."
msgstr ""
-"Vous n'avez pas le droit de supprimer une facture précedement contrôlée ou "
+"Vous n'avez pas le droit de supprimer une facture précédemment contrôlée ou "
"invalidée."
-#: models.py:197
+#: models.py:199
msgid "You don't have the right to view someone else's invoices history."
msgstr ""
"Vous n'avez pas le droit de voir l'historique des factures d'un autre "
"utilisateur."
-#: models.py:200
+#: models.py:202
msgid "The invoice has been invalidated."
msgstr "La facture a été invalidée."
-#: models.py:210
+#: models.py:214
msgid "You don't have the right to edit the \"controlled\" state."
msgstr "Vous n'avez pas le droit de modifier le statut \"contrôlé\"."
-#: models.py:224
+#: models.py:228
msgid "There are no payment method which you can use."
msgstr "Il n'y a pas de moyen de paiement que vous puissiez utiliser."
-#: models.py:226
+#: models.py:230
msgid "There are no article that you can buy."
msgstr "Il n'y a pas d'article que vous puissiez acheter."
-#: models.py:261
+#: models.py:272
msgid "Can view a custom invoice object"
msgstr "Peut voir un objet facture personnalisée"
-#: models.py:265 templates/cotisations/aff_custom_invoice.html:36
+#: models.py:276 templates/cotisations/aff_cost_estimate.html:36
+#: templates/cotisations/aff_custom_invoice.html:36
msgid "Recipient"
msgstr "Destinataire"
-#: models.py:269 templates/cotisations/aff_paiement.html:33
+#: models.py:280 templates/cotisations/aff_paiement.html:33
msgid "Payment type"
msgstr "Type de paiement"
-#: models.py:273
+#: models.py:284
msgid "Address"
msgstr "Adresse"
-#: models.py:276 templates/cotisations/aff_custom_invoice.html:54
+#: models.py:287 templates/cotisations/aff_custom_invoice.html:54
msgid "Paid"
msgstr "Payé"
-#: models.py:296 models.py:516 models.py:764
+#: models.py:291
+msgid "Remark"
+msgstr "Remarque"
+
+#: models.py:300
+msgid "Can view a cost estimate object"
+msgstr "Peut voir un objet devis"
+
+#: models.py:303
+msgid "Period of validity"
+msgstr "Période de validité"
+
+#: models.py:340
+msgid "You don't have the right to delete a cost estimate."
+msgstr "Vous n'avez pas le droit de supprimer un devis."
+
+#: models.py:343
+msgid "The cost estimate has an invoice and can't be deleted."
+msgstr "Le devis a une facture et ne peut pas être supprimé."
+
+#: models.py:364 models.py:585 models.py:852
msgid "Connection"
msgstr "Connexion"
-#: models.py:297 models.py:517 models.py:765
+#: models.py:365 models.py:586 models.py:853
msgid "Membership"
msgstr "Adhésion"
-#: models.py:298 models.py:512 models.py:518 models.py:766
+#: models.py:366 models.py:581 models.py:587 models.py:854
msgid "Both of them"
msgstr "Les deux"
-#: models.py:310
+#: models.py:378
msgid "amount"
msgstr "montant"
-#: models.py:315
+#: models.py:383
msgid "article"
msgstr "article"
-#: models.py:322
+#: models.py:390
msgid "price"
msgstr "prix"
-#: models.py:327 models.py:535
+#: models.py:395 models.py:604
msgid "duration (in months)"
msgstr "durée (en mois)"
-#: models.py:335 models.py:549 models.py:780
+#: models.py:403 models.py:618 models.py:868
msgid "subscription type"
msgstr "type de cotisation"
-#: models.py:340
+#: models.py:408
msgid "Can view a purchase object"
msgstr "Peut voir un objet achat"
-#: models.py:341
+#: models.py:409
msgid "Can edit all the previous purchases"
msgstr "Peut modifier tous les achats précédents"
-#: models.py:343 models.py:774
+#: models.py:411 models.py:862
msgid "purchase"
msgstr "achat"
-#: models.py:344
+#: models.py:412
msgid "purchases"
msgstr "achats"
-#: models.py:411 models.py:573
+#: models.py:479 models.py:642
msgid "Duration must be specified for a subscription."
msgstr "La durée de la cotisation doit être indiquée."
-#: models.py:418
+#: models.py:486
msgid "You don't have the right to edit the purchases."
msgstr "Vous n'avez pas le droit de modifier les achats."
-#: models.py:423
+#: models.py:491
msgid "You don't have the right to edit this user's purchases."
msgstr "Vous n'avez pas le droit de modifier les achats de cet utilisateur."
-#: models.py:427
+#: models.py:495
msgid ""
"You don't have the right to edit a purchase already controlled or "
"invalidated."
@@ -285,150 +325,150 @@ msgstr ""
"Vous n'avez pas le droit de modifier un achat précédemment contrôlé ou "
"invalidé."
-#: models.py:434
+#: models.py:502
msgid "You don't have the right to delete a purchase."
msgstr "Vous n'avez pas le droit de supprimer un achat."
-#: models.py:436
+#: models.py:504
msgid "You don't have the right to delete this user's purchases."
msgstr "Vous n'avez pas le droit de supprimer les achats de cet utilisateur."
-#: models.py:439
+#: models.py:507
msgid ""
"You don't have the right to delete a purchase already controlled or "
"invalidated."
msgstr ""
-"Vous n'avez pas le droit de supprimer un achat précédement contrôlé ou "
+"Vous n'avez pas le droit de supprimer un achat précédemment contrôlé ou "
"invalidé."
-#: models.py:447
+#: models.py:515
msgid "You don't have the right to view someone else's purchase history."
msgstr ""
"Vous n'avez pas le droit de voir l'historique des achats d'un autre "
"utilisateur."
-#: models.py:511
+#: models.py:580
msgid "Club"
msgstr "Club"
-#: models.py:523
+#: models.py:592
msgid "designation"
msgstr "désignation"
-#: models.py:529
+#: models.py:598
msgid "unit price"
msgstr "prix unitaire"
-#: models.py:541
+#: models.py:610
msgid "type of users concerned"
msgstr "type d'utilisateurs concernés"
-#: models.py:553 models.py:649
+#: models.py:622 models.py:733
msgid "is available for every user"
msgstr "est disponible pour chaque utilisateur"
-#: models.py:560
+#: models.py:629
msgid "Can view an article object"
msgstr "Peut voir un objet article"
-#: models.py:561
+#: models.py:630
msgid "Can buy every article"
msgstr "Peut acheter chaque article"
-#: models.py:569
+#: models.py:638
msgid "Balance is a reserved article name."
msgstr "Solde est un nom d'article réservé."
-#: models.py:594
+#: models.py:663
msgid "You can't buy this article."
msgstr "Vous ne pouvez pas acheter cet article."
-#: models.py:624
+#: models.py:708
msgid "Can view a bank object"
msgstr "Peut voir un objet banque"
-#: models.py:626
+#: models.py:710
msgid "bank"
msgstr "banque"
-#: models.py:627
+#: models.py:711
msgid "banks"
msgstr "banques"
-#: models.py:645
+#: models.py:729
msgid "method"
msgstr "moyen"
-#: models.py:654
+#: models.py:738
msgid "is user balance"
msgstr "est solde utilisateur"
-#: models.py:655
+#: models.py:739
msgid "There should be only one balance payment method."
msgstr "Il ne devrait y avoir qu'un moyen de paiement solde."
-#: models.py:661
+#: models.py:745
msgid "Can view a payment method object"
msgstr "Peut voir un objet moyen de paiement"
-#: models.py:662
+#: models.py:746
msgid "Can use every payment method"
msgstr "Peut utiliser chaque moyen de paiement"
-#: models.py:664
+#: models.py:748
msgid "payment method"
msgstr "moyen de paiement"
-#: models.py:665
+#: models.py:749
msgid "payment methods"
msgstr "moyens de paiement"
-#: models.py:699 payment_methods/comnpay/views.py:63
+#: models.py:787 payment_methods/comnpay/views.py:63
#, python-format
msgid "The subscription of %(member_name)s was extended to %(end_date)s."
msgstr "La cotisation de %(member_name)s a été étendue au %(end_date)s."
-#: models.py:709
+#: models.py:797
msgid "The invoice was created."
msgstr "La facture a été créée."
-#: models.py:730
+#: models.py:818
msgid "You can't use this payment method."
msgstr "Vous ne pouvez pas utiliser ce moyen de paiement."
-#: models.py:748
+#: models.py:836
msgid "No custom payment method."
msgstr "Pas de moyen de paiement personnalisé."
-#: models.py:783
+#: models.py:871
msgid "start date"
msgstr "date de début"
-#: models.py:786
+#: models.py:874
msgid "end date"
msgstr "date de fin"
-#: models.py:791
+#: models.py:879
msgid "Can view a subscription object"
msgstr "Peut voir un objet cotisation"
-#: models.py:792
+#: models.py:880
msgid "Can edit the previous subscriptions"
msgstr "Peut modifier les cotisations précédentes"
-#: models.py:794
+#: models.py:882
msgid "subscription"
msgstr "cotisation"
-#: models.py:795
+#: models.py:883
msgid "subscriptions"
msgstr "cotisations"
-#: models.py:799
+#: models.py:887
msgid "You don't have the right to edit a subscription."
msgstr "Vous n'avez pas le droit de modifier une cotisation."
-#: models.py:803
+#: models.py:891
msgid ""
"You don't have the right to edit a subscription already controlled or "
"invalidated."
@@ -436,11 +476,11 @@ msgstr ""
"Vous n'avez pas le droit de modifier une cotisation précédemment contrôlée "
"ou invalidée."
-#: models.py:810
+#: models.py:898
msgid "You don't have the right to delete a subscription."
msgstr "Vous n'avez pas le droit de supprimer une cotisation."
-#: models.py:813
+#: models.py:901
msgid ""
"You don't have the right to delete a subscription already controlled or "
"invalidated."
@@ -448,7 +488,7 @@ msgstr ""
"Vous n'avez pas le droit de supprimer une cotisation précédemment contrôlée "
"ou invalidée."
-#: models.py:821
+#: models.py:909
msgid "You don't have the right to view someone else's subscription history."
msgstr ""
"Vous n'avez pas le droit de voir l'historique des cotisations d'un autre "
@@ -482,11 +522,11 @@ msgstr "Le montant maximal d'argent autorisé pour le solde."
msgid "Allow user to credit their balance"
msgstr "Autorise l'utilisateur à créditer son solde"
-#: payment_methods/balance/models.py:81 payment_methods/balance/models.py:112
+#: payment_methods/balance/models.py:79 payment_methods/balance/models.py:110
msgid "Your balance is too low for this operation."
msgstr "Votre solde est trop bas pour cette opération."
-#: payment_methods/balance/models.py:99 validators.py:20
+#: payment_methods/balance/models.py:97 validators.py:20
msgid "There is already a payment method for user balance."
msgstr "Il y a déjà un moyen de paiement pour le solde utilisateur."
@@ -523,11 +563,11 @@ msgstr ""
msgid "Production mode enabled (production URL, instead of homologation)"
msgstr "Mode production activé (URL de production, au lieu d'homologation)"
-#: payment_methods/comnpay/models.py:104
+#: payment_methods/comnpay/models.py:102
msgid "Pay invoice number "
msgstr "Payer la facture numéro "
-#: payment_methods/comnpay/models.py:116
+#: payment_methods/comnpay/models.py:114
msgid ""
"In order to pay your invoice with ComNpay, the price must be greater than {} "
"€."
@@ -559,6 +599,30 @@ msgstr ""
msgid "no"
msgstr "non"
+#: payment_methods/note_kfet/forms.py:32
+msgid "pseudo note"
+msgstr "pseudo note"
+
+#: payment_methods/note_kfet/forms.py:35
+msgid "Password"
+msgstr "Mot de passe"
+
+#: payment_methods/note_kfet/models.py:40
+msgid "NoteKfet"
+msgstr "NoteKfet"
+
+#: payment_methods/note_kfet/models.py:50
+msgid "server"
+msgstr "serveur"
+
+#: payment_methods/note_kfet/views.py:60
+msgid "Unknown error."
+msgstr "Erreur inconnue."
+
+#: payment_methods/note_kfet/views.py:88
+msgid "The payment with note was done."
+msgstr "Le paiement par note a été effectué."
+
#: templates/cotisations/aff_article.html:34
msgid "Price"
msgstr "Prix"
@@ -579,34 +643,47 @@ msgstr "Utilisateurs concernés"
msgid "Available for everyone"
msgstr "Disponible pour tous"
-#: templates/cotisations/aff_article.html:52
-#: templates/cotisations/aff_paiement.html:48
-#: templates/cotisations/control.html:107 views.py:483 views.py:570
-#: views.py:650
-msgid "Edit"
-msgstr "Modifier"
-
#: templates/cotisations/aff_banque.html:32
msgid "Bank"
msgstr "Banque"
-#: templates/cotisations/aff_cotisations.html:38
-msgid "User"
-msgstr "Utilisateur"
-
+#: templates/cotisations/aff_cost_estimate.html:39
#: templates/cotisations/aff_cotisations.html:41
#: templates/cotisations/aff_custom_invoice.html:39
#: templates/cotisations/control.html:63
-#: templates/cotisations/edit_facture.html:45
+#: templates/cotisations/edit_facture.html:49
msgid "Designation"
msgstr "Désignation"
+#: templates/cotisations/aff_cost_estimate.html:40
#: templates/cotisations/aff_cotisations.html:42
#: templates/cotisations/aff_custom_invoice.html:40
#: templates/cotisations/control.html:64
msgid "Total price"
msgstr "Prix total"
+#: templates/cotisations/aff_cost_estimate.html:50
+msgid "Validity"
+msgstr "Validité"
+
+#: templates/cotisations/aff_cost_estimate.html:54
+msgid "Cost estimate ID"
+msgstr "ID devis"
+
+#: templates/cotisations/aff_cost_estimate.html:58
+msgid "Invoice created"
+msgstr "Facture créée"
+
+#: templates/cotisations/aff_cost_estimate.html:91
+#: templates/cotisations/aff_cotisations.html:81
+#: templates/cotisations/aff_custom_invoice.html:79
+msgid "PDF"
+msgstr "PDF"
+
+#: templates/cotisations/aff_cotisations.html:38
+msgid "User"
+msgstr "Utilisateur"
+
#: templates/cotisations/aff_cotisations.html:52
#: templates/cotisations/aff_custom_invoice.html:50
#: templates/cotisations/control.html:56
@@ -617,11 +694,6 @@ msgstr "ID facture"
msgid "Controlled invoice"
msgstr "Facture contrôlée"
-#: templates/cotisations/aff_cotisations.html:81
-#: templates/cotisations/aff_custom_invoice.html:79
-msgid "PDF"
-msgstr "PDF"
-
#: templates/cotisations/aff_cotisations.html:84
msgid "Invalidated invoice"
msgstr "Facture invalidée"
@@ -666,6 +738,11 @@ msgstr "Validé"
msgid "Controlled"
msgstr "Contrôlé"
+#: templates/cotisations/control.html:107 views.py:642 views.py:729
+#: views.py:809
+msgid "Edit"
+msgstr "Modifier"
+
#: templates/cotisations/delete.html:29
msgid "Deletion of subscriptions"
msgstr "Suppression de cotisations"
@@ -676,33 +753,33 @@ msgid ""
"Warning: are you sure you really want to delete this %(object_name)s object "
"( %(objet)s )?"
msgstr ""
-"\tAttention: voulez-vous vraiment supprimer cet objet %(object_name)s "
+"Attention: voulez-vous vraiment supprimer cet objet %(object_name)s "
"( %(objet)s ) ?"
#: templates/cotisations/delete.html:38
-#: templates/cotisations/edit_facture.html:60
-#: views.py:181 views.py:235
+#: templates/cotisations/edit_facture.html:64 views.py:178 views.py:228
+#: views.py:280
msgid "Confirm"
-msgstr "Valider"
+msgstr "Confirmer"
#: templates/cotisations/edit_facture.html:31
#: templates/cotisations/facture.html:30
msgid "Creation and editing of invoices"
msgstr "Création et modification de factures"
-#: templates/cotisations/edit_facture.html:38
-msgid "Edit the invoice"
+#: templates/cotisations/edit_facture.html:41
+msgid "Edit invoice"
msgstr "Modifier la facture"
-#: templates/cotisations/edit_facture.html:41
-#: templates/cotisations/facture.html:56
+#: templates/cotisations/edit_facture.html:45
+#: templates/cotisations/facture.html:62
#: templates/cotisations/index_article.html:30
msgid "Articles"
msgstr "Articles"
#: templates/cotisations/facture.html:37
msgid "Buy"
-msgstr "Acheter une cotisation"
+msgstr "Acheter"
#: templates/cotisations/facture.html:40
#, python-format
@@ -714,11 +791,11 @@ msgstr "Solde maximum autorisé : %(max_balance)s €"
msgid "Current balance: %(balance)s €"
msgstr "Solde actuel : %(balance)s €"
-#: templates/cotisations/facture.html:70
+#: templates/cotisations/facture.html:76
msgid "Add an extra article"
msgstr "Ajouter un article supplémentaire"
-#: templates/cotisations/facture.html:72
+#: templates/cotisations/facture.html:82
msgid "Total price: 0,00 €"
msgstr "Prix total : 0,00 €"
@@ -730,9 +807,8 @@ msgstr "Factures"
msgid "Subscriptions"
msgstr "Cotisations"
-
#: templates/cotisations/index_article.html:33
-msgid "Article types list"
+msgid "List of article types"
msgstr "Liste des types d'article"
#: templates/cotisations/index_article.html:36
@@ -744,12 +820,12 @@ msgid "Delete one or several article types"
msgstr "Supprimer un ou plusieurs types d'article"
#: templates/cotisations/index_banque.html:30
-#: templates/cotisations/sidebar.html:55
+#: templates/cotisations/sidebar.html:60
msgid "Banks"
msgstr "Banques"
#: templates/cotisations/index_banque.html:33
-msgid "Banks list"
+msgid "List of banks"
msgstr "Liste des banques"
#: templates/cotisations/index_banque.html:36
@@ -760,17 +836,26 @@ msgstr "Ajouter une banque"
msgid "Delete one or several banks"
msgstr "Supprimer une ou plusieurs banques"
+#: templates/cotisations/index_cost_estimate.html:28
+#: templates/cotisations/sidebar.html:50
+msgid "Cost estimates"
+msgstr "Devis"
+
+#: templates/cotisations/index_cost_estimate.html:31
+msgid "List of cost estimates"
+msgstr "Liste des devis"
+
#: templates/cotisations/index_custom_invoice.html:28
#: templates/cotisations/sidebar.html:45
msgid "Custom invoices"
msgstr "Factures personnalisées"
#: templates/cotisations/index_custom_invoice.html:31
-msgid "Custom invoices list"
-msgstr "Liste des factures personalisées"
+msgid "List of custom invoices"
+msgstr "Liste des factures personnalisées"
#: templates/cotisations/index_paiement.html:30
-#: templates/cotisations/sidebar.html:60
+#: templates/cotisations/sidebar.html:65
msgid "Payment methods"
msgstr "Moyens de paiement"
@@ -793,9 +878,9 @@ msgstr "Rechargement de solde"
#: templates/cotisations/payment.html:34
#, python-format
msgid "Pay %(amount)s €"
-msgstr "Recharger de %(amount)s €"
+msgstr "Payer %(amount)s €"
-#: templates/cotisations/payment.html:42 views.py:870
+#: templates/cotisations/payment.html:42 views.py:1049
msgid "Pay"
msgstr "Payer"
@@ -807,81 +892,104 @@ msgstr "Créer une facture"
msgid "Control the invoices"
msgstr "Contrôler les factures"
-#: views.py:167
+#: views.py:164
msgid "You need to choose at least one article."
msgstr "Vous devez choisir au moins un article."
+#: views.py:222
+msgid "The cost estimate was created."
+msgstr "Le devis a été créé."
-#: views.py:228
+#: views.py:232 views.py:534
+msgid "Cost estimate"
+msgstr "Devis"
+
+#: views.py:274
msgid "The custom invoice was created."
msgstr "La facture personnalisée a été créée."
-#: views.py:316 views.py:370
+#: views.py:363 views.py:466
msgid "The invoice was edited."
msgstr "La facture a été modifiée."
-#: views.py:336 views.py:430
+#: views.py:383 views.py:589
msgid "The invoice was deleted."
msgstr "La facture a été supprimée."
-#: views.py:341 views.py:435
+#: views.py:388 views.py:594
msgid "Invoice"
msgstr "Facture"
-#: views.py:456
+#: views.py:417
+msgid "The cost estimate was edited."
+msgstr "Le devis a été modifié."
+
+#: views.py:424
+msgid "Edit cost estimate"
+msgstr "Modifier le devis"
+
+#: views.py:436
+msgid "An invoice was successfully created from your cost estimate."
+msgstr "Une facture a bien été créée à partir de votre devis."
+
+#: views.py:529
+msgid "The cost estimate was deleted."
+msgstr "Le devis a été supprimé."
+
+#: views.py:615
msgid "The article was created."
msgstr "L'article a été créé."
-#: views.py:461 views.py:534 views.py:627
+#: views.py:620 views.py:693 views.py:786
msgid "Add"
msgstr "Ajouter"
-#: views.py:462
+#: views.py:621
msgid "New article"
msgstr "Nouvel article"
-#: views.py:478
+#: views.py:637
msgid "The article was edited."
msgstr "L'article a été modifié."
-#: views.py:484
+#: views.py:643
msgid "Edit article"
msgstr "Modifier l'article"
-#: views.py:500
+#: views.py:659
msgid "The articles were deleted."
msgstr "Les articles ont été supprimés."
-#: views.py:505 views.py:605 views.py:685
+#: views.py:664 views.py:764 views.py:844
msgid "Delete"
msgstr "Supprimer"
-#: views.py:506
+#: views.py:665
msgid "Delete article"
msgstr "Supprimer l'article"
-#: views.py:528
+#: views.py:687
msgid "The payment method was created."
msgstr "Le moyen de paiment a été créé."
-#: views.py:535
+#: views.py:694
msgid "New payment method"
msgstr "Nouveau moyen de paiement"
-#: views.py:564
+#: views.py:723
msgid "The payment method was edited."
msgstr "Le moyen de paiment a été modifié."
-#: views.py:571
+#: views.py:730
msgid "Edit payment method"
msgstr "Modifier le moyen de paiement"
-#: views.py:590
+#: views.py:749
#, python-format
msgid "The payment method %(method_name)s was deleted."
msgstr "Le moyen de paiement %(method_name)s a été supprimé."
-#: views.py:597
+#: views.py:756
#, python-format
msgid ""
"The payment method %(method_name)s can't be deleted "
@@ -890,52 +998,51 @@ msgstr ""
"Le moyen de paiement %(method_name)s ne peut pas être supprimé car il y a "
"des factures qui l'utilisent."
-#: views.py:606
+#: views.py:765
msgid "Delete payment method"
msgstr "Supprimer le moyen de paiement"
-#: views.py:622
+#: views.py:781
msgid "The bank was created."
msgstr "La banque a été créée."
-#: views.py:628
+#: views.py:787
msgid "New bank"
msgstr "Nouvelle banque"
-#: views.py:645
+#: views.py:804
msgid "The bank was edited."
msgstr "La banque a été modifiée."
-#: views.py:651
+#: views.py:810
msgid "Edit bank"
msgstr "Modifier la banque"
-#: views.py:670
+#: views.py:829
#, python-format
msgid "The bank %(bank_name)s was deleted."
msgstr "La banque %(bank_name)s a été supprimée."
-#: views.py:677
+#: views.py:836
#, python-format
msgid ""
-"The bank %(bank_name)s can't be deleted because there "
-"are invoices using it."
+"The bank %(bank_name)s can't be deleted because there are invoices using it."
msgstr ""
"La banque %(bank_name)s ne peut pas être supprimée car il y a des factures "
"qui l'utilisent."
-#: views.py:686
+#: views.py:845
msgid "Delete bank"
msgstr "Supprimer la banque"
-#: views.py:722
+#: views.py:881
msgid "Your changes have been properly taken into account."
msgstr "Vos modifications ont correctement été prises en compte."
-#: views.py:834
+#: views.py:1016
msgid "You are not allowed to credit your balance."
msgstr "Vous n'êtes pas autorisés à créditer votre solde."
-#: views.py:869
+#: views.py:1048
msgid "Refill your balance"
msgstr "Recharger votre solde"
diff --git a/cotisations/models.py b/cotisations/models.py
index 623db068..ea565ac8 100644
--- a/cotisations/models.py
+++ b/cotisations/models.py
@@ -341,7 +341,7 @@ class CostEstimate(CustomInvoice):
"to delete a cost estimate.")
if self.final_invoice is not None:
return False, _("The cost estimate has an "
- "invoice and cannot be deleted.")
+ "invoice and can't be deleted.")
return True, None
diff --git a/cotisations/payment_methods/note_kfet/views.py b/cotisations/payment_methods/note_kfet/views.py
index d4d0ac21..cfdda9b0 100644
--- a/cotisations/payment_methods/note_kfet/views.py
+++ b/cotisations/payment_methods/note_kfet/views.py
@@ -57,7 +57,7 @@ def note_payment(request, facture, factureid):
user = facture.user
payment_method = find_payment_method(facture.paiement)
if not payment_method or not isinstance(payment_method, NotePayment):
- messages.error(request, "Erreur inconnue")
+ messages.error(request, _("Unknown error."))
return redirect(reverse(
'users:profil',
kwargs={'userid': user.id}
@@ -85,7 +85,7 @@ def note_payment(request, facture, factureid):
)
facture.valid = True
facture.save()
- messages.success(request, "Le paiement par note a bien été effectué")
+ messages.success(request, _("The payment with note was done."))
return redirect(reverse(
'users:profil',
kwargs={'userid': user.id}
diff --git a/cotisations/templates/cotisations/aff_article.html b/cotisations/templates/cotisations/aff_article.html
index b07035da..682d6a05 100644
--- a/cotisations/templates/cotisations/aff_article.html
+++ b/cotisations/templates/cotisations/aff_article.html
@@ -49,9 +49,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ article.available_for_everyone | tick }} |
{% can_edit article %}
-
-
-
+ {% include 'buttons/edit.html' with href='cotisations:edit-article' id=article.id %}
{% acl_end %}
{% history_button article %}
|
diff --git a/cotisations/templates/cotisations/aff_cost_estimate.html b/cotisations/templates/cotisations/aff_cost_estimate.html
index d4a3f60d..e591a5fe 100644
--- a/cotisations/templates/cotisations/aff_cost_estimate.html
+++ b/cotisations/templates/cotisations/aff_cost_estimate.html
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if cost_estimate_list.paginator %}
- {% include 'pagination.html' with list=cost_estimate_list%}
+ {% include 'pagination.html' with list=cost_estimate_list%}
{% endif %}
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Recipient" as tr_recip %}
- {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_user %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_recip %}
|
{% trans "Designation" %} |
{% trans "Total price" %} |
@@ -96,6 +96,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if custom_invoice_list.paginator %}
- {% include 'pagination.html' with list=custom_invoice_list %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
{% endif %}
diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html
index 93384106..7dd64395 100644
--- a/cotisations/templates/cotisations/aff_cotisations.html
+++ b/cotisations/templates/cotisations/aff_cotisations.html
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}
@@ -89,7 +89,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}
diff --git a/cotisations/templates/cotisations/aff_custom_invoice.html b/cotisations/templates/cotisations/aff_custom_invoice.html
index 0f4605ad..c1c5a396 100644
--- a/cotisations/templates/cotisations/aff_custom_invoice.html
+++ b/cotisations/templates/cotisations/aff_custom_invoice.html
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if custom_invoice_list.paginator %}
- {% include 'pagination.html' with list=custom_invoice_list %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
{% endif %}
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Recipient" as tr_recip %}
- {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_user %}
+ {% include 'buttons/sort.html' with prefix='invoice' col='user' text=tr_recip %}
|
{% trans "Designation" %} |
{% trans "Total price" %} |
@@ -51,7 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% include 'buttons/sort.html' with prefix='invoice' col='id' text=tr_invoice_id %}
- {% trans "Paid" as tr_invoice_paid%}
+ {% trans "Paid" as tr_invoice_paid %}
{% include 'buttons/sort.html' with prefix='invoice' col='paid' text=tr_invoice_paid %}
|
|
@@ -84,6 +84,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if custom_invoice_list.paginator %}
- {% include 'pagination.html' with list=custom_invoice_list %}
+ {% include 'pagination.html' with list=custom_invoice_list %}
{% endif %}
diff --git a/cotisations/templates/cotisations/aff_paiement.html b/cotisations/templates/cotisations/aff_paiement.html
index 633eb456..afb78b48 100644
--- a/cotisations/templates/cotisations/aff_paiement.html
+++ b/cotisations/templates/cotisations/aff_paiement.html
@@ -45,9 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% can_edit paiement %}
-
-
-
+ {% include 'buttons/edit.html' with href='cotisations:edit-paiement' id=paiement.id %}
{% acl_end %}
{% history_button paiement %}
|
diff --git a/cotisations/templates/cotisations/control.html b/cotisations/templates/cotisations/control.html
index 483c150c..5a18bd01 100644
--- a/cotisations/templates/cotisations/control.html
+++ b/cotisations/templates/cotisations/control.html
@@ -1,4 +1,4 @@
-{% extends "cotisations/sidebar.html" %}
+{% extends 'cotisations/sidebar.html' %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Invoice control and validation" %}
{% if facture_list.paginator %}
-{% include 'pagination.html' with list=facture_list %}
+ {% include 'pagination.html' with list=facture_list %}
{% endif %}