8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-05 01:16:27 +00:00

Merge branch 'translation' into 'dev'

Translation

See merge request federez/re2o!471
This commit is contained in:
chirac 2019-11-24 23:32:47 +01:00
commit 9afe81b9e2
163 changed files with 4398 additions and 3322 deletions

View file

@ -74,6 +74,6 @@ def can_view(user):
can = user.has_perm(permission) can = user.has_perm(permission)
return ( return (
can, can,
None if can else _("You don't have the right to see this" " application."), None if can else _("You don't have the right to view this application."),
(permission,), (permission,),
) )

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-05 19:48+0200\n" "POT-Creation-Date: 2019-11-19 23:43+0100\n"
"PO-Revision-Date: 2019-01-07 01:37+0100\n" "PO-Revision-Date: 2019-01-07 01:37+0100\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -31,10 +31,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: api/acl.py:74 #: api/acl.py:77
msgid "You don't have the right to see this application." msgid "You don't have the right to view this application."
msgstr "Vous n'avez pas le droit de voir cette application." msgstr "Vous n'avez pas le droit de voir cette application."
#: api/authentication.py:49 #: api/authentication.py:47
msgid "The token has expired." msgid "The token has expired."
msgstr "Le jeton a expiré." msgstr "Le jeton a expiré."

View file

@ -116,7 +116,7 @@ class DiscountForm(Form):
""" """
is_relative = forms.BooleanField( is_relative = forms.BooleanField(
label=_("Discount is on percentage."), required=False label=_("Discount is in percentage."), required=False
) )
discount = forms.DecimalField( discount = forms.DecimalField(
label=_("Discount"), label=_("Discount"),
@ -184,7 +184,7 @@ class DelArticleForm(FormRevMixin, Form):
articles = forms.ModelMultipleChoiceField( articles = forms.ModelMultipleChoiceField(
queryset=Article.objects.none(), queryset=Article.objects.none(),
label=_("Available articles"), label=_("Current articles"),
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
) )
@ -226,7 +226,7 @@ class DelPaiementForm(FormRevMixin, Form):
# TODO : change paiement to payment # TODO : change paiement to payment
paiements = forms.ModelMultipleChoiceField( paiements = forms.ModelMultipleChoiceField(
queryset=Paiement.objects.none(), queryset=Paiement.objects.none(),
label=_("Available payment methods"), label=_("Current payment methods"),
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
) )
@ -266,7 +266,7 @@ class DelBanqueForm(FormRevMixin, Form):
# TODO : change banque to bank # TODO : change banque to bank
banques = forms.ModelMultipleChoiceField( banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.none(), queryset=Banque.objects.none(),
label=_("Available banks"), label=_("Current banks"),
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
) )

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-11-20 00:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cotisations', '0041_auto_20191103_2131'),
]
operations = [
migrations.AlterModelOptions(
name='chequepayment',
options={'verbose_name': 'cheque'},
),
migrations.AlterField(
model_name='balancepayment',
name='credit_balance_allowed',
field=models.BooleanField(default=False, verbose_name='allow user to credit their balance'),
),
migrations.AlterField(
model_name='balancepayment',
name='maximum_balance',
field=models.DecimalField(blank=True, decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, null=True, verbose_name='maximum balance'),
),
migrations.AlterField(
model_name='balancepayment',
name='minimum_balance',
field=models.DecimalField(decimal_places=2, default=0, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify a negative amount.', max_digits=5, verbose_name='minimum balance'),
),
migrations.AlterField(
model_name='baseinvoice',
name='date',
field=models.DateTimeField(auto_now_add=True, verbose_name='date'),
),
migrations.AlterField(
model_name='comnpaypayment',
name='minimum_payment',
field=models.DecimalField(decimal_places=2, default=1, help_text='The minimal amount of money you have to use when paying with ComNpay.', max_digits=5, verbose_name='minimum payment'),
),
migrations.AlterField(
model_name='comnpaypayment',
name='production',
field=models.BooleanField(default=True, verbose_name='production mode enabled (production URL, instead of homologation)'),
),
migrations.AlterField(
model_name='costestimate',
name='validity',
field=models.DurationField(help_text='DD HH:MM:SS', verbose_name='period of validity'),
),
migrations.AlterField(
model_name='custominvoice',
name='address',
field=models.CharField(max_length=255, verbose_name='address'),
),
migrations.AlterField(
model_name='custominvoice',
name='paid',
field=models.BooleanField(default=False, verbose_name='paid'),
),
migrations.AlterField(
model_name='custominvoice',
name='payment',
field=models.CharField(max_length=255, verbose_name='payment type'),
),
migrations.AlterField(
model_name='custominvoice',
name='recipient',
field=models.CharField(max_length=255, verbose_name='recipient'),
),
migrations.AlterField(
model_name='custominvoice',
name='remark',
field=models.TextField(blank=True, null=True, verbose_name='remark'),
),
]

View file

@ -56,7 +56,7 @@ from cotisations.validators import check_no_balance
class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
date = models.DateTimeField(auto_now_add=True, verbose_name=_("Date")) date = models.DateTimeField(auto_now_add=True, verbose_name=_("date"))
# TODO : change prix to price # TODO : change prix to price
def prix(self): def prix(self):
@ -138,7 +138,7 @@ class Facture(BaseInvoice):
abstract = False abstract = False
permissions = ( permissions = (
# TODO : change facture to invoice # TODO : change facture to invoice
("change_facture_control", _('Can edit the "controlled" state')), ("change_facture_control", _("Can edit the \"controlled\" state")),
("view_facture", _("Can view an invoice object")), ("view_facture", _("Can view an invoice object")),
("change_all_facture", _("Can edit all the previous invoices")), ("change_all_facture", _("Can edit all the previous invoices")),
) )
@ -243,7 +243,7 @@ class Facture(BaseInvoice):
can = user_request.has_perm("cotisations.change_facture_control") can = user_request.has_perm("cotisations.change_facture_control")
return ( return (
can, can,
_('You don\'t have the right to edit the "controlled" state.') _("You don't have the right to edit the \"controlled\" state.")
if not can if not can
else None, else None,
("cotisations.change_facture_control",), ("cotisations.change_facture_control",),
@ -262,13 +262,13 @@ class Facture(BaseInvoice):
if len(Paiement.find_allowed_payments(user_request)) <= 0: if len(Paiement.find_allowed_payments(user_request)) <= 0:
return ( return (
False, False,
_("There are no payment method which you can use."), _("There are no payment methods that you can use."),
("cotisations.add_facture",), ("cotisations.add_facture",),
) )
if len(Article.find_allowed_articles(user_request, user_request)) <= 0: if len(Article.find_allowed_articles(user_request, user_request)) <= 0:
return ( return (
False, False,
_("There are no article that you can buy."), _("There are no articles that you can buy."),
("cotisations.add_facture",), ("cotisations.add_facture",),
) )
return True, None, None return True, None, None
@ -346,11 +346,11 @@ class CustomInvoice(BaseInvoice):
class Meta: class Meta:
permissions = (("view_custominvoice", _("Can view a custom invoice object")),) permissions = (("view_custominvoice", _("Can view a custom invoice object")),)
recipient = models.CharField(max_length=255, verbose_name=_("Recipient")) recipient = models.CharField(max_length=255, verbose_name=_("recipient"))
payment = models.CharField(max_length=255, verbose_name=_("Payment type")) payment = models.CharField(max_length=255, verbose_name=_("payment type"))
address = models.CharField(max_length=255, verbose_name=_("Address")) address = models.CharField(max_length=255, verbose_name=_("address"))
paid = models.BooleanField(verbose_name=_("Paid"), default=False) paid = models.BooleanField(verbose_name=_("paid"), default=False)
remark = models.TextField(verbose_name=_("Remark"), blank=True, null=True) remark = models.TextField(verbose_name=_("remark"), blank=True, null=True)
class CostEstimate(CustomInvoice): class CostEstimate(CustomInvoice):
@ -358,7 +358,7 @@ class CostEstimate(CustomInvoice):
permissions = (("view_costestimate", _("Can view a cost estimate object")),) permissions = (("view_costestimate", _("Can view a cost estimate object")),)
validity = models.DurationField( validity = models.DurationField(
verbose_name=_("Period of validity"), help_text="DD HH:MM:SS" verbose_name=_("period of validity"), help_text="DD HH:MM:SS"
) )
final_invoice = models.ForeignKey( final_invoice = models.ForeignKey(
CustomInvoice, CustomInvoice,
@ -547,7 +547,7 @@ class Vente(RevMixin, AclMixin, models.Model):
if not user_request.has_perm("cotisations.change_vente"): if not user_request.has_perm("cotisations.change_vente"):
return ( return (
False, False,
_("You don't have the right to edit the purchases."), _("You don't have the right to edit a purchase."),
("cotisations.change_vente",), ("cotisations.change_vente",),
) )
elif not (user_request.has_perm("cotisations.change_all_facture") or user_can): elif not (user_request.has_perm("cotisations.change_all_facture") or user_can):
@ -731,7 +731,7 @@ class Article(RevMixin, AclMixin, models.Model):
def clean(self): def clean(self):
if self.name.lower() == "solde": if self.name.lower() == "solde":
raise ValidationError(_("Balance is a reserved article name.")) raise ValidationError(_("Solde is a reserved article name."))
if self.type_cotisation and not (self.duration or self.duration_days): if self.type_cotisation and not (self.duration or self.duration_days):
raise ValidationError(_("Duration must be specified for a subscription.")) raise ValidationError(_("Duration must be specified for a subscription."))
@ -921,7 +921,7 @@ class Paiement(RevMixin, AclMixin, models.Model):
p = find_payment_method(self) p = find_payment_method(self)
if p is not None: if p is not None:
return p._meta.verbose_name return p._meta.verbose_name
return _("No custom payment method.") return _("No custom payment methods.")
class Cotisation(RevMixin, AclMixin, models.Model): class Cotisation(RevMixin, AclMixin, models.Model):

View file

@ -44,18 +44,17 @@ class BalancePayment(PaymentMethodMixin, models.Model):
editable=False, editable=False,
) )
minimum_balance = models.DecimalField( minimum_balance = models.DecimalField(
verbose_name=_("Minimum balance"), verbose_name=_("minimum balance"),
help_text=_( help_text=_(
"The minimal amount of money allowed for the balance" "The minimal amount of money allowed for the balance at the end"
" at the end of a payment. You can specify negative " " of a payment. You can specify a negative amount."
"amount."
), ),
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
default=0, default=0,
) )
maximum_balance = models.DecimalField( maximum_balance = models.DecimalField(
verbose_name=_("Maximum balance"), verbose_name=_("maximum balance"),
help_text=_("The maximal amount of money allowed for the balance."), help_text=_("The maximal amount of money allowed for the balance."),
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
@ -64,7 +63,7 @@ class BalancePayment(PaymentMethodMixin, models.Model):
null=True, null=True,
) )
credit_balance_allowed = models.BooleanField( credit_balance_allowed = models.BooleanField(
verbose_name=_("Allow user to credit their balance"), default=False verbose_name=_("allow user to credit their balance"), default=False
) )
def end_payment(self, invoice, request): def end_payment(self, invoice, request):

View file

@ -33,7 +33,7 @@ class ChequePayment(PaymentMethodMixin, models.Model):
""" """
class Meta: class Meta:
verbose_name = _("Cheque") verbose_name = _("cheque")
payment = models.OneToOneField( payment = models.OneToOneField(
Paiement, Paiement,

View file

@ -51,9 +51,10 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key") max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key")
) )
minimum_payment = models.DecimalField( minimum_payment = models.DecimalField(
verbose_name=_("Minimum payment"), verbose_name=_("minimum payment"),
help_text=_( help_text=_(
"The minimal amount of money you have to use when paying" " with ComNpay" "The minimal amount of money you have to use when paying with"
" ComNpay."
), ),
max_digits=5, max_digits=5,
decimal_places=2, decimal_places=2,
@ -62,7 +63,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
production = models.BooleanField( production = models.BooleanField(
default=True, default=True,
verbose_name=_( verbose_name=_(
"Production mode enabled (production URL, instead of homologation)" "production mode enabled (production URL, instead of homologation)"
), ),
) )

View file

@ -71,7 +71,7 @@ class PaymentMethodForm(forms.Form):
self.fields["payment_method"].choices = [ self.fields["payment_method"].choices = [
(i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS) (i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS)
] ]
self.fields["payment_method"].choices.insert(0, ("", _("no"))) self.fields["payment_method"].choices.insert(0, ("", _("No")))
self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"} self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"}
self.templates = [ self.templates = [
forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix) forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix)

View file

@ -51,4 +51,4 @@ class FreePayment(PaymentMethodMixin, models.Model):
"""Checks that the price meets the requirement to be paid with user """Checks that the price meets the requirement to be paid with user
balance. balance.
""" """
return (price == 0, _("You cannot validate this invoice for free.")) return (price == 0, _("You can't pay this invoice for free."))

View file

@ -30,5 +30,5 @@ class NoteCredentialForm(forms.Form):
object. object.
""" """
login = forms.CharField(label=_("pseudo note")) login = forms.CharField(label=_("Username"))
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)

View file

@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<thead> <thead>
<tr> <tr>
<th>{% trans "Payment type" %}</th> <th>{% trans "Payment type" %}</th>
<th>{% trans "Is available for everyone" %}</th> <th>{% trans "Available for everyone" %}</th>
<th>{% trans "Custom payment method" %}</th> <th>{% trans "Custom payment method" %}</th>
<th></th> <th></th>
</tr> </tr>

View file

@ -45,12 +45,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "Profile" %}</th> <th>{% trans "Profile" %}</th>
<th> <th>
{% trans "Last name" as tr_last_name %} {% trans "First name" as tr_first_name %}
{% include 'buttons/sort.html' with prefix='control' col='name' text=tr_last_name %} {% include 'buttons/sort.html' with prefix='control' col='name' text=tr_first_name %}
</th> </th>
<th> <th>
{% trans "First name" as tr_first_name %} {% trans "Surname" as tr_surname %}
{% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_first_name %} {% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_surname %}
</th> </th>
<th> <th>
{% trans "Invoice ID" as tr_invoice_id %} {% trans "Invoice ID" as tr_invoice_id %}
@ -104,8 +104,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
{% trans "Edit" as tr_edit %} {% trans "Confirm" as tr_confirm %}
{% bootstrap_button tr_edit button_type='submit' icon='ok' button_class='btn-success' %} {% bootstrap_button tr_confirm button_type='submit' icon='ok' button_class='btn-success' %}
</form> </form>
{% endblock %} {% endblock %}

View file

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
<h4> <h4>
{% blocktrans %}Warning: are you sure you really want to delete this {{ object_name }} object ( {{ objet }} )?{% endblocktrans %} {% blocktrans %}Warning: are you sure you really want to delete this {{ objet_name }} object ( {{ objet }} )?{% endblocktrans %}
</h4> </h4>
{% trans "Confirm" as tr_confirm %} {% trans "Confirm" as tr_confirm %}
{% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %} {% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %}

View file

@ -6,17 +6,17 @@ Nous vous remercions pour votre achat auprès de {{asso_name}} et nous vous en j
En cas de question, nhésitez pas à nous contacter par mail à {{contact_mail}}. En cas de question, nhésitez pas à nous contacter par mail à {{contact_mail}}.
Cordialement, Respectueusement,
Léquipe de {{asso_name}} Léquipe de {{asso_name}}.
=== English version === === English version ===
Dear {{name}}, Hello {{name}},
Thank you for your purchase. Here is your invoice. Thank you for your purchase at {{asso_name}}. Here is your invoice.
Should you need extra information, you can email us at {{contact_mail}}. Should you need extra information, do not hesitate to email us at {{contact_mail}}.
Best regards, Regards,
{{ asso_name }}'s team The {{ asso_name }} team.

View file

@ -6,17 +6,18 @@ Vous trouverez en pièce jointe un reçu.
Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}. Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.
À bientôt, Respectueusement,
L'équipe de {{asso_name}}. L'équipe de {{asso_name}}.
--- ---
Hello {{name}}!
Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}} until {{ date_end|date:"d/m/Y" }}. Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}} until {{ date_end|date:"d/m/Y" }}.
You will find with this email a subscription voucher. You will find with this email a subscription voucher.
For any information, suggestion or problem, you can contact us via email at To express any comment, suggestion or problem, you can send us an email to {{asso_email}}.
{{asso_email}}.
Regards, Regards,
The {{asso_name}} team. The {{asso_name}} team.

View file

@ -30,14 +30,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Articles" %}{% endblock %} {% block title %}{% trans "Articles" %}{% endblock %}
{% block content %} {% block content %}
<h2>{% trans "List of article types" %}</h2> <h2>{% trans "List of articles" %}</h2>
{% can_create Article %} {% can_create Article %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-article' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-article' %}">
<i class="fa fa-cart-plus"></i> {% trans "Add an article type" %} <i class="fa fa-plus"></i> {% trans "Add an article" %}
</a> </a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-article' %}"> <a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-article' %}">
<i class="fa fa-trash"></i> {% trans "Delete one or several article types" %} <i class="fa fa-trash"></i> {% trans "Delete one or several articles" %}
</a> </a>
{% include 'cotisations/aff_article.html' with article_list=article_list %} {% include 'cotisations/aff_article.html' with article_list=article_list %}
{% endblock %} {% endblock %}

View file

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h2>{% trans "List of banks" %}</h2> <h2>{% trans "List of banks" %}</h2>
{% can_create Banque %} {% can_create Banque %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-banque' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-banque' %}">
<i class="fa fa-cart-plus"></i> {% trans "Add a bank" %} <i class="fa fa-plus"></i> {% trans "Add a bank" %}
</a> </a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-banque' %}"> <a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-banque' %}">

View file

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h2>{% trans "List of payment methods" %}</h2> <h2>{% trans "List of payment methods" %}</h2>
{% can_create Paiement %} {% can_create Paiement %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-paiement' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-paiement' %}">
<i class="fa fa-cart-plus"></i> {% trans "Add a payment method" %} <i class="fa fa-plus"></i> {% trans "Add a payment method" %}
</a> </a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-paiement' %}"> <a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-paiement' %}">

View file

@ -52,7 +52,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% acl_end %} {% acl_end %}
{% can_view_all Article %} {% can_view_all Article %}
<a class="list-group-item list-group-item-info" href="{% url 'cotisations:index-article' %}"> <a class="list-group-item list-group-item-info" href="{% url 'cotisations:index-article' %}">
<i class="fa fa-list-ul"></i> {% trans "Available articles" %} <i class="fa fa-list-ul"></i> {% trans "Articles" %}
</a> </a>
{% acl_end %} {% acl_end %}
{% can_view_all Banque %} {% can_view_all Banque %}

View file

@ -36,7 +36,6 @@ from django.template.loader import get_template
from django.http import HttpResponse from django.http import HttpResponse
from django.conf import settings from django.conf import settings
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from re2o.mixins import AclMixin, RevMixin from re2o.mixins import AclMixin, RevMixin
from preferences.models import CotisationsOption from preferences.models import CotisationsOption

View file

@ -166,6 +166,7 @@ def new_facture(request, user, userid):
"articlelist": article_list, "articlelist": article_list,
"balance": balance, "balance": balance,
"action_name": _("Confirm"), "action_name": _("Confirm"),
"title": _("New invoice"),
}, },
"cotisations/facture.html", "cotisations/facture.html",
request, request,
@ -222,7 +223,7 @@ def new_cost_estimate(request):
"articlesformset": articles_formset, "articlesformset": articles_formset,
"articlelist": articles, "articlelist": articles,
"discount_form": discount_form, "discount_form": discount_form,
"title": _("Cost estimate"), "title": _("New cost estimate"),
}, },
"cotisations/facture.html", "cotisations/facture.html",
request, request,
@ -278,6 +279,7 @@ def new_custom_invoice(request):
"articlesformset": articles_formset, "articlesformset": articles_formset,
"articlelist": articles, "articlelist": articles,
"discount_form": discount_form, "discount_form": discount_form,
"title": _("New custom invoice"),
}, },
"cotisations/facture.html", "cotisations/facture.html",
request, request,
@ -373,7 +375,7 @@ def del_facture(request, facture, **_kwargs):
messages.success(request, _("The invoice was deleted.")) messages.success(request, _("The invoice was deleted."))
return redirect(reverse("cotisations:index")) return redirect(reverse("cotisations:index"))
return form( return form(
{"objet": facture, "objet_name": _("Invoice")}, {"objet": facture, "objet_name": _("invoice")},
"cotisations/delete.html", "cotisations/delete.html",
request, request,
) )
@ -437,7 +439,11 @@ def edit_custom_invoice(request, invoice, **kwargs):
return redirect(reverse("cotisations:index-custom-invoice")) return redirect(reverse("cotisations:index-custom-invoice"))
return form( return form(
{"factureform": invoice_form, "venteform": purchase_form}, {
"factureform": invoice_form,
"venteform": purchase_form,
"title": _("Edit custom invoice"),
},
"cotisations/edit_facture.html", "cotisations/edit_facture.html",
request, request,
) )
@ -501,7 +507,7 @@ def del_cost_estimate(request, estimate, **_kwargs):
messages.success(request, _("The cost estimate was deleted.")) messages.success(request, _("The cost estimate was deleted."))
return redirect(reverse("cotisations:index-cost-estimate")) return redirect(reverse("cotisations:index-cost-estimate"))
return form( return form(
{"objet": estimate, "objet_name": _("Cost estimate")}, {"objet": estimate, "objet_name": _("cost estimate")},
"cotisations/delete.html", "cotisations/delete.html",
request, request,
) )
@ -564,7 +570,7 @@ def del_custom_invoice(request, invoice, **_kwargs):
messages.success(request, _("The invoice was deleted.")) messages.success(request, _("The invoice was deleted."))
return redirect(reverse("cotisations:index-custom-invoice")) return redirect(reverse("cotisations:index-custom-invoice"))
return form( return form(
{"objet": invoice, "objet_name": _("Invoice")}, {"objet": invoice, "objet_name": _("invoice")},
"cotisations/delete.html", "cotisations/delete.html",
request, request,
) )
@ -588,7 +594,11 @@ def add_article(request):
messages.success(request, _("The article was created.")) messages.success(request, _("The article was created."))
return redirect(reverse("cotisations:index-article")) return redirect(reverse("cotisations:index-article"))
return form( return form(
{"factureform": article, "action_name": _("Add"), "title": _("New article")}, {
"factureform": article,
"action_name": _("Add"),
"title": _("New article"),
},
"cotisations/facture.html", "cotisations/facture.html",
request, request,
) )
@ -607,7 +617,11 @@ def edit_article(request, article_instance, **_kwargs):
messages.success(request, _("The article was edited.")) messages.success(request, _("The article was edited."))
return redirect(reverse("cotisations:index-article")) return redirect(reverse("cotisations:index-article"))
return form( return form(
{"factureform": article, "action_name": _("Edit"), "title": _("Edit article")}, {
"factureform": article,
"action_name": _("Edit"),
"title": _("Edit article"),
},
"cotisations/facture.html", "cotisations/facture.html",
request, request,
) )
@ -718,8 +732,8 @@ def del_paiement(request, instances):
messages.error( messages.error(
request, request,
_( _(
"The payment method %(method_name)s can't be deleted \ "The payment method %(method_name)s can't be deleted"
because there are invoices using it." " because there are invoices using it."
) )
% {"method_name": payment_del}, % {"method_name": payment_del},
) )
@ -748,7 +762,11 @@ def add_banque(request):
messages.success(request, _("The bank was created.")) messages.success(request, _("The bank was created."))
return redirect(reverse("cotisations:index-banque")) return redirect(reverse("cotisations:index-banque"))
return form( return form(
{"factureform": bank, "action_name": _("Add"), "title": _("New bank")}, {
"factureform": bank,
"action_name": _("Add"),
"title": _("New bank"),
},
"cotisations/facture.html", "cotisations/facture.html",
request, request,
) )
@ -768,7 +786,11 @@ def edit_banque(request, banque_instance, **_kwargs):
messages.success(request, _("The bank was edited.")) messages.success(request, _("The bank was edited."))
return redirect(reverse("cotisations:index-banque")) return redirect(reverse("cotisations:index-banque"))
return form( return form(
{"factureform": bank, "action_name": _("Edit"), "title": _("Edit bank")}, {
"factureform": bank,
"action_name": _("Edit"),
"title": _("Edit bank"),
},
"cotisations/facture.html", "cotisations/facture.html",
request, request,
) )
@ -802,7 +824,11 @@ def del_banque(request, instances):
) )
return redirect(reverse("cotisations:index-banque")) return redirect(reverse("cotisations:index-banque"))
return form( return form(
{"factureform": bank, "action_name": _("Delete"), "title": _("Delete bank")}, {
"factureform": bank,
"action_name": _("Delete"),
"title": _("Delete bank"),
},
"cotisations/facture.html", "cotisations/facture.html",
request, request,
) )
@ -833,7 +859,7 @@ def control(request):
) )
if control_invoices_form.is_valid(): if control_invoices_form.is_valid():
control_invoices_form.save() control_invoices_form.save()
reversion.set_comment("Controle") reversion.set_comment("Control")
messages.success( messages.success(
request, _("Your changes have been properly taken into account.") request, _("Your changes have been properly taken into account.")
) )

View file

@ -41,6 +41,7 @@ def can_view(user):
can = user.has_module_perms("admin") can = user.has_module_perms("admin")
return ( return (
can, can,
None if can else _("You don't have the right to view this" " application."), None if can else _("You don't have the right to view this"
" application."),
"admin", "admin",
) )

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-05 19:48+0200\n" "POT-Creation-Date: 2019-11-19 23:43+0100\n"
"PO-Revision-Date: 2018-06-23 16:01+0200\n" "PO-Revision-Date: 2018-06-23 16:01+0200\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: logs/acl.py:42 #: logs/acl.py:44
msgid "You don't have the right to view this application." msgid "You don't have the right to view this application."
msgstr "Vous n'avez pas le droit de voir cette application." msgstr "Vous n'avez pas le droit de voir cette application."
@ -159,7 +159,7 @@ msgid "Statistics"
msgstr "Statistiques" msgstr "Statistiques"
#: logs/templates/logs/index.html:32 logs/templates/logs/stats_logs.html:32 #: logs/templates/logs/index.html:32 logs/templates/logs/stats_logs.html:32
#: logs/views.py:422 #: logs/views.py:400
msgid "Actions performed" msgid "Actions performed"
msgstr "Actions effectuées" msgstr "Actions effectuées"
@ -183,7 +183,7 @@ msgstr "Base de données"
msgid "Wiring actions" msgid "Wiring actions"
msgstr "Actions de câblage" msgstr "Actions de câblage"
#: logs/templates/logs/sidebar.html:53 logs/views.py:344 #: logs/templates/logs/sidebar.html:53
msgid "Users" msgid "Users"
msgstr "Utilisateurs" msgstr "Utilisateurs"
@ -199,161 +199,126 @@ msgstr "Statistiques sur la base de données"
msgid "Statistics about users" msgid "Statistics about users"
msgstr "Statistiques sur les utilisateurs" msgstr "Statistiques sur les utilisateurs"
#: logs/views.py:194 #: logs/views.py:175
msgid "Nonexistent revision." msgid "Nonexistent revision."
msgstr "Révision inexistante." msgstr "Révision inexistante."
#: logs/views.py:197 #: logs/views.py:178
msgid "The action was deleted." msgid "The action was deleted."
msgstr "L'action a été supprimée." msgstr "L'action a été supprimée."
#: logs/views.py:230 #: logs/views.py:219
msgid "Category" msgid "Category"
msgstr "Catégorie" msgstr "Catégorie"
#: logs/views.py:231 #: logs/views.py:220
msgid "Number of users (members and clubs)" msgid "Number of users (members and clubs)"
msgstr "Nombre d'utilisateurs (adhérents et clubs)" msgstr "Nombre d'utilisateurs (adhérents et clubs)"
#: logs/views.py:232 #: logs/views.py:221
msgid "Number of members" msgid "Number of members"
msgstr "Nombre d'adhérents" msgstr "Nombre d'adhérents"
#: logs/views.py:233 #: logs/views.py:222
msgid "Number of clubs" msgid "Number of clubs"
msgstr "Nombre de clubs" msgstr "Nombre de clubs"
#: logs/views.py:237 #: logs/views.py:226
msgid "Activated users" msgid "Activated users"
msgstr "Utilisateurs activés" msgstr "Utilisateurs activés"
#: logs/views.py:245 #: logs/views.py:232
msgid "Disabled users" msgid "Disabled users"
msgstr "Utilisateurs désactivés" msgstr "Utilisateurs désactivés"
#: logs/views.py:253 #: logs/views.py:238
msgid "Archived users" msgid "Archived users"
msgstr "Utilisateurs archivés" msgstr "Utilisateurs archivés"
#: logs/views.py:261 #: logs/views.py:244
#, fuzzy msgid "Fully archived users"
#| msgid "Archived users" msgstr "Utilisateurs complètement archivés"
msgid "Full Archived users"
msgstr "Utilisateurs archivés"
#: logs/views.py:269 #: logs/views.py:254
msgid "Not yet active users" msgid "Not yet active users"
msgstr "Utilisateurs pas encore actifs" msgstr "Utilisateurs pas encore actifs"
#: logs/views.py:277 #: logs/views.py:264
msgid "Contributing members" msgid "Contributing members"
msgstr "Adhérents cotisants" msgstr "Adhérents cotisants"
#: logs/views.py:283 #: logs/views.py:270
msgid "Users benefiting from a connection" msgid "Users benefiting from a connection"
msgstr "Utilisateurs bénéficiant d'une connexion" msgstr "Utilisateurs bénéficiant d'une connexion"
#: logs/views.py:289 #: logs/views.py:276
msgid "Banned users" msgid "Banned users"
msgstr "Utilisateurs bannis" msgstr "Utilisateurs bannis"
#: logs/views.py:295 #: logs/views.py:282
msgid "Users benefiting from a free connection" msgid "Users benefiting from a free connection"
msgstr "Utilisateurs bénéficiant d'une connexion gratuite" msgstr "Utilisateurs bénéficiant d'une connexion gratuite"
#: logs/views.py:301 #: logs/views.py:288
msgid "Active interfaces (with access to the network)" msgid "Active interfaces (with access to the network)"
msgstr "Interfaces actives (ayant accès au réseau)" msgstr "Interfaces actives (ayant accès au réseau)"
#: logs/views.py:311 #: logs/views.py:302
msgid "Active interfaces assigned IPv4" msgid "Active interfaces assigned IPv4"
msgstr "Interfaces actives assignées IPv4" msgstr "Interfaces actives assignées IPv4"
#: logs/views.py:324 #: logs/views.py:319
msgid "IP range" msgid "IP range"
msgstr "Plage d'IP" msgstr "Plage d'IP"
#: logs/views.py:325 #: logs/views.py:320
msgid "VLAN" msgid "VLAN"
msgstr "VLAN" msgstr "VLAN"
#: logs/views.py:326 #: logs/views.py:321
msgid "Total number of IP addresses" msgid "Total number of IP addresses"
msgstr "Nombre total d'adresses IP" msgstr "Nombre total d'adresses IP"
#: logs/views.py:327 #: logs/views.py:322
msgid "Number of assigned IP addresses" msgid "Number of assigned IP addresses"
msgstr "Nombre d'adresses IP non assignées" msgstr "Nombre d'adresses IP assignées"
#: logs/views.py:328 #: logs/views.py:323
msgid "Number of IP address assigned to an activated machine" msgid "Number of IP address assigned to an activated machine"
msgstr "Nombre d'adresses IP assignées à une machine activée" msgstr "Nombre d'adresses IP assignées à une machine activée"
#: logs/views.py:329 #: logs/views.py:324
msgid "Number of nonassigned IP addresses" msgid "Number of unassigned IP addresses"
msgstr "Nombre d'adresses IP non assignées" msgstr "Nombre d'adresses IP non assignées"
#: logs/views.py:356 #: logs/views.py:339
msgid "Subscriptions" msgid "Users (members and clubs)"
msgstr "Cotisations" msgstr "Utilisateurs (adhérents et clubs)"
#: logs/views.py:378 logs/views.py:439 #: logs/views.py:385
msgid "Machines"
msgstr "Machines"
#: logs/views.py:405
msgid "Topology" msgid "Topology"
msgstr "Topologie" msgstr "Topologie"
#: logs/views.py:424 #: logs/views.py:401
msgid "Number of actions" msgid "Number of actions"
msgstr "Nombre d'actions" msgstr "Nombre d'actions"
#: logs/views.py:438 logs/views.py:456 logs/views.py:461 logs/views.py:466 #: logs/views.py:426
#: logs/views.py:481 msgid "rights"
msgid "User" msgstr "droits"
msgstr "Utilisateur"
#: logs/views.py:442
msgid "Invoice"
msgstr "Facture"
#: logs/views.py:445
msgid "Ban"
msgstr "Bannissement"
#: logs/views.py:448
msgid "Whitelist"
msgstr "Accès gracieux"
#: logs/views.py:451
msgid "Rights"
msgstr "Droits"
#: logs/views.py:455 #: logs/views.py:455
msgid "School" msgid "actions"
msgstr "Établissement" msgstr "actions"
#: logs/views.py:460 #: logs/views.py:486
msgid "Payment method"
msgstr "Moyen de paiement"
#: logs/views.py:465
msgid "Bank"
msgstr "Banque"
#: logs/views.py:482
msgid "Action"
msgstr "Action"
#: logs/views.py:513
msgid "No model found." msgid "No model found."
msgstr "Aucun modèle trouvé." msgstr "Aucun modèle trouvé."
#: logs/views.py:519 #: logs/views.py:492
msgid "Nonexistent entry." msgid "Nonexistent entry."
msgstr "Entrée inexistante." msgstr "Entrée inexistante."
#: logs/views.py:526 #: logs/views.py:499
msgid "You don't have the right to access this menu." msgid "You don't have the right to access this menu."
msgstr "Vous n'avez pas le droit d'accéder à ce menu." msgstr "Vous n'avez pas le droit d'accéder à ce menu."

View file

@ -241,7 +241,7 @@ def stats_general(request):
Club.objects.filter(state=Club.STATE_ARCHIVE).count(), Club.objects.filter(state=Club.STATE_ARCHIVE).count(),
], ],
"full_archive_users": [ "full_archive_users": [
_("Full Archived users"), _("Fully archived users"),
User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(), User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(),
( (
Adherent.objects.filter( Adherent.objects.filter(
@ -321,7 +321,7 @@ def stats_general(request):
_("Total number of IP addresses"), _("Total number of IP addresses"),
_("Number of assigned IP addresses"), _("Number of assigned IP addresses"),
_("Number of IP address assigned to an activated machine"), _("Number of IP address assigned to an activated machine"),
_("Number of nonassigned IP addresses"), _("Number of unassigned IP addresses"),
], ],
ip_dict, # Data already prepared ip_dict, # Data already prepared
], ],
@ -336,7 +336,7 @@ def stats_models(request):
nombre d'users, d'écoles, de droits, de bannissements, nombre d'users, d'écoles, de droits, de bannissements,
de factures, de ventes, de banque, de machines, etc""" de factures, de ventes, de banque, de machines, etc"""
stats = { stats = {
_("Users"): { _("Users (members and clubs)"): {
"users": [User._meta.verbose_name, User.objects.count()], "users": [User._meta.verbose_name, User.objects.count()],
"adherents": [Adherent._meta.verbose_name, Adherent.objects.count()], "adherents": [Adherent._meta.verbose_name, Adherent.objects.count()],
"clubs": [Club._meta.verbose_name, Club.objects.count()], "clubs": [Club._meta.verbose_name, Club.objects.count()],
@ -350,14 +350,14 @@ def stats_models(request):
"ban": [Ban._meta.verbose_name, Ban.objects.count()], "ban": [Ban._meta.verbose_name, Ban.objects.count()],
"whitelist": [Whitelist._meta.verbose_name, Whitelist.objects.count()], "whitelist": [Whitelist._meta.verbose_name, Whitelist.objects.count()],
}, },
_("Subscriptions"): { Cotisation._meta.verbose_name_plural.title(): {
"factures": [Facture._meta.verbose_name, Facture.objects.count()], "factures": [Facture._meta.verbose_name, Facture.objects.count()],
"vente": [Vente._meta.verbose_name, Vente.objects.count()], "vente": [Vente._meta.verbose_name, Vente.objects.count()],
"cotisation": [Cotisation._meta.verbose_name, Cotisation.objects.count()], "cotisation": [Cotisation._meta.verbose_name, Cotisation.objects.count()],
"article": [Article._meta.verbose_name, Article.objects.count()], "article": [Article._meta.verbose_name, Article.objects.count()],
"banque": [Banque._meta.verbose_name, Banque.objects.count()], "banque": [Banque._meta.verbose_name, Banque.objects.count()],
}, },
_("Machines"): { Machine._meta.verbose_name_plural.title(): {
"machine": [Machine._meta.verbose_name, Machine.objects.count()], "machine": [Machine._meta.verbose_name, Machine.objects.count()],
"typemachine": [ "typemachine": [
MachineType._meta.verbose_name, MachineType._meta.verbose_name,
@ -412,31 +412,31 @@ def stats_users(request):
de moyens de paiements par user, de banque par user, de moyens de paiements par user, de banque par user,
de bannissement par user, etc""" de bannissement par user, etc"""
stats = { stats = {
_("User"): { User._meta.verbose_name: {
_("Machines"): User.objects.annotate(num=Count("machine")).order_by("-num")[ Machine._meta.verbose_name_plural: User.objects.annotate(num=Count("machine")).order_by("-num")[
:10 :10
], ],
_("Invoice"): User.objects.annotate(num=Count("facture")).order_by("-num")[ Facture._meta.verbose_name_plural: User.objects.annotate(num=Count("facture")).order_by("-num")[
:10 :10
], ],
_("Ban"): User.objects.annotate(num=Count("ban")).order_by("-num")[:10], Ban._meta.verbose_name_plural: User.objects.annotate(num=Count("ban")).order_by("-num")[:10],
_("Whitelist"): User.objects.annotate(num=Count("whitelist")).order_by( Whitelist._meta.verbose_name_plural: User.objects.annotate(num=Count("whitelist")).order_by(
"-num" "-num"
)[:10], )[:10],
_("Rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[ _("rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[
:10 :10
], ],
}, },
_("School"): { School._meta.verbose_name: {
_("User"): School.objects.annotate(num=Count("user")).order_by("-num")[:10] User._meta.verbose_name_plural: School.objects.annotate(num=Count("user")).order_by("-num")[:10]
}, },
_("Payment method"): { Paiement._meta.verbose_name: {
_("User"): Paiement.objects.annotate(num=Count("facture")).order_by("-num")[ User._meta.verbose_name_plural: Paiement.objects.annotate(num=Count("facture")).order_by("-num")[
:10 :10
] ]
}, },
_("Bank"): { Banque._meta.verbose_name: {
_("User"): Banque.objects.annotate(num=Count("facture")).order_by("-num")[ User._meta.verbose_name_plural: Banque.objects.annotate(num=Count("facture")).order_by("-num")[
:10 :10
] ]
}, },
@ -451,8 +451,8 @@ def stats_actions(request):
utilisateurs. utilisateurs.
Affiche le nombre de modifications aggrégées par utilisateurs""" Affiche le nombre de modifications aggrégées par utilisateurs"""
stats = { stats = {
_("User"): { User._meta.verbose_name: {
_("Action"): User.objects.annotate(num=Count("revision")).order_by("-num")[ _("actions"): User.objects.annotate(num=Count("revision")).order_by("-num")[
:40 :40
] ]
} }

View file

@ -41,6 +41,7 @@ def can_view(user):
can = user.has_module_perms("machines") can = user.has_module_perms("machines")
return ( return (
can, can,
None if can else _("You don't have the right to view this" " application."), None if can else _("You don't have the right to view this"
" application."),
("machines",), ("machines",),
) )

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-11-20 00:59
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('machines', '0105_dname_ttl'),
]
operations = [
migrations.AlterModelOptions(
name='domain',
options={'permissions': (('view_domain', 'Can view a domain object'), ('change_ttl', 'Can change the TTL of a domain object')), 'verbose_name': 'domain', 'verbose_name_plural': 'domains'},
),
migrations.AlterField(
model_name='extension',
name='dnssec',
field=models.BooleanField(default=False, help_text='Should the zone be signed with DNSSEC.'),
),
migrations.AlterField(
model_name='extension',
name='name',
field=models.CharField(help_text='Zone name, must begin with a dot (.example.org).', max_length=255, unique=True),
),
migrations.AlterField(
model_name='extension',
name='origin',
field=models.ForeignKey(blank=True, help_text='A record associated with the zone.', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpList'),
),
migrations.AlterField(
model_name='extension',
name='origin_v6',
field=models.GenericIPAddressField(blank=True, help_text='AAAA record associated with the zone.', null=True, protocol='IPv6'),
),
migrations.AlterField(
model_name='iptype',
name='domaine_ip_netmask',
field=models.IntegerField(default=24, help_text="Netmask for the domain's IPv4 range.", validators=[django.core.validators.MaxValueValidator(31), django.core.validators.MinValueValidator(8)]),
),
migrations.AlterField(
model_name='iptype',
name='domaine_ip_network',
field=models.GenericIPAddressField(blank=True, help_text="Network containing the domain's IPv4 range (optional).", null=True, protocol='IPv4'),
),
migrations.AlterField(
model_name='iptype',
name='reverse_v4',
field=models.BooleanField(default=False, help_text='Enable reverse DNS for IPv4.'),
),
migrations.AlterField(
model_name='iptype',
name='reverse_v6',
field=models.BooleanField(default=False, help_text='Enable reverse DNS for IPv6.'),
),
migrations.AlterField(
model_name='machine',
name='name',
field=models.CharField(blank=True, help_text='Optional.', max_length=255, null=True),
),
migrations.AlterField(
model_name='soa',
name='expire',
field=models.PositiveIntegerField(default=3600000, help_text='Seconds before the secondary DNS stop answering requests in case of primary DNS timeout.'),
),
migrations.AlterField(
model_name='soa',
name='mail',
field=models.EmailField(help_text='Contact email address for the zone.', max_length=254),
),
migrations.AlterField(
model_name='soa',
name='refresh',
field=models.PositiveIntegerField(default=86400, help_text='Seconds before the secondary DNS have to ask the primary DNS serial to detect a modification.'),
),
migrations.AlterField(
model_name='soa',
name='retry',
field=models.PositiveIntegerField(default=7200, help_text='Seconds before the secondary DNS ask the serial again in case of a primary DNS timeout.'),
),
migrations.AlterField(
model_name='soa',
name='ttl',
field=models.PositiveIntegerField(default=172800, help_text='Time To Live.'),
),
migrations.AlterField(
model_name='srv',
name='port',
field=models.PositiveIntegerField(help_text='TCP/UDP port.', validators=[django.core.validators.MaxValueValidator(65535)]),
),
migrations.AlterField(
model_name='srv',
name='priority',
field=models.PositiveIntegerField(default=0, help_text='Priority of the target server (positive integer value, the lower it is, the more the server will be used if available).', validators=[django.core.validators.MaxValueValidator(65535)]),
),
migrations.AlterField(
model_name='srv',
name='target',
field=models.ForeignKey(help_text='Target server.', on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'),
),
migrations.AlterField(
model_name='srv',
name='ttl',
field=models.PositiveIntegerField(default=172800, help_text='Time To Live.'),
),
migrations.AlterField(
model_name='srv',
name='weight',
field=models.PositiveIntegerField(default=0, help_text='Relative weight for records with the same priority (integer value between 0 and 65535).', validators=[django.core.validators.MaxValueValidator(65535)]),
),
migrations.AlterField(
model_name='sshfp',
name='comment',
field=models.CharField(blank=True, help_text='Comment.', max_length=255, null=True),
),
migrations.AlterField(
model_name='sshfp',
name='pub_key_entry',
field=models.TextField(help_text='SSH public key.', max_length=2048),
),
migrations.AlterField(
model_name='vlan',
name='igmp',
field=models.BooleanField(default=False, help_text='v4 multicast management.'),
),
migrations.AlterField(
model_name='vlan',
name='mld',
field=models.BooleanField(default=False, help_text='v6 multicast management.'),
),
]

View file

@ -68,7 +68,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
user = models.ForeignKey("users.User", on_delete=models.CASCADE) user = models.ForeignKey("users.User", on_delete=models.CASCADE)
name = models.CharField( name = models.CharField(
max_length=255, help_text=_("Optional"), blank=True, null=True max_length=255, help_text=_("Optional."), blank=True, null=True
) )
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
@ -157,7 +157,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
if user != user_request: if user != user_request:
return ( return (
False, False,
_("You don't have the right to add a machine" " to another user."), _("You don't have the right to add a machine to another"
" user."),
("machines.add_machine",), ("machines.add_machine",),
) )
if user.user_interfaces().count() >= max_lambdauser_interfaces: if user.user_interfaces().count() >= max_lambdauser_interfaces:
@ -185,7 +186,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
if not (user_request.has_perm("machines.change_interface") and can_user): if not (user_request.has_perm("machines.change_interface") and can_user):
return ( return (
False, False,
_("You don't have the right to edit a machine" " of another user."), _("You don't have the right to edit a machine of another"
" user."),
("machines.change_interface",) + permissions, ("machines.change_interface",) + permissions,
) )
return True, None, None return True, None, None
@ -223,7 +225,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
): ):
return ( return (
False, False,
_("You don't have the right to view other machines" " than yours."), _("You don't have the right to view other machines than"
" yours."),
("machines.view_machine",), ("machines.view_machine",),
) )
return True, None, None return True, None, None
@ -358,22 +361,22 @@ class IpType(RevMixin, AclMixin, models.Model):
protocol="IPv4", protocol="IPv4",
null=True, null=True,
blank=True, blank=True,
help_text=_("Network containing the domain's IPv4 range (optional)"), help_text=_("Network containing the domain's IPv4 range (optional)."),
) )
domaine_ip_netmask = models.IntegerField( domaine_ip_netmask = models.IntegerField(
default=24, default=24,
validators=[MaxValueValidator(31), MinValueValidator(8)], validators=[MaxValueValidator(31), MinValueValidator(8)],
help_text=_("Netmask for the domain's IPv4 range"), help_text=_("Netmask for the domain's IPv4 range."),
) )
reverse_v4 = models.BooleanField( reverse_v4 = models.BooleanField(
default=False, help_text=_("Enable reverse DNS for IPv4") default=False, help_text=_("Enable reverse DNS for IPv4.")
) )
prefix_v6 = models.GenericIPAddressField(protocol="IPv6", null=True, blank=True) prefix_v6 = models.GenericIPAddressField(protocol="IPv6", null=True, blank=True)
prefix_v6_length = models.IntegerField( prefix_v6_length = models.IntegerField(
default=64, validators=[MaxValueValidator(128), MinValueValidator(0)] default=64, validators=[MaxValueValidator(128), MinValueValidator(0)]
) )
reverse_v6 = models.BooleanField( reverse_v6 = models.BooleanField(
default=False, help_text=_("Enable reverse DNS for IPv6") default=False, help_text=_("Enable reverse DNS for IPv6.")
) )
vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True) vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True)
ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True) ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True)
@ -553,7 +556,8 @@ class IpType(RevMixin, AclMixin, models.Model):
for element in IpType.objects.all().exclude(pk=self.pk): for element in IpType.objects.all().exclude(pk=self.pk):
if not self.ip_set.isdisjoint(element.ip_set): if not self.ip_set.isdisjoint(element.ip_set):
raise ValidationError( raise ValidationError(
_("The specified range is not disjoint" " from existing ranges.") _("The specified range is not disjoint from existing"
" ranges.")
) )
# On formate le prefix v6 # On formate le prefix v6
if self.prefix_v6: if self.prefix_v6:
@ -604,8 +608,8 @@ class Vlan(RevMixin, AclMixin, models.Model):
arp_protect = models.BooleanField(default=False) arp_protect = models.BooleanField(default=False)
dhcp_snooping = models.BooleanField(default=False) dhcp_snooping = models.BooleanField(default=False)
dhcpv6_snooping = models.BooleanField(default=False) dhcpv6_snooping = models.BooleanField(default=False)
igmp = models.BooleanField(default=False, help_text=_("v4 multicast management")) igmp = models.BooleanField(default=False, help_text=_("v4 multicast management."))
mld = models.BooleanField(default=False, help_text=_("v6 multicast management")) mld = models.BooleanField(default=False, help_text=_("v6 multicast management."))
class Meta: class Meta:
permissions = (("view_vlan", _("Can view a VLAN object")),) permissions = (("view_vlan", _("Can view a VLAN object")),)
@ -653,30 +657,30 @@ class SOA(RevMixin, AclMixin, models.Model):
""" """
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
mail = models.EmailField(help_text=_("Contact email address for the zone")) mail = models.EmailField(help_text=_("Contact email address for the zone."))
refresh = models.PositiveIntegerField( refresh = models.PositiveIntegerField(
default=86400, # 24 hours default=86400, # 24 hours
help_text=_( help_text=_(
"Seconds before the secondary DNS have to ask the primary" "Seconds before the secondary DNS have to ask the primary"
" DNS serial to detect a modification" " DNS serial to detect a modification."
), ),
) )
retry = models.PositiveIntegerField( retry = models.PositiveIntegerField(
default=7200, # 2 hours default=7200, # 2 hours
help_text=_( help_text=_(
"Seconds before the secondary DNS ask the serial again in" "Seconds before the secondary DNS ask the serial again in"
" case of a primary DNS timeout" " case of a primary DNS timeout."
), ),
) )
expire = models.PositiveIntegerField( expire = models.PositiveIntegerField(
default=3600000, # 1000 hours default=3600000, # 1000 hours
help_text=_( help_text=_(
"Seconds before the secondary DNS stop answering requests" "Seconds before the secondary DNS stop answering requests"
" in case of primary DNS timeout" " in case of primary DNS timeout."
), ),
) )
ttl = models.PositiveIntegerField( ttl = models.PositiveIntegerField(
default=172800, help_text=_("Time to Live") # 2 days default=172800, help_text=_("Time To Live.") # 2 days
) )
class Meta: class Meta:
@ -732,7 +736,7 @@ class Extension(RevMixin, AclMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=255, max_length=255,
unique=True, unique=True,
help_text=_("Zone name, must begin with a dot (.example.org)"), help_text=_("Zone name, must begin with a dot (.example.org)."),
) )
need_infra = models.BooleanField(default=False) need_infra = models.BooleanField(default=False)
origin = models.ForeignKey( origin = models.ForeignKey(
@ -740,17 +744,17 @@ class Extension(RevMixin, AclMixin, models.Model):
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
help_text=_("A record associated with the zone"), help_text=_("A record associated with the zone."),
) )
origin_v6 = models.GenericIPAddressField( origin_v6 = models.GenericIPAddressField(
protocol="IPv6", protocol="IPv6",
null=True, null=True,
blank=True, blank=True,
help_text=_("AAAA record associated with the zone"), help_text=_("AAAA record associated with the zone."),
) )
soa = models.ForeignKey("SOA", on_delete=models.CASCADE) soa = models.ForeignKey("SOA", on_delete=models.CASCADE)
dnssec = models.BooleanField( dnssec = models.BooleanField(
default=False, help_text=_("Should the zone be signed with DNSSEC") default=False, help_text=_("Should the zone be signed with DNSSEC.")
) )
class Meta: class Meta:
@ -819,7 +823,7 @@ class Extension(RevMixin, AclMixin, models.Model):
can = user_request.has_perm("machines.use_all_extension") can = user_request.has_perm("machines.use_all_extension")
return ( return (
can, can,
_("You cannot use all extensions.") if not can else None, _("You don't have the right to use all extensions.") if not can else None,
("machines.use_all_extension",), ("machines.use_all_extension",),
) )
@ -943,7 +947,7 @@ class Srv(RevMixin, AclMixin, models.Model):
) )
extension = models.ForeignKey("Extension", on_delete=models.PROTECT) extension = models.ForeignKey("Extension", on_delete=models.PROTECT)
ttl = models.PositiveIntegerField( ttl = models.PositiveIntegerField(
default=172800, help_text=_("Time to Live") # 2 days default=172800, help_text=_("Time To Live.") # 2 days
) )
priority = models.PositiveIntegerField( priority = models.PositiveIntegerField(
default=0, default=0,
@ -951,7 +955,7 @@ class Srv(RevMixin, AclMixin, models.Model):
help_text=_( help_text=_(
"Priority of the target server (positive integer value," "Priority of the target server (positive integer value,"
" the lower it is, the more the server will be used if" " the lower it is, the more the server will be used if"
" available)" " available)."
), ),
) )
weight = models.PositiveIntegerField( weight = models.PositiveIntegerField(
@ -959,14 +963,14 @@ class Srv(RevMixin, AclMixin, models.Model):
validators=[MaxValueValidator(65535)], validators=[MaxValueValidator(65535)],
help_text=_( help_text=_(
"Relative weight for records with the same priority" "Relative weight for records with the same priority"
" (integer value between 0 and 65535)" " (integer value between 0 and 65535)."
), ),
) )
port = models.PositiveIntegerField( port = models.PositiveIntegerField(
validators=[MaxValueValidator(65535)], help_text=_("TCP/UDP port") validators=[MaxValueValidator(65535)], help_text=_("TCP/UDP port.")
) )
target = models.ForeignKey( target = models.ForeignKey(
"Domain", on_delete=models.PROTECT, help_text=_("Target server") "Domain", on_delete=models.PROTECT, help_text=_("Target server.")
) )
class Meta: class Meta:
@ -1023,10 +1027,10 @@ class SshFp(RevMixin, AclMixin, models.Model):
) )
machine = models.ForeignKey("Machine", on_delete=models.CASCADE) machine = models.ForeignKey("Machine", on_delete=models.CASCADE)
pub_key_entry = models.TextField(help_text=_("SSH public key"), max_length=2048) pub_key_entry = models.TextField(help_text=_("SSH public key."), max_length=2048)
algo = models.CharField(choices=ALGO, max_length=32) algo = models.CharField(choices=ALGO, max_length=32)
comment = models.CharField( comment = models.CharField(
help_text=_("Comment"), max_length=255, null=True, blank=True help_text=_("Comment."), max_length=255, null=True, blank=True
) )
@cached_property @cached_property
@ -1128,7 +1132,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
oui = mac.oui oui = mac.oui
vendor = oui.registration().org vendor = oui.registration().org
except NotRegisteredError: except NotRegisteredError:
vendor = "Unknown vendor" vendor = _("Unknown vendor.")
return vendor return vendor
def sync_ipv6_dhcpv6(self): def sync_ipv6_dhcpv6(self):
@ -1201,7 +1205,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
self.ipv4 = free_ips[0] self.ipv4 = free_ips[0]
else: else:
raise ValidationError( raise ValidationError(
_("There is no IP address available in the" " slash.") _("There are no IP addresses available in the slash.")
) )
return return
@ -1214,7 +1218,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
"""Unassign ipv4 to multiple interfaces""" """Unassign ipv4 to multiple interfaces"""
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
interface_list.update(ipv4=None) interface_list.update(ipv4=None)
reversion.set_comment(_("IPv4 unassigning")) reversion.set_comment("IPv4 unassignment")
@classmethod @classmethod
def mass_assign_ipv4(cls, interface_list): def mass_assign_ipv4(cls, interface_list):
@ -1222,7 +1226,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
interface.assign_ipv4() interface.assign_ipv4()
interface.save() interface.save()
reversion.set_comment(_("IPv4 assigning")) reversion.set_comment("IPv4 assignment")
def update_type(self): def update_type(self):
""" Lorsque le machinetype est changé de type d'ip, on réassigne""" """ Lorsque le machinetype est changé de type d'ip, on réassigne"""
@ -1267,7 +1271,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
) )
if interfaces_similar and interfaces_similar.first() != self: if interfaces_similar and interfaces_similar.first() != self:
raise ValidationError( raise ValidationError(
_("Mac address already registered in this Machine Type/Subnet") _("MAC address already registered in this machine type/subnet.")
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@ -1276,7 +1280,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if self.ipv4: if self.ipv4:
if self.machine_type.ip_type != self.ipv4.ip_type: if self.machine_type.ip_type != self.ipv4.ip_type:
raise ValidationError( raise ValidationError(
_("The IPv4 address and the machine type" " don't match.") _("The IPv4 address and the machine type don't match.")
) )
self.validate_unique() self.validate_unique()
super(Interface, self).save(*args, **kwargs) super(Interface, self).save(*args, **kwargs)
@ -1296,7 +1300,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not ( if not (
preferences.models.OptionalMachine.get_cached_value("create_machine") preferences.models.OptionalMachine.get_cached_value("create_machine")
): ):
return False, _("You can't add a machine."), ("machines.add_interface",) return False, _("You don't have the right to add a machine."), ("machines.add_interface",)
max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value( max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value(
"max_lambdauser_interfaces" "max_lambdauser_interfaces"
) )
@ -1328,7 +1332,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
can = user_request.has_perm("machines.change_interface_machine") can = user_request.has_perm("machines.change_interface_machine")
return ( return (
can, can,
_("Permission required to edit the machine.") if not can else None, _("You don't have the right to edit the machine.") if not can else None,
("machines.change_interface_machine",), ("machines.change_interface_machine",),
) )
@ -1345,7 +1349,8 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not (user_request.has_perm("machines.change_interface") and can_user): if not (user_request.has_perm("machines.change_interface") and can_user):
return ( return (
False, False,
_("You don't have the right to edit a machine of" " another user."), _("You don't have the right to edit a machine of another"
" user."),
("machines.change_interface",) + permissions, ("machines.change_interface",) + permissions,
) )
return True, None, None return True, None, None
@ -1363,7 +1368,8 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not (user_request.has_perm("machines.change_interface") and can_user): if not (user_request.has_perm("machines.change_interface") and can_user):
return ( return (
False, False,
_("You don't have the right to edit a machine of" " another user."), _("You don't have the right to edit a machine of another"
" user."),
("machines.change_interface",) + permissions, ("machines.change_interface",) + permissions,
) )
return True, None, None return True, None, None
@ -1411,7 +1417,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
("view_ipv6list", _("Can view an IPv6 addresses list object")), ("view_ipv6list", _("Can view an IPv6 addresses list object")),
( (
"change_ipv6list_slaac_ip", "change_ipv6list_slaac_ip",
_("Can change the SLAAC value of an" " IPv6 addresses list"), _("Can change the SLAAC value of an IPv6 addresses list"),
), ),
) )
verbose_name = _("IPv6 addresses list") verbose_name = _("IPv6 addresses list")
@ -1446,7 +1452,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
can = user_request.has_perm("machines.change_ipv6list_slaac_ip") can = user_request.has_perm("machines.change_ipv6list_slaac_ip")
return ( return (
can, can,
_("Permission required to change the SLAAC value of an IPv6" " address") _("You don't have the right to change the SLAAC value of an IPv6 address.")
if not can if not can
else None, else None,
("machines.change_ipv6list_slaac_ip",), ("machines.change_ipv6list_slaac_ip",),
@ -1465,7 +1471,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not (user_request.has_perm("machines.change_ipv6list") and can_user): if not (user_request.has_perm("machines.change_ipv6list") and can_user):
return ( return (
False, False,
_("You don't have the right to edit a machine of" " another user."), _("You don't have the right to edit a machine of another user."),
("machines.change_ipv6list",), ("machines.change_ipv6list",),
) )
return True, None, None return True, None, None
@ -1483,7 +1489,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not (user_request.has_perm("machines.change_ipv6list") and can_user): if not (user_request.has_perm("machines.change_ipv6list") and can_user):
return ( return (
False, False,
_("You don't have the right to edit a machine of" " another user."), _("You don't have the right to edit a machine of another user."),
("machines.change_ipv6list",) + permissions, ("machines.change_ipv6list",) + permissions,
) )
return True, None, None return True, None, None
@ -1587,7 +1593,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
unique_together = (("name", "extension"),) unique_together = (("name", "extension"),)
permissions = ( permissions = (
("view_domain", _("Can view a domain object")), ("view_domain", _("Can view a domain object")),
("change_ttl", _("Can change TTL of a domain object")), ("change_ttl", _("Can change the TTL of a domain object")),
) )
verbose_name = _("domain") verbose_name = _("domain")
verbose_name_plural = _("domains") verbose_name_plural = _("domains")
@ -1612,20 +1618,20 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if self.get_extension(): if self.get_extension():
self.extension = self.get_extension() self.extension = self.get_extension()
if self.interface_parent and self.cname: if self.interface_parent and self.cname:
raise ValidationError(_("You can't create a both A and CNAME" " record.")) raise ValidationError(_("You can't create a both A and CNAME record."))
if self.cname == self: if self.cname == self:
raise ValidationError( raise ValidationError(
_("You can't create a CNAME record pointing" " to itself.") _("You can't create a CNAME record pointing to itself.")
) )
HOSTNAME_LABEL_PATTERN = re.compile(r"(?!-)[A-Z\d-]+(?<!-)$", re.IGNORECASE) HOSTNAME_LABEL_PATTERN = re.compile(r"(?!-)[A-Z\d-]+(?<!-)$", re.IGNORECASE)
dns = self.name.lower() dns = self.name.lower()
if len(dns) > 63: if len(dns) > 63:
raise ValidationError( raise ValidationError(
_("The domain name %s is too long (over 63" " characters).") % dns _("The domain name %s is too long (over 63 characters).") % dns
) )
if not HOSTNAME_LABEL_PATTERN.match(dns): if not HOSTNAME_LABEL_PATTERN.match(dns):
raise ValidationError( raise ValidationError(
_("The domain name %s contains forbidden" " characters.") % dns _("The domain name %s contains forbidden characters.") % dns
) )
self.validate_unique() self.validate_unique()
super(Domain, self).clean() super(Domain, self).clean()
@ -1753,7 +1759,8 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
): ):
return ( return (
False, False,
_("You don't have the right to view machines other than yours."), _("You don't have the right to view other machines than"
" yours."),
("machines.view_domain",), ("machines.view_domain",),
) )
return True, None, None return True, None, None
@ -1794,7 +1801,7 @@ class IpList(RevMixin, AclMixin, models.Model):
""" Erreur si l'ip_type est incorrect""" """ Erreur si l'ip_type est incorrect"""
if not str(self.ipv4) in self.ip_type.ip_set_as_str: if not str(self.ipv4) in self.ip_type.ip_set_as_str:
raise ValidationError( raise ValidationError(
_("The IPv4 address and the range of the IP" " type don't match.") _("The IPv4 address and the range of the IP type don't match.")
) )
return return
@ -1970,7 +1977,8 @@ class OuverturePortList(RevMixin, AclMixin, models.Model):
class Meta: class Meta:
permissions = ( permissions = (
("view_ouvertureportlist", _("Can view a ports opening list" " object")), ("view_ouvertureportlist", _("Can view a ports opening list"
" object")),
) )
verbose_name = _("ports opening list") verbose_name = _("ports opening list")
verbose_name_plural = _("ports opening lists") verbose_name_plural = _("ports opening lists")

View file

@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<thead> <thead>
<tr> <tr>
<th>{% trans "Extension" %}</th> <th>{% trans "Extension" %}</th>
<th>{% trans "'infra' right required" %}</th> <th>{% blocktrans %}"infra" right required{% endblocktrans %}</th>
<th>{% trans "SOA record" %}</th> <th>{% trans "SOA record" %}</th>
<th>{% trans "A record origin" %}</th> <th>{% trans "A record origin" %}</th>
{% if ipv6_enabled %} {% if ipv6_enabled %}

View file

@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "IP type" %}</th> <th>{% trans "IP type" %}</th>
<th>{% trans "Extension" %}</th> <th>{% trans "Extension" %}</th>
<th>{% trans "'infra' right required" %}</th> <th>{% blocktrans %}"infra" right required{% endblocktrans %}</th>
<th>{% trans "IPv4 range" %}</th> <th>{% trans "IPv4 range" %}</th>
<th>{% trans "v6 prefix" %}</th> <th>{% trans "v6 prefix" %}</th>
<th>{% trans "DNSSEC reverse v4/v6" %}</th> <th>{% trans "DNSSEC reverse v4/v6" %}</th>

View file

@ -31,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<th>{% trans "Service name" %}</th> <th>{% trans "Service name" %}</th>
<th>{% trans "Server" %}</th> <th>{% trans "Server" %}</th>
<th>{% trans "Last regeneration" %}</th> <th>{% trans "Last regeneration" %}</th>
<th>{% trans "Regeneration required" %}</th> <th>{% trans "Regeneration asked" %}</th>
<th>{% trans "Regeneration activated" %}</th> <th>{% trans "Regeneration needed" %}</th>
</tr> </tr>
</thead> </thead>
{% for server in servers_list %} {% for server in servers_list %}

View file

@ -47,11 +47,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div> </div>
<p> <p>
{% trans "Add a port" as value %} <input class="btn btn-primary btn-sm" role="button" value="{% trans "Add a port" %}" id="add_one">
<input class="btn btn-primary btn-sm" role="button" value="value" id="add_one">
</p> </p>
{% trans "Create or edit" as tr_create_or_edit %} {% trans "Confirm" as tr_confirm %}
{% bootstrap_button tr_create_or_edit icon='ok' button_class='btn-success' %} {% bootstrap_button tr_confirm icon='ok' button_class='btn-success' %}
</form> </form>
<script type="text/javascript"> <script type="text/javascript">
var template = `{{ports.empty_form}}`; var template = `{{ports.empty_form}}`;

View file

@ -33,8 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h2>{% trans "List of extensions" %}</h2> <h2>{% trans "List of extensions" %}</h2>
{% can_create Extension %} {% can_create Extension %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-extension' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-extension' %}">
<i class="fa fa-plus"></i> <i class="fa fa-plus"></i> {% trans "Add an extension" %}</a>
{% trans " Add an extension" %}</a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-extension' %}"> <a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-extension' %}">
<i class="fa fa-trash"></i> {% trans "Delete one or several extensions" %} <i class="fa fa-trash"></i> {% trans "Delete one or several extensions" %}

View file

@ -250,7 +250,7 @@ def new_machine(request, user, **_kwargs):
"interfaceform": interface, "interfaceform": interface,
"domainform": domain, "domainform": domain,
"i_mbf_param": i_mbf_param, "i_mbf_param": i_mbf_param,
"action_name": _("Create a machine"), "action_name": _("Add"),
}, },
"machines/machine.html", "machines/machine.html",
request, request,
@ -314,7 +314,7 @@ def del_machine(request, machine, **_kwargs):
reverse("users:profil", kwargs={"userid": str(machine.user.id)}) reverse("users:profil", kwargs={"userid": str(machine.user.id)})
) )
return form( return form(
{"objet": machine, "objet_name": "machine"}, "machines/delete.html", request {"objet": machine, "objet_name": _("machine")}, "machines/delete.html", request
) )
@ -345,7 +345,7 @@ def new_interface(request, machine, **_kwargs):
"interfaceform": interface_form, "interfaceform": interface_form,
"domainform": domain_form, "domainform": domain_form,
"i_mbf_param": i_mbf_param, "i_mbf_param": i_mbf_param,
"action_name": _("Create an interface"), "action_name": _("Add"),
}, },
"machines/machine.html", "machines/machine.html",
request, request,
@ -366,7 +366,7 @@ def del_interface(request, interface, **_kwargs):
reverse("users:profil", kwargs={"userid": str(request.user.id)}) reverse("users:profil", kwargs={"userid": str(request.user.id)})
) )
return form( return form(
{"objet": interface, "objet_name": "interface"}, "machines/delete.html", request {"objet": interface, "objet_name": _("interface")}, "machines/delete.html", request
) )
@ -386,7 +386,7 @@ def new_ipv6list(request, interface, **_kwargs):
reverse("machines:index-ipv6", kwargs={"interfaceid": str(interface.id)}) reverse("machines:index-ipv6", kwargs={"interfaceid": str(interface.id)})
) )
return form( return form(
{"ipv6form": ipv6, "action_name": _("Create an IPv6 addresses list")}, {"ipv6form": ipv6, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -426,7 +426,7 @@ def del_ipv6list(request, ipv6list, **_kwargs):
reverse("machines:index-ipv6", kwargs={"interfaceid": str(interfaceid)}) reverse("machines:index-ipv6", kwargs={"interfaceid": str(interfaceid)})
) )
return form( return form(
{"objet": ipv6list, "objet_name": "ipv6"}, "machines/delete.html", request {"objet": ipv6list, "objet_name": _("IPv6 addresses list")}, "machines/delete.html", request
) )
@ -444,7 +444,7 @@ def new_sshfp(request, machine, **_kwargs):
reverse("machines:index-sshfp", kwargs={"machineid": str(machine.id)}) reverse("machines:index-sshfp", kwargs={"machineid": str(machine.id)})
) )
return form( return form(
{"sshfpform": sshfp, "action_name": _("Create a SSHFP record")}, {"sshfpform": sshfp, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -482,7 +482,7 @@ def del_sshfp(request, sshfp, **_kwargs):
reverse("machines:index-sshfp", kwargs={"machineid": str(machineid)}) reverse("machines:index-sshfp", kwargs={"machineid": str(machineid)})
) )
return form( return form(
{"objet": sshfp, "objet_name": "sshfp"}, "machines/delete.html", request {"objet": sshfp, "objet_name": _("SSHFP record")}, "machines/delete.html", request
) )
@ -498,7 +498,7 @@ def add_iptype(request):
messages.success(request, _("The IP type was created.")) messages.success(request, _("The IP type was created."))
return redirect(reverse("machines:index-iptype")) return redirect(reverse("machines:index-iptype"))
return form( return form(
{"iptypeform": iptype, "action_name": _("Create an IP type")}, {"iptypeform": iptype, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -563,7 +563,7 @@ def add_machinetype(request):
messages.success(request, _("The machine type was created.")) messages.success(request, _("The machine type was created."))
return redirect(reverse("machines:index-machinetype")) return redirect(reverse("machines:index-machinetype"))
return form( return form(
{"machinetypeform": machinetype, "action_name": _("Create a machine" " type")}, {"machinetypeform": machinetype, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -626,7 +626,7 @@ def add_extension(request):
messages.success(request, _("The extension was created.")) messages.success(request, _("The extension was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"extensionform": extension, "action_name": _("Create an extension")}, {"extensionform": extension, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -688,7 +688,7 @@ def add_soa(request):
messages.success(request, _("The SOA record was created.")) messages.success(request, _("The SOA record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"soaform": soa, "action_name": _("Create an SOA record")}, {"soaform": soa, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -740,7 +740,7 @@ def add_mx(request):
messages.success(request, _("The MX record was created.")) messages.success(request, _("The MX record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"mxform": mx, "action_name": _("Create an MX record")}, {"mxform": mx, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -792,7 +792,7 @@ def add_ns(request):
messages.success(request, _("The NS record was created.")) messages.success(request, _("The NS record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"nsform": ns, "action_name": _("Create an NS record")}, {"nsform": ns, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -844,7 +844,7 @@ def add_dname(request):
messages.success(request, _("The DNAME record was created.")) messages.success(request, _("The DNAME record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"dnameform": dname, "action_name": _("Create a DNAME record")}, {"dnameform": dname, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -899,7 +899,7 @@ def add_txt(request):
messages.success(request, _("The TXT record was created.")) messages.success(request, _("The TXT record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"txtform": txt, "action_name": _("Create a TXT record")}, {"txtform": txt, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -951,7 +951,7 @@ def add_srv(request):
messages.success(request, _("The SRV record was created.")) messages.success(request, _("The SRV record was created."))
return redirect(reverse("machines:index-extension")) return redirect(reverse("machines:index-extension"))
return form( return form(
{"srvform": srv, "action_name": _("Create an SRV record")}, {"srvform": srv, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1008,7 +1008,7 @@ def add_alias(request, interface, interfaceid):
reverse("machines:index-alias", kwargs={"interfaceid": str(interfaceid)}) reverse("machines:index-alias", kwargs={"interfaceid": str(interfaceid)})
) )
return form( return form(
{"aliasform": alias, "action_name": _("Create an alias")}, {"aliasform": alias, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1069,7 +1069,7 @@ def add_role(request):
messages.success(request, _("The role was created.")) messages.success(request, _("The role was created."))
return redirect(reverse("machines:index-role")) return redirect(reverse("machines:index-role"))
return form( return form(
{"roleform": role, "action_name": _("Create a role")}, {"roleform": role, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1121,7 +1121,7 @@ def add_service(request):
messages.success(request, _("The service was created.")) messages.success(request, _("The service was created."))
return redirect(reverse("machines:index-service")) return redirect(reverse("machines:index-service"))
return form( return form(
{"serviceform": service, "action_name": _("Create a service")}, {"serviceform": service, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1187,7 +1187,7 @@ def add_vlan(request):
messages.success(request, _("The VLAN was created.")) messages.success(request, _("The VLAN was created."))
return redirect(reverse("machines:index-vlan")) return redirect(reverse("machines:index-vlan"))
return form( return form(
{"vlanform": vlan, "action_name": _("Create a VLAN")}, {"vlanform": vlan, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1239,7 +1239,7 @@ def add_nas(request):
messages.success(request, _("The NAS device was created.")) messages.success(request, _("The NAS device was created."))
return redirect(reverse("machines:index-nas")) return redirect(reverse("machines:index-nas"))
return form( return form(
{"nasform": nas, "action_name": _("Create a NAS device")}, {"nasform": nas, "action_name": _("Add")},
"machines/machine.html", "machines/machine.html",
request, request,
) )
@ -1558,8 +1558,8 @@ def configure_ports(request, interface_instance, **_kwargs):
request, request,
( (
_( _(
"Warning: the IPv4 isn't public, the opening won't have effect" "Warning: the IP address is not public, the opening won't"
" in v4." " have any effect in v4."
) )
), ),
) )
@ -1572,7 +1572,7 @@ def configure_ports(request, interface_instance, **_kwargs):
messages.success(request, _("The ports configuration was edited.")) messages.success(request, _("The ports configuration was edited."))
return redirect(reverse("machines:index")) return redirect(reverse("machines:index"))
return form( return form(
{"interfaceform": interface, "action_name": _("Edit the" " configuration")}, {"interfaceform": interface, "action_name": _("Edit")},
"machines/machine.html", "machines/machine.html",
request, request,
) )

View file

@ -0,0 +1,128 @@
# 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-11-20 01:24+0100\n"
"PO-Revision-Date: 2019-11-16 00:22+0100\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\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"
#: multi_op/forms.py:43
msgid "Dormitory"
msgstr "Résidence"
#: multi_op/preferences/models.py:37
msgid "enabled dorm"
msgstr "résidence activée"
#: multi_op/preferences/models.py:41
msgid "dormitories preferences"
msgstr "préférences de résidences"
#: multi_op/templates/multi_op/aff_room_state.html:36
msgid "Room"
msgstr "Chambre"
#: multi_op/templates/multi_op/aff_room_state.html:37
msgid "Building"
msgstr "Bâtiment"
#: multi_op/templates/multi_op/aff_room_state.html:40
msgid "Connnected to"
msgstr "Connectée à"
#: multi_op/templates/multi_op/aff_room_state.html:41
msgid "User"
msgstr "Utilisateur"
#: multi_op/templates/multi_op/aff_room_state.html:42
msgid "Details"
msgstr "Détails"
#: multi_op/templates/multi_op/aff_room_state.html:43
msgid "End of subscription on"
msgstr "Fin de cotisation le"
#: multi_op/templates/multi_op/aff_room_state.html:44
msgid "Internet access"
msgstr "Accès Internet"
#: multi_op/templates/multi_op/aff_room_state.html:45
msgid "Action"
msgstr "Action"
#: multi_op/templates/multi_op/aff_room_state.html:52
msgid "Other operator"
msgstr "Autre opérateur"
#: multi_op/templates/multi_op/aff_room_state.html:53
msgid "None"
msgstr "Aucun"
#: multi_op/templates/multi_op/aff_room_state.html:55
msgid "Non member"
msgstr "Non adhérent"
#: multi_op/templates/multi_op/aff_room_state.html:58
msgid "Active"
msgstr "Actif"
#: multi_op/templates/multi_op/aff_room_state.html:60
msgid "Disabled"
msgstr "Désactivé"
#: multi_op/templates/multi_op/index_room_state.html:30
msgid "Multiple operators"
msgstr "Opérateurs multiples"
#: multi_op/templates/multi_op/index_room_state.html:38
msgid "Room connections"
msgstr "Connexions de chambre"
#: multi_op/templates/multi_op/index_room_state.html:44
msgid "Select dormitory"
msgstr "Sélectionnez la résidence"
#: multi_op/templates/multi_op/navbar.html:2
msgid "Manage the operators"
msgstr "Gérer les opérateurs"
#: multi_op/templates/multi_op/sidebar.html:31
msgid "Room connections state"
msgstr "État des connexions de chambre"
#: multi_op/templates/multi_op/sidebar.html:35
msgid "Sockets to connect"
msgstr "Prises à connecter"
#: multi_op/templates/multi_op/sidebar.html:39
msgid "Sockets to disconnect"
msgstr "Prises à déconnecter"
#: multi_op/views.py:169
#, python-format
msgid "The room %s was disconnected."
msgstr "La chambre %s a été déconnectée."

View file

@ -34,8 +34,8 @@ class Preferences(models.Model):
"topologie.Dormitory", "topologie.Dormitory",
related_name="vlan_tagged", related_name="vlan_tagged",
blank=True, blank=True,
verbose_name=_("Enabled dorm"), verbose_name=_("enabled dorm"),
) )
class Meta: class Meta:
verbose_name = _("Dormitory of connection settings") verbose_name = _("dormitories preferences")

View file

@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Building" as tr_building %} {% trans "Building" as tr_building %}
<th>{% include 'buttons/sort.html' with prefix='building' col='name' text=tr_building %}</th> <th>{% include 'buttons/sort.html' with prefix='building' col='name' text=tr_building %}</th>
<th>{% include 'buttons/sort.html' with prefix='room' col='name' text=tr_room %}</th> <th>{% include 'buttons/sort.html' with prefix='room' col='name' text=tr_room %}</th>
<th>{% trans "Connnected on" %}</th> <th>{% trans "Connnected to" %}</th>
<th>{% trans "User" %}</th> <th>{% trans "User" %}</th>
<th>{% trans "Details" %}</th> <th>{% trans "Details" %}</th>
<th>{% trans "End of subscription on" %}</th> <th>{% trans "End of subscription on" %}</th>
@ -49,10 +49,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<td>{{ room.building }}</td> <td>{{ room.building }}</td>
<td>{{ room.name }}</td> <td>{{ room.name }}</td>
<td>{% if room.port_set.all %}<span class="label label-success">AURORE{% else %}<span class="label label-danger">{% trans "Other operator" %}{% endif %}</span></td> <td>{% if room.port_set.all %}<span class="label label-success">{{ asso_name }}{% else %}<span class="label label-danger">{% trans "Other operator" %}{% endif %}</span></td>
<td>{% if room.adherent %}<a href="{% url 'users:profil' room.adherent.id%}">{{ room.adherent }}</a>{% else %} {% trans "Aucun" %}{% endif %}</td> <td>{% if room.adherent %}<a href="{% url 'users:profil' room.adherent.id%}">{{ room.adherent }}</a>{% else %} {% trans "None" %}{% endif %}</td>
<td>{{ room.details }}</td> <td>{{ room.details }}</td>
<td>{% if room.adherent.is_adherent %}<i class="text-success">{% else %}<i class="text-danger">{% endif %}{% if room.adherent.end_adhesion %}{{ room.adherent.end_adhesion}}{% else %}{% trans "No member" %}{% endif %}</i></td> <td>{% if room.adherent.is_adherent %}<i class="text-success">{% else %}<i class="text-danger">{% endif %}{% if room.adherent.end_adhesion %}{{ room.adherent.end_adhesion}}{% else %}{% trans "Non member" %}{% endif %}</i></td>
<td> <td>
{% if room.adherent.has_access == True %} {% if room.adherent.has_access == True %}
<i class="text-success">{% trans "Active" %}</i> <i class="text-success">{% trans "Active" %}</i>

View file

@ -1,48 +0,0 @@
{% extends 'machines/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
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
Copyright © 2017 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.
{% endcomment %}
{% load bootstrap3 %}
{% load i18n %}
{% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %}
<h2> {% trans "Tickets settings modification" %}</h2>
{% for message in messages %}
<div class="{{ message| bootstrap_message_classes }} alert-dismissable">
<button type="button" class="close" data_dismiss="alert" aria-hidden="true">&#125;</button>
{{ message | safe }}
</div>
{% endfor %}
<form class="form" method="post">
{% csrf_token %}
{% bootstrap_field preferencesform.publish_address %}
{% bootstrap_field preferencesform.mail_language %}
{% bootstrap_button "Editer" button_type="submit" icon='ok' button_class='btn-success' %}
</form>
{% endblock %}

View file

@ -1,58 +0,0 @@
{% extends 'machines/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
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
Copyright © 2017 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.
{% endcomment %}
{% load bootstrap3 %}
{% load massive_bootstrap_form %}
{% load i18n %}
{% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %}
<h2> Ouverture d'un Ticket </h2>
<form class="form" method="post">
{% csrf_token %}
{% if not user.is_authenticated %}
<p>{% trans "Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous puissions vous recontacter." %}</p>
{% bootstrap_field ticketform.email %}
{% endif %}
{% bootstrap_field ticketform.title %}
<br>
<p>{% trans "Description de votre problème. Veuillez fournir le plus d'informations possible afin de faciliter la recherche de solution. Voici quelques informations dont nous pourions avoir besoin:" %}</p>
<ul class="list">
<li>
<p> {% trans "Le type de votre problème (adhesion, connexion, paiement ou autre)." %}</p>
</li>
<li>
<p> {% trans "Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?" %}</p>
</li>
<li>
<p> {% trans "Les endroits dans lequels le problème survient (chez vous, dans une partie commune, dans un batiment en particulier)." %}</p>
</ul>
{% bootstrap_field ticketform.description %}
{% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %}
</form>
{% endblock %}

View file

@ -1,34 +0,0 @@
{% extends 'users/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
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
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.
{% endcomment %}
{% load bootstrap3 %}
{% load i18n %}
{% block title%}{% trans "Tickets" %}{% endblock %}
{% block content %}
<h2>{% trans "Tickets" %}</h2>
{% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %}
{% endblock %}

View file

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load acl %} {% load acl %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans "Multi Operators" %}{% endblock %} {% block title %}{% trans "Multiple operators" %}{% endblock %}
{% block content %} {% block content %}
@ -35,17 +35,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% bootstrap_form_errors dormitory_form %} {% bootstrap_form_errors dormitory_form %}
{% endif %} {% endif %}
<h2>{% trans "Rooms connections" %}</h2> <h2>{% trans "Room connections" %}</h2>
{% if dormitory_form %} {% if dormitory_form %}
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
{% bootstrap_form dormitory_form %} {% bootstrap_form dormitory_form %}
{% bootstrap_button "Select Dormitory" icon='ok' button_class='btn-success' %} {% trans "Select dormitory" as tr_select_dorm %}
{% bootstrap_button tr_select_dorm icon='ok' button_class='btn-success' %}
</form> </form>
{% endif %} {% endif %}
{% include 'multi_op/aff_room_state.html' with room_list=room_list %} {% include 'multi_op/aff_room_state.html' with room_list=room_list asso_name=asso_name %}
<br /> <br />
<br /> <br />
<br /> <br />

View file

@ -1,2 +1,2 @@
{% load i18n %} {% load i18n %}
<li><a href="{% url 'multi_op:aff-state-global' %}"><i class="fa fa-random"></i> {% trans "Multi Operators" %}</a></li> <li><a href="{% url 'multi_op:aff-state-global' %}"><i class="fa fa-random"></i> {% trans "Manage the operators" %}</a></li>

View file

@ -1,6 +0,0 @@
{% load i18n %}
<li>
<a href="{% url 'tickets:new-ticket' %}">
<i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}
</a>
</li>

View file

@ -1,36 +0,0 @@
{% load i18n %}
<div class="panel panel-default" id="tickets">
<div class="panel-heading" data-toggle="collapse" href="#collapse_tickets">
<h4 class="panel-title">
<a><i class="fa fa-ticket"></i> {% trans "Tickets" %}</a>
</h4>
</div>
<div id="collapse_tickets" class="panel-collapse panel-body collapse">
<a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:edit-preferences-tickets' %}">
<i class="fa fa-edit"></i>
{% trans "Edit" %}
</a>
<p></p>
<div class="table-responsive">
<table class="table">
<tr>
<th><p>{% trans "Publication email address"%}</p></th>
{% if preferences.publish_address %}
<td><p>{{ preferences.publish_address }}</p></td>
{% else %}
<td><p>{% trans "Pas d'adresse, les tickets ne sont pas annoncés" %}</p></td>
{% endif %}
</tr>
<tr>
<th><p>{% trans "Email language" %}</p></th>
<td><p>{{ language }}</p></th>
</tr>
<table class="table">
</table>
</div>
</div>
</div>

View file

@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block sidebar %} {% block sidebar %}
<a class="list-group-item list-group-item-info" href="{% url 'multi_op:aff-state-global' %}"> <a class="list-group-item list-group-item-info" href="{% url 'multi_op:aff-state-global' %}">
<i class="fa fa-random"></i> <i class="fa fa-random"></i>
{% trans "Rooms connection state" %} {% trans "Room connections state" %}
</a> </a>
<a class="list-group-item list-group-item-info" href="{% url 'multi_op:aff-pending-connection' %}"> <a class="list-group-item list-group-item-info" href="{% url 'multi_op:aff-pending-connection' %}">
<i class="fa fa-compress"></i> <i class="fa fa-compress"></i>

View file

@ -41,7 +41,7 @@ from re2o.base import re2o_paginator, SortTable
from re2o.acl import can_view, can_view_all, can_edit, can_create from re2o.acl import can_view, can_view_all, can_edit, can_create
from preferences.models import GeneralOption from preferences.models import GeneralOption, AssoOption
from .forms import DormitoryForm from .forms import DormitoryForm
@ -67,7 +67,15 @@ def display_rooms_connection(request, dormitory=None):
) )
pagination_number = GeneralOption.get_cached_value("pagination_number") pagination_number = GeneralOption.get_cached_value("pagination_number")
room_list = re2o_paginator(request, room_list, pagination_number) room_list = re2o_paginator(request, room_list, pagination_number)
return render(request, "multi_op/index_room_state.html", {"room_list": room_list}) asso_name = AssoOption.get_cached_value("pseudo")
return render(
request,
"multi_op/index_room_state.html",
{
"room_list": room_list,
"asso_name": asso_name,
},
)
@login_required @login_required
@ -105,10 +113,15 @@ def aff_pending_connection(request):
) )
pagination_number = GeneralOption.get_cached_value("pagination_number") pagination_number = GeneralOption.get_cached_value("pagination_number")
room_list = re2o_paginator(request, room_list, pagination_number) room_list = re2o_paginator(request, room_list, pagination_number)
asso_name = AssoOption.get_cached_value("pseudo")
return render( return render(
request, request,
"multi_op/index_room_state.html", "multi_op/index_room_state.html",
{"room_list": room_list, "dormitory_form": dormitory_form}, {
"room_list": room_list,
"dormitory_form": dormitory_form,
"asso_name": asso_name,
},
) )
@ -135,10 +148,15 @@ def aff_pending_disconnection(request):
) )
pagination_number = GeneralOption.get_cached_value("pagination_number") pagination_number = GeneralOption.get_cached_value("pagination_number")
room_list = re2o_paginator(request, room_list, pagination_number) room_list = re2o_paginator(request, room_list, pagination_number)
asso_name = AssoOption.get_cached_value("pseudo")
return render( return render(
request, request,
"multi_op/index_room_state.html", "multi_op/index_room_state.html",
{"room_list": room_list, "dormitory_form": dormitory_form}, {
"room_list": room_list,
"dormitory_form": dormitory_form,
"asso_name": asso_name,
},
) )
@ -148,7 +166,7 @@ def disconnect_room(request, room, roomid):
"""Action of disconnecting a room""" """Action of disconnecting a room"""
room.port_set.clear() room.port_set.clear()
room.save() room.save()
messages.success(request, "Room %s disconnected" % room) messages.success(request, _("The room %s was disconnected.") % room)
return redirect(reverse("multi_op:aff-pending-disconnection")) return redirect(reverse("multi_op:aff-pending-disconnection"))

View file

@ -41,6 +41,7 @@ def can_view(user):
can = user.has_module_perms("preferences") can = user.has_module_perms("preferences")
return ( return (
can, can,
None if can else _("You don't have the right to view this" " application."), None if can else _("You don't have the right to view this"
" application."),
("preferences",), ("preferences",),
) )

View file

@ -81,13 +81,13 @@ class EditOptionalMachineForm(ModelForm):
prefix = kwargs.pop("prefix", self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields["password_machine"].label = _( self.fields["password_machine"].label = _(
"Possibility to set a" " password per machine" "Possibility to set a password per machine"
) )
self.fields["max_lambdauser_interfaces"].label = _( self.fields["max_lambdauser_interfaces"].label = _(
"Maximum number of" " interfaces" " allowed for a" " standard user" "Maximum number of interfaces allowed for a standard user"
) )
self.fields["max_lambdauser_aliases"].label = _( self.fields["max_lambdauser_aliases"].label = _(
"Maximum number of DNS" " aliases allowed for" " a standard user" "Maximum number of DNS aliases allowed for a standard user"
) )
self.fields["ipv6_mode"].label = _("IPv6 mode") self.fields["ipv6_mode"].label = _("IPv6 mode")
self.fields["create_machine"].label = _("Can create a machine") self.fields["create_machine"].label = _("Can create a machine")
@ -136,20 +136,20 @@ class EditGeneralOptionForm(ModelForm):
self.fields["general_message_fr"].label = _("General message in French") self.fields["general_message_fr"].label = _("General message in French")
self.fields["general_message_en"].label = _("General message in English") self.fields["general_message_en"].label = _("General message in English")
self.fields["search_display_page"].label = _( self.fields["search_display_page"].label = _(
"Number of results" " displayed when" " searching" "Number of results displayed when searching"
) )
self.fields["pagination_number"].label = _( self.fields["pagination_number"].label = _(
"Number of items per page," " standard size (e.g." " users)" "Number of items per page, standard size (e.g. users)"
) )
self.fields["pagination_large_number"].label = _( self.fields["pagination_large_number"].label = _(
"Number of items per" " page, large size" " (e.g. machines)" "Number of items per page, large size (e.g. machines)"
) )
self.fields["req_expire_hrs"].label = _( self.fields["req_expire_hrs"].label = _(
"Time before expiration of the" " reset password link (in" " hours)" "Time before expiration of the reset password link (in hours)"
) )
self.fields["site_name"].label = _("Website name") self.fields["site_name"].label = _("Website name")
self.fields["email_from"].label = _("Email address for automatic" " emailing") self.fields["email_from"].label = _("Email address for automatic emailing")
self.fields["GTU_sum_up"].label = _("Summary of the General Terms of" " Use") self.fields["GTU_sum_up"].label = _("Summary of the General Terms of Use")
self.fields["GTU"].label = _("General Terms of Use") self.fields["GTU"].label = _("General Terms of Use")
@ -171,7 +171,7 @@ class EditAssoOptionForm(ModelForm):
self.fields["telephone"].label = _("Telephone number") self.fields["telephone"].label = _("Telephone number")
self.fields["pseudo"].label = _("Usual name") self.fields["pseudo"].label = _("Usual name")
self.fields["utilisateur_asso"].label = _( self.fields["utilisateur_asso"].label = _(
"Account used for editing" " from /admin" "Account used for editing from /admin"
) )
self.fields["description"].label = _("Description") self.fields["description"].label = _("Description")
@ -187,10 +187,10 @@ class EditMailMessageOptionForm(ModelForm):
prefix = kwargs.pop("prefix", self.Meta.model.__name__) prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs) super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields["welcome_mail_fr"].label = _( self.fields["welcome_mail_fr"].label = _(
"Message for the French" " welcome email" "Message for the French welcome email"
) )
self.fields["welcome_mail_en"].label = _( self.fields["welcome_mail_en"].label = _(
"Message for the English" " welcome email" "Message for the English welcome email"
) )
@ -451,7 +451,7 @@ class DelDocumentTemplateForm(FormRevMixin, Form):
document_templates = forms.ModelMultipleChoiceField( document_templates = forms.ModelMultipleChoiceField(
queryset=DocumentTemplate.objects.none(), queryset=DocumentTemplate.objects.none(),
label=_("Available document templates"), label=_("Current document templates"),
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
) )

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,289 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-11-20 00:59
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import preferences.models
import re2o.aes_field
class Migration(migrations.Migration):
dependencies = [
('preferences', '0066_optionalmachine_default_dns_ttl'),
]
operations = [
migrations.AlterModelOptions(
name='assooption',
options={'permissions': (('view_assooption', 'Can view the organisation preferences'),), 'verbose_name': 'organisation preferences'},
),
migrations.AlterModelOptions(
name='cotisationsoption',
options={'verbose_name': 'subscription preferences'},
),
migrations.AlterModelOptions(
name='generaloption',
options={'permissions': (('view_generaloption', 'Can view the general preferences'),), 'verbose_name': 'general preferences'},
),
migrations.AlterModelOptions(
name='homeoption',
options={'permissions': (('view_homeoption', 'Can view the homepage preferences'),), 'verbose_name': 'homepage preferences'},
),
migrations.AlterModelOptions(
name='mailmessageoption',
options={'permissions': (('view_mailmessageoption', 'Can view the email message preferences'),), 'verbose_name': 'email message preferences'},
),
migrations.AlterModelOptions(
name='mandate',
options={'permissions': (('view_mandate', 'Can view a mandate object'),), 'verbose_name': 'mandate', 'verbose_name_plural': 'mandates'},
),
migrations.AlterModelOptions(
name='optionalmachine',
options={'permissions': (('view_optionalmachine', 'Can view the machine preferences'),), 'verbose_name': 'machine preferences'},
),
migrations.AlterModelOptions(
name='optionaltopologie',
options={'permissions': (('view_optionaltopologie', 'Can view the topology preferences'),), 'verbose_name': 'topology preferences'},
),
migrations.AlterModelOptions(
name='optionaluser',
options={'permissions': (('view_optionaluser', 'Can view the user preferences'),), 'verbose_name': 'user preferences'},
),
migrations.AlterModelOptions(
name='service',
options={'permissions': (('view_service', 'Can view the service preferences'),), 'verbose_name': 'service', 'verbose_name_plural': 'services'},
),
migrations.AlterField(
model_name='cotisationsoption',
name='invoice_template',
field=models.OneToOneField(default=preferences.models.default_invoice, on_delete=django.db.models.deletion.PROTECT, related_name='invoice_template', to='preferences.DocumentTemplate', verbose_name='template for invoices'),
),
migrations.AlterField(
model_name='cotisationsoption',
name='send_voucher_mail',
field=models.BooleanField(default=False, help_text='Be careful, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers.', verbose_name='send voucher by email when the invoice is controlled'),
),
migrations.AlterField(
model_name='cotisationsoption',
name='voucher_template',
field=models.OneToOneField(default=preferences.models.default_voucher, on_delete=django.db.models.deletion.PROTECT, related_name='voucher_template', to='preferences.DocumentTemplate', verbose_name='template for subscription vouchers'),
),
migrations.AlterField(
model_name='generaloption',
name='general_message_en',
field=models.TextField(blank=True, default='', help_text='General message displayed on the English version of the website (e.g. in case of maintenance).'),
),
migrations.AlterField(
model_name='generaloption',
name='general_message_fr',
field=models.TextField(blank=True, default='', help_text='General message displayed on the French version of the website (e.g. in case of maintenance).'),
),
migrations.AlterField(
model_name='mailcontact',
name='address',
field=models.EmailField(default='contact@example.org', help_text='Contact email address.', max_length=254),
),
migrations.AlterField(
model_name='mailmessageoption',
name='welcome_mail_en',
field=models.TextField(blank=True, default='', help_text='Welcome email in English.'),
),
migrations.AlterField(
model_name='mailmessageoption',
name='welcome_mail_fr',
field=models.TextField(blank=True, default='', help_text='Welcome email in French.'),
),
migrations.AlterField(
model_name='mandate',
name='president',
field=models.ForeignKey(blank=True, help_text='Displayed on subscription vouchers.', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='president of the association'),
),
migrations.AlterField(
model_name='optionalmachine',
name='default_dns_ttl',
field=models.PositiveIntegerField(default=172800, verbose_name='default Time To Live (TTL) for CNAME, A and AAAA records'),
),
migrations.AlterField(
model_name='optionalmachine',
name='ipv6_mode',
field=models.CharField(choices=[('SLAAC', 'Automatic configuration by RA'), ('DHCPV6', 'IP addresses assignment by DHCPv6'), ('DISABLED', 'Disabled')], default='DISABLED', max_length=32),
),
migrations.AlterField(
model_name='optionaltopologie',
name='sftp_login',
field=models.CharField(blank=True, help_text='SFTP login for switches.', max_length=32, null=True),
),
migrations.AlterField(
model_name='optionaltopologie',
name='sftp_pass',
field=re2o.aes_field.AESEncryptedField(blank=True, help_text='SFTP password.', max_length=63, null=True),
),
migrations.AlterField(
model_name='optionaltopologie',
name='switchs_ip_type',
field=models.OneToOneField(blank=True, help_text='IP range for the management of switches.', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpType'),
),
migrations.AlterField(
model_name='optionaltopologie',
name='switchs_provision',
field=models.CharField(choices=[('sftp', 'SFTP'), ('tftp', 'TFTP')], default='tftp', help_text='Provision of configuration mode for switches.', max_length=32),
),
migrations.AlterField(
model_name='optionaltopologie',
name='switchs_rest_management',
field=models.BooleanField(default=False, help_text='REST management, activated in case of automatic provision.'),
),
migrations.AlterField(
model_name='optionaltopologie',
name='switchs_web_management',
field=models.BooleanField(default=False, help_text='Web management, activated in case of automatic provision.'),
),
migrations.AlterField(
model_name='optionaltopologie',
name='switchs_web_management_ssl',
field=models.BooleanField(default=False, help_text='SSL web management, make sure that a certificate is installed on the switch.'),
),
migrations.AlterField(
model_name='optionaluser',
name='local_email_domain',
field=models.CharField(default='@example.org', help_text='Domain to use for local email accounts.', max_length=32),
),
migrations.AlterField(
model_name='radiusattribute',
name='attribute',
field=models.CharField(help_text='See https://freeradius.org/rfc/attributes.html.', max_length=255, verbose_name='attribute'),
),
migrations.AlterField(
model_name='radiusattribute',
name='comment',
field=models.TextField(blank=True, default='', help_text='Use this field to document this attribute.', verbose_name='comment'),
),
migrations.AlterField(
model_name='radiusattribute',
name='value',
field=models.CharField(max_length=255, verbose_name='value'),
),
migrations.AlterField(
model_name='radiuskey',
name='comment',
field=models.CharField(blank=True, help_text='Comment for this key.', max_length=255, null=True),
),
migrations.AlterField(
model_name='radiuskey',
name='default_switch',
field=models.BooleanField(default=False, help_text='Default key for switches.'),
),
migrations.AlterField(
model_name='radiuskey',
name='radius_key',
field=re2o.aes_field.AESEncryptedField(help_text='RADIUS key.', max_length=255),
),
migrations.AlterField(
model_name='radiusoption',
name='banned',
field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='policy for banned users'),
),
migrations.AlterField(
model_name='radiusoption',
name='banned_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for banned users.', related_name='banned_attribute', to='preferences.RadiusAttribute', verbose_name='banned users attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='banned_vlan',
field=models.ForeignKey(blank=True, help_text='VLAN for banned users if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='banned_vlan', to='machines.Vlan', verbose_name='banned users VLAN'),
),
migrations.AlterField(
model_name='radiusoption',
name='non_member',
field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='policy for non members'),
),
migrations.AlterField(
model_name='radiusoption',
name='non_member_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for non members.', related_name='non_member_attribute', to='preferences.RadiusAttribute', verbose_name='non members attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='non_member_vlan',
field=models.ForeignKey(blank=True, help_text='VLAN for non members if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='non_member_vlan', to='machines.Vlan', verbose_name='non members VLAN'),
),
migrations.AlterField(
model_name='radiusoption',
name='ok_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for accepted users.', related_name='ok_attribute', to='preferences.RadiusAttribute', verbose_name='accepted users attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='radius_general_policy',
field=models.CharField(choices=[('MACHINE', "On the IP range's VLAN of the machine"), ('DEFINED', 'Preset in "VLAN for machines accepted by RADIUS"')], default='DEFINED', max_length=32),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_machine',
field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='policy for unknown machines'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_machine_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown machines.', related_name='unknown_machine_attribute', to='preferences.RadiusAttribute', verbose_name='unknown machines attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_machine_vlan',
field=models.ForeignKey(blank=True, help_text='VLAN for unknown machines if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_machine_vlan', to='machines.Vlan', verbose_name='unknown machines VLAN'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_port',
field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='policy for unknown ports'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_port_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown ports.', related_name='unknown_port_attribute', to='preferences.RadiusAttribute', verbose_name='unknown ports attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_port_vlan',
field=models.ForeignKey(blank=True, help_text='VLAN for unknown ports if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_port_vlan', to='machines.Vlan', verbose_name='unknown ports VLAN'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_room_attributes',
field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown rooms.', related_name='unknown_room_attribute', to='preferences.RadiusAttribute', verbose_name='unknown rooms attributes'),
),
migrations.AlterField(
model_name='radiusoption',
name='unknown_room_vlan',
field=models.ForeignKey(blank=True, help_text='VLAN for unknown rooms if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_room_vlan', to='machines.Vlan', verbose_name='unknown rooms VLAN'),
),
migrations.AlterField(
model_name='reminder',
name='days',
field=models.IntegerField(default=7, help_text="Delay between the email and the membership's end.", unique=True),
),
migrations.AlterField(
model_name='reminder',
name='message',
field=models.TextField(blank=True, default='', help_text='Message displayed specifically for this reminder.', null=True),
),
migrations.AlterField(
model_name='switchmanagementcred',
name='default_switch',
field=models.BooleanField(default=True, help_text='Default credentials for switches.', unique=True),
),
migrations.AlterField(
model_name='switchmanagementcred',
name='management_id',
field=models.CharField(help_text='Switch login.', max_length=63),
),
migrations.AlterField(
model_name='switchmanagementcred',
name='management_pass',
field=re2o.aes_field.AESEncryptedField(help_text='Password.', max_length=63),
),
]

View file

@ -95,16 +95,16 @@ class OptionalUser(AclMixin, PreferencesModel):
local_email_domain = models.CharField( local_email_domain = models.CharField(
max_length=32, max_length=32,
default="@example.org", default="@example.org",
help_text=_("Domain to use for local email accounts"), help_text=_("Domain to use for local email accounts."),
) )
max_email_address = models.IntegerField( max_email_address = models.IntegerField(
default=15, default=15,
help_text=_("Maximum number of local email addresses for a standard" " user."), help_text=_("Maximum number of local email addresses for a standard user."),
) )
delete_notyetactive = models.IntegerField( delete_notyetactive = models.IntegerField(
default=15, default=15,
help_text=_( help_text=_(
"Not yet active users will be deleted after this number of" " days." "Not yet active users will be deleted after this number of days."
), ),
) )
self_adhesion = models.BooleanField( self_adhesion = models.BooleanField(
@ -122,15 +122,15 @@ class OptionalUser(AclMixin, PreferencesModel):
) )
class Meta: class Meta:
permissions = (("view_optionaluser", _("Can view the user options")),) permissions = (("view_optionaluser", _("Can view the user preferences")),)
verbose_name = _("user options") verbose_name = _("user preferences")
def clean(self): def clean(self):
"""Clean model: """Clean model:
Check the mail_extension Check the mail_extension
""" """
if self.local_email_domain[0] != "@": if self.local_email_domain[0] != "@":
raise ValidationError(_("Email domain must begin with @")) raise ValidationError(_("Email domain must begin with @."))
@receiver(post_save, sender=OptionalUser) @receiver(post_save, sender=OptionalUser)
@ -148,8 +148,8 @@ class OptionalMachine(AclMixin, PreferencesModel):
DHCPV6 = "DHCPV6" DHCPV6 = "DHCPV6"
DISABLED = "DISABLED" DISABLED = "DISABLED"
CHOICE_IPV6 = ( CHOICE_IPV6 = (
(SLAAC, _("Autoconfiguration by RA")), (SLAAC, _("Automatic configuration by RA")),
(DHCPV6, _("IP addresses assigning by DHCPv6")), (DHCPV6, _("IP addresses assignment by DHCPv6")),
(DISABLED, _("Disabled")), (DISABLED, _("Disabled")),
) )
@ -159,7 +159,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
ipv6_mode = models.CharField(max_length=32, choices=CHOICE_IPV6, default="DISABLED") ipv6_mode = models.CharField(max_length=32, choices=CHOICE_IPV6, default="DISABLED")
create_machine = models.BooleanField(default=True) create_machine = models.BooleanField(default=True)
default_dns_ttl = models.PositiveIntegerField( default_dns_ttl = models.PositiveIntegerField(
verbose_name=_("Default Time To Live (TTL) for CNAME, A and AAA records."), verbose_name=_("default Time To Live (TTL) for CNAME, A and AAAA records"),
default=172800, # 2 days default=172800, # 2 days
) )
@ -169,8 +169,8 @@ class OptionalMachine(AclMixin, PreferencesModel):
return not self.get_cached_value("ipv6_mode") == "DISABLED" return not self.get_cached_value("ipv6_mode") == "DISABLED"
class Meta: class Meta:
permissions = (("view_optionalmachine", _("Can view the machine options")),) permissions = (("view_optionalmachine", _("Can view the machine preferences")),)
verbose_name = _("machine options") verbose_name = _("machine preferences")
@receiver(post_save, sender=OptionalMachine) @receiver(post_save, sender=OptionalMachine)
@ -191,43 +191,43 @@ class OptionalTopologie(AclMixin, PreferencesModel):
DEFINED = "DEFINED" DEFINED = "DEFINED"
CHOICE_RADIUS = ( CHOICE_RADIUS = (
(MACHINE, _("On the IP range's VLAN of the machine")), (MACHINE, _("On the IP range's VLAN of the machine")),
(DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")), (DEFINED, _("Preset in \"VLAN for machines accepted by RADIUS\"")),
) )
CHOICE_PROVISION = (("sftp", "sftp"), ("tftp", "tftp")) CHOICE_PROVISION = (("sftp", "SFTP"), ("tftp", "TFTP"))
switchs_web_management = models.BooleanField( switchs_web_management = models.BooleanField(
default=False, default=False,
help_text=_("Web management, activated in case of automatic provision"), help_text=_("Web management, activated in case of automatic provision."),
) )
switchs_web_management_ssl = models.BooleanField( switchs_web_management_ssl = models.BooleanField(
default=False, default=False,
help_text=_( help_text=_(
"SSL web management, make sure that a certificate is" "SSL web management, make sure that a certificate is"
" installed on the switch" " installed on the switch."
), ),
) )
switchs_rest_management = models.BooleanField( switchs_rest_management = models.BooleanField(
default=False, default=False,
help_text=_("REST management, activated in case of automatic provision"), help_text=_("REST management, activated in case of automatic provision."),
) )
switchs_ip_type = models.OneToOneField( switchs_ip_type = models.OneToOneField(
"machines.IpType", "machines.IpType",
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
help_text=_("IP range for the management of switches"), help_text=_("IP range for the management of switches."),
) )
switchs_provision = models.CharField( switchs_provision = models.CharField(
max_length=32, max_length=32,
choices=CHOICE_PROVISION, choices=CHOICE_PROVISION,
default="tftp", default="tftp",
help_text=_("Provision of configuration mode for switches"), help_text=_("Provision of configuration mode for switches."),
) )
sftp_login = models.CharField( sftp_login = models.CharField(
max_length=32, null=True, blank=True, help_text=_("SFTP login for switches") max_length=32, null=True, blank=True, help_text=_("SFTP login for switches.")
) )
sftp_pass = AESEncryptedField( sftp_pass = AESEncryptedField(
max_length=63, null=True, blank=True, help_text=_("SFTP password") max_length=63, null=True, blank=True, help_text=_("SFTP password.")
) )
@cached_property @cached_property
@ -331,8 +331,8 @@ class OptionalTopologie(AclMixin, PreferencesModel):
) )
class Meta: class Meta:
permissions = (("view_optionaltopologie", _("Can view the topology options")),) permissions = (("view_optionaltopologie", _("Can view the topology preferences")),)
verbose_name = _("topology options") verbose_name = _("topology preferences")
@receiver(post_save, sender=OptionalTopologie) @receiver(post_save, sender=OptionalTopologie)
@ -345,12 +345,12 @@ def optionaltopologie_post_save(**kwargs):
class RadiusKey(AclMixin, models.Model): class RadiusKey(AclMixin, models.Model):
"""Class of a radius key""" """Class of a radius key"""
radius_key = AESEncryptedField(max_length=255, help_text=_("RADIUS key")) radius_key = AESEncryptedField(max_length=255, help_text=_("RADIUS key."))
comment = models.CharField( comment = models.CharField(
max_length=255, null=True, blank=True, help_text=_("Comment for this key") max_length=255, null=True, blank=True, help_text=_("Comment for this key.")
) )
default_switch = models.BooleanField( default_switch = models.BooleanField(
default=False, help_text=_("Default key for switches") default=False, help_text=_("Default key for switches.")
) )
class Meta: class Meta:
@ -363,7 +363,7 @@ class RadiusKey(AclMixin, models.Model):
Check default switch is unique Check default switch is unique
""" """
if RadiusKey.objects.filter(default_switch=True).count() > 1: if RadiusKey.objects.filter(default_switch=True).count() > 1:
raise ValidationError(_("Default radiuskey for switchs already exist")) raise ValidationError(_("Default RADIUS key for switches already exists."))
def __str__(self): def __str__(self):
return _("RADIUS key ") + str(self.id) + " " + str(self.comment) return _("RADIUS key ") + str(self.id) + " " + str(self.comment)
@ -372,17 +372,17 @@ class RadiusKey(AclMixin, models.Model):
class SwitchManagementCred(AclMixin, models.Model): class SwitchManagementCred(AclMixin, models.Model):
"""Class of a management creds of a switch, for rest management""" """Class of a management creds of a switch, for rest management"""
management_id = models.CharField(max_length=63, help_text=_("Switch login")) management_id = models.CharField(max_length=63, help_text=_("Switch login."))
management_pass = AESEncryptedField(max_length=63, help_text=_("Password")) management_pass = AESEncryptedField(max_length=63, help_text=_("Password."))
default_switch = models.BooleanField( default_switch = models.BooleanField(
default=True, unique=True, help_text=_("Default credentials for switches") default=True, unique=True, help_text=_("Default credentials for switches.")
) )
class Meta: class Meta:
permissions = ( permissions = (
( (
"view_switchmanagementcred", "view_switchmanagementcred",
_("Can view a switch management" " credentials object"), _("Can view a switch management credentials object"),
), ),
) )
verbose_name = _("switch management credentials") verbose_name = _("switch management credentials")
@ -400,13 +400,13 @@ class Reminder(AclMixin, models.Model):
days = models.IntegerField( days = models.IntegerField(
default=7, default=7,
unique=True, unique=True,
help_text=_("Delay between the email and the membership's end"), help_text=_("Delay between the email and the membership's end."),
) )
message = models.TextField( message = models.TextField(
default="", default="",
null=True, null=True,
blank=True, blank=True,
help_text=_("Message displayed specifically for this reminder"), help_text=_("Message displayed specifically for this reminder."),
) )
class Meta: class Meta:
@ -434,7 +434,7 @@ class GeneralOption(AclMixin, PreferencesModel):
blank=True, blank=True,
help_text=_( help_text=_(
"General message displayed on the French version of the" "General message displayed on the French version of the"
" website (e.g. in case of maintenance)" " website (e.g. in case of maintenance)."
), ),
) )
general_message_en = models.TextField( general_message_en = models.TextField(
@ -442,7 +442,7 @@ class GeneralOption(AclMixin, PreferencesModel):
blank=True, blank=True,
help_text=_( help_text=_(
"General message displayed on the English version of the" "General message displayed on the English version of the"
" website (e.g. in case of maintenance)" " website (e.g. in case of maintenance)."
), ),
) )
search_display_page = models.IntegerField(default=15) search_display_page = models.IntegerField(default=15)
@ -456,8 +456,8 @@ class GeneralOption(AclMixin, PreferencesModel):
GTU = models.FileField(upload_to="", default="", null=True, blank=True) GTU = models.FileField(upload_to="", default="", null=True, blank=True)
class Meta: class Meta:
permissions = (("view_generaloption", _("Can view the general options")),) permissions = (("view_generaloption", _("Can view the general preferences")),)
verbose_name = _("general options") verbose_name = _("general preferences")
@receiver(post_save, sender=GeneralOption) @receiver(post_save, sender=GeneralOption)
@ -477,7 +477,7 @@ class Service(AclMixin, models.Model):
image = models.ImageField(upload_to="logo", blank=True) image = models.ImageField(upload_to="logo", blank=True)
class Meta: class Meta:
permissions = (("view_service", _("Can view the service options")),) permissions = (("view_service", _("Can view the service preferences")),)
verbose_name = _("service") verbose_name = _("service")
verbose_name_plural = _("services") verbose_name_plural = _("services")
@ -489,7 +489,7 @@ class MailContact(AclMixin, models.Model):
"""Contact email adress with a commentary.""" """Contact email adress with a commentary."""
address = models.EmailField( address = models.EmailField(
default="contact@example.org", help_text=_("Contact email address") default="contact@example.org", help_text=_("Contact email address.")
) )
commentary = models.CharField( commentary = models.CharField(
@ -516,17 +516,17 @@ class MailContact(AclMixin, models.Model):
class Mandate(RevMixin, AclMixin, models.Model): class Mandate(RevMixin, AclMixin, models.Model):
class Meta: class Meta:
verbose_name = _("Mandate") verbose_name = _("mandate")
verbose_name_plural = _("Mandates") verbose_name_plural = _("mandates")
permissions = (("view_mandate", _("Can view a mandate")),) permissions = (("view_mandate", _("Can view a mandate object")),)
president = models.ForeignKey( president = models.ForeignKey(
"users.User", "users.User",
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True, null=True,
blank=True, blank=True,
verbose_name=_("President of the association"), verbose_name=_("president of the association"),
help_text=_("Displayed on subscription vouchers"), help_text=_("Displayed on subscription vouchers."),
) )
start_date = models.DateTimeField(verbose_name=_("start date")) start_date = models.DateTimeField(verbose_name=_("start date"))
end_date = models.DateTimeField(verbose_name=_("end date"), blank=True, null=True) end_date = models.DateTimeField(verbose_name=_("end date"), blank=True, null=True)
@ -542,7 +542,7 @@ class Mandate(RevMixin, AclMixin, models.Model):
) )
if not mandate: if not mandate:
raise cls.DoesNotExist( raise cls.DoesNotExist(
"No mandate have been created. Please go to the preferences page to create one." _("No mandates have been created. Please go to the preferences page to create one.")
) )
return mandate return mandate
@ -571,8 +571,8 @@ class AssoOption(AclMixin, PreferencesModel):
description = models.TextField(null=True, blank=True) description = models.TextField(null=True, blank=True)
class Meta: class Meta:
permissions = (("view_assooption", _("Can view the organisation options")),) permissions = (("view_assooption", _("Can view the organisation preferences")),)
verbose_name = _("organisation options") verbose_name = _("organisation preferences")
@receiver(post_save, sender=AssoOption) @receiver(post_save, sender=AssoOption)
@ -590,8 +590,8 @@ class HomeOption(AclMixin, PreferencesModel):
twitter_account_name = models.CharField(max_length=32, null=True, blank=True) twitter_account_name = models.CharField(max_length=32, null=True, blank=True)
class Meta: class Meta:
permissions = (("view_homeoption", _("Can view the homepage options")),) permissions = (("view_homeoption", _("Can view the homepage preferences")),)
verbose_name = _("homepage options") verbose_name = _("homepage preferences")
@receiver(post_save, sender=HomeOption) @receiver(post_save, sender=HomeOption)
@ -605,17 +605,17 @@ class MailMessageOption(AclMixin, models.Model):
"""Reglages, mail de bienvenue et autre""" """Reglages, mail de bienvenue et autre"""
welcome_mail_fr = models.TextField( welcome_mail_fr = models.TextField(
default="", blank=True, help_text=_("Welcome email in French") default="", blank=True, help_text=_("Welcome email in French.")
) )
welcome_mail_en = models.TextField( welcome_mail_en = models.TextField(
default="", blank=True, help_text=_("Welcome email in English") default="", blank=True, help_text=_("Welcome email in English.")
) )
class Meta: class Meta:
permissions = ( permissions = (
("view_mailmessageoption", _("Can view the email message" " options")), ("view_mailmessageoption", _("Can view the email message preferences")),
) )
verbose_name = _("email message options") verbose_name = _("email message preferences")
class RadiusAttribute(RevMixin, AclMixin, models.Model): class RadiusAttribute(RevMixin, AclMixin, models.Model):
@ -625,12 +625,12 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model):
attribute = models.CharField( attribute = models.CharField(
max_length=255, max_length=255,
verbose_name=_("Attribute"), verbose_name=_("attribute"),
help_text=_("See http://freeradius.org/rfc/attributes.html"), help_text=_("See https://freeradius.org/rfc/attributes.html."),
) )
value = models.CharField(max_length=255, verbose_name=_("Value")) value = models.CharField(max_length=255, verbose_name=_("value"))
comment = models.TextField( comment = models.TextField(
verbose_name=_("Comment"), verbose_name=_("comment"),
help_text=_("Use this field to document this attribute."), help_text=_("Use this field to document this attribute."),
blank=True, blank=True,
default="", default="",
@ -649,7 +649,7 @@ class RadiusOption(AclMixin, PreferencesModel):
DEFINED = "DEFINED" DEFINED = "DEFINED"
CHOICE_RADIUS = ( CHOICE_RADIUS = (
(MACHINE, _("On the IP range's VLAN of the machine")), (MACHINE, _("On the IP range's VLAN of the machine")),
(DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")), (DEFINED, _("Preset in \"VLAN for machines accepted by RADIUS\"")),
) )
REJECT = "REJECT" REJECT = "REJECT"
SET_VLAN = "SET_VLAN" SET_VLAN = "SET_VLAN"
@ -664,7 +664,7 @@ class RadiusOption(AclMixin, PreferencesModel):
max_length=32, max_length=32,
choices=CHOICE_POLICY, choices=CHOICE_POLICY,
default=REJECT, default=REJECT,
verbose_name=_("Policy for unknown machines"), verbose_name=_("policy for unknown machines"),
) )
unknown_machine_vlan = models.ForeignKey( unknown_machine_vlan = models.ForeignKey(
"machines.Vlan", "machines.Vlan",
@ -672,21 +672,21 @@ class RadiusOption(AclMixin, PreferencesModel):
related_name="unknown_machine_vlan", related_name="unknown_machine_vlan",
blank=True, blank=True,
null=True, null=True,
verbose_name=_("Unknown machines VLAN"), verbose_name=_("unknown machines VLAN"),
help_text=_("VLAN for unknown machines if not rejected"), help_text=_("VLAN for unknown machines if not rejected."),
) )
unknown_machine_attributes = models.ManyToManyField( unknown_machine_attributes = models.ManyToManyField(
RadiusAttribute, RadiusAttribute,
related_name="unknown_machine_attribute", related_name="unknown_machine_attribute",
blank=True, blank=True,
verbose_name=_("Unknown machines attributes."), verbose_name=_("unknown machines attributes"),
help_text=_("Answer attributes for unknown machines."), help_text=_("Answer attributes for unknown machines."),
) )
unknown_port = models.CharField( unknown_port = models.CharField(
max_length=32, max_length=32,
choices=CHOICE_POLICY, choices=CHOICE_POLICY,
default=REJECT, default=REJECT,
verbose_name=_("Policy for unknown ports"), verbose_name=_("policy for unknown ports"),
) )
unknown_port_vlan = models.ForeignKey( unknown_port_vlan = models.ForeignKey(
"machines.Vlan", "machines.Vlan",
@ -694,14 +694,14 @@ class RadiusOption(AclMixin, PreferencesModel):
related_name="unknown_port_vlan", related_name="unknown_port_vlan",
blank=True, blank=True,
null=True, null=True,
verbose_name=_("Unknown ports VLAN"), verbose_name=_("unknown ports VLAN"),
help_text=_("VLAN for unknown ports if not rejected"), help_text=_("VLAN for unknown ports if not rejected."),
) )
unknown_port_attributes = models.ManyToManyField( unknown_port_attributes = models.ManyToManyField(
RadiusAttribute, RadiusAttribute,
related_name="unknown_port_attribute", related_name="unknown_port_attribute",
blank=True, blank=True,
verbose_name=_("Unknown ports attributes."), verbose_name=_("unknown ports attributes"),
help_text=_("Answer attributes for unknown ports."), help_text=_("Answer attributes for unknown ports."),
) )
unknown_room = models.CharField( unknown_room = models.CharField(
@ -719,21 +719,21 @@ class RadiusOption(AclMixin, PreferencesModel):
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
verbose_name=_("Unknown rooms VLAN"), verbose_name=_("unknown rooms VLAN"),
help_text=_("VLAN for unknown rooms if not rejected"), help_text=_("VLAN for unknown rooms if not rejected."),
) )
unknown_room_attributes = models.ManyToManyField( unknown_room_attributes = models.ManyToManyField(
RadiusAttribute, RadiusAttribute,
related_name="unknown_room_attribute", related_name="unknown_room_attribute",
blank=True, blank=True,
verbose_name=_("Unknown rooms attributes."), verbose_name=_("unknown rooms attributes"),
help_text=_("Answer attributes for unknown rooms."), help_text=_("Answer attributes for unknown rooms."),
) )
non_member = models.CharField( non_member = models.CharField(
max_length=32, max_length=32,
choices=CHOICE_POLICY, choices=CHOICE_POLICY,
default=REJECT, default=REJECT,
verbose_name=_("Policy for non members"), verbose_name=_("policy for non members"),
) )
non_member_vlan = models.ForeignKey( non_member_vlan = models.ForeignKey(
"machines.Vlan", "machines.Vlan",
@ -741,21 +741,21 @@ class RadiusOption(AclMixin, PreferencesModel):
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
verbose_name=_("Non members VLAN"), verbose_name=_("non members VLAN"),
help_text=_("VLAN for non members if not rejected"), help_text=_("VLAN for non members if not rejected."),
) )
non_member_attributes = models.ManyToManyField( non_member_attributes = models.ManyToManyField(
RadiusAttribute, RadiusAttribute,
related_name="non_member_attribute", related_name="non_member_attribute",
blank=True, blank=True,
verbose_name=_("Non member attributes."), verbose_name=_("non members attributes"),
help_text=_("Answer attributes for non members."), help_text=_("Answer attributes for non members."),
) )
banned = models.CharField( banned = models.CharField(
max_length=32, max_length=32,
choices=CHOICE_POLICY, choices=CHOICE_POLICY,
default=REJECT, default=REJECT,
verbose_name=_("Policy for banned users"), verbose_name=_("policy for banned users"),
) )
banned_vlan = models.ForeignKey( banned_vlan = models.ForeignKey(
"machines.Vlan", "machines.Vlan",
@ -763,14 +763,14 @@ class RadiusOption(AclMixin, PreferencesModel):
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
verbose_name=_("Banned users VLAN"), verbose_name=_("banned users VLAN"),
help_text=_("VLAN for banned users if not rejected"), help_text=_("VLAN for banned users if not rejected."),
) )
banned_attributes = models.ManyToManyField( banned_attributes = models.ManyToManyField(
RadiusAttribute, RadiusAttribute,
related_name="banned_attribute", related_name="banned_attribute",
blank=True, blank=True,
verbose_name=_("Banned attributes."), verbose_name=_("banned users attributes"),
help_text=_("Answer attributes for banned users."), help_text=_("Answer attributes for banned users."),
) )
vlan_decision_ok = models.OneToOneField( vlan_decision_ok = models.OneToOneField(
@ -784,7 +784,7 @@ class RadiusOption(AclMixin, PreferencesModel):
RadiusAttribute, RadiusAttribute,
related_name="ok_attribute", related_name="ok_attribute",
blank=True, blank=True,
verbose_name=_("Accepted users attributes."), verbose_name=_("accepted users attributes"),
help_text=_("Answer attributes for accepted users."), help_text=_("Answer attributes for accepted users."),
) )
@ -812,26 +812,27 @@ def default_voucher():
class CotisationsOption(AclMixin, PreferencesModel): class CotisationsOption(AclMixin, PreferencesModel):
class Meta: class Meta:
verbose_name = _("cotisations options") verbose_name = _("subscription preferences")
invoice_template = models.OneToOneField( invoice_template = models.OneToOneField(
"preferences.DocumentTemplate", "preferences.DocumentTemplate",
verbose_name=_("Template for invoices"), verbose_name=_("template for invoices"),
related_name="invoice_template", related_name="invoice_template",
on_delete=models.PROTECT, on_delete=models.PROTECT,
default=default_invoice, default=default_invoice,
) )
voucher_template = models.OneToOneField( voucher_template = models.OneToOneField(
"preferences.DocumentTemplate", "preferences.DocumentTemplate",
verbose_name=_("Template for subscription voucher"), verbose_name=_("template for subscription vouchers"),
related_name="voucher_template", related_name="voucher_template",
on_delete=models.PROTECT, on_delete=models.PROTECT,
default=default_voucher, default=default_voucher,
) )
send_voucher_mail = models.BooleanField( send_voucher_mail = models.BooleanField(
verbose_name=_("Send voucher by email when the invoice is controlled."), verbose_name=_("send voucher by email when the invoice is controlled"),
help_text=_( help_text=_(
"Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers." "Be careful, if no mandate is defined on the preferences page,"
" errors will be triggered when generating vouchers."
), ),
default=False, default=False,
) )

View file

@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% for mandate in mandate_list %} {% for mandate in mandate_list %}
<tr> <tr>
<td>{{mandate.start_date|date:"d/m/Y"}}</td> <td>{{mandate.start_date|date:"d/m/Y"}}</td>
<td>{% if mandate.end_date %}{{mandate.end_date|date:"d/m/Y"}}{% else %}{% trans "In progress." %}{% endif %}</td> <td>{% if mandate.end_date %}{{mandate.end_date|date:"d/m/Y"}}{% else %}{% trans "In progress" %}{% endif %}</td>
<td><a href="{% url 'users:profil' userid=mandate.president.id %}">{{mandate.president.name}} {{mandate.president.surname}}</a></td> <td><a href="{% url 'users:profil' userid=mandate.president.id %}">{{mandate.president.name}} {{mandate.president.surname}}</a></td>
<td class="text-right"> <td class="text-right">
{% can_edit mandate%} {% can_edit mandate%}

View file

@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<th>{% trans "RADIUS key ID" %}</th> <th>{% trans "RADIUS key ID" %}</th>
<th>{% trans "Comment" %}</th> <th>{% trans "Comment" %}</th>
<th>{% trans "Default RADIUS key for switches" %}</th> <th>{% trans "Default RADIUS key for switches" %}</th>
<th>{% trans "RADIUS key used by the swithes" %}</th> <th>{% trans "Switches using the RADIUS key" %}</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>

View file

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "General policy for VLAN setting" %}</th> <th>{% trans "General policy for VLAN setting" %}</th>
<td>{{ radiusoptions.radius_general_policy }}</td> <td>{{ radiusoptions.radius_general_policy }}</td>
<td>{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}</td> <td>{% blocktrans %}This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in "VLAN for machines accepted by RADIUS".{% endblocktrans %}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans "VLAN for machines accepted by RADIUS" %}</th> <th>{% trans "VLAN for machines accepted by RADIUS" %}</th>

View file

@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "Switch login" %}</th> <th>{% trans "Switch login" %}</th>
<th>{% trans "Default switch management credentials" %}</th> <th>{% trans "Default switch management credentials" %}</th>
<th>{% trans "Management credentials used by the switches" %}</th> <th>{% trans "Switches using the management credentials" %}</th>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>

View file

@ -125,7 +125,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "All users are active by default" %}</th> <th>{% trans "All users are active by default" %}</th>
<td>{{ useroptions.all_users_active|tick }}</td> <td>{{ useroptions.all_users_active|tick }}</td>
<th>{% trans "Allow archived users to log-in" %}</th> <th>{% trans "Allow archived users to log in" %}</th>
<td>{{ useroptions.allow_archived_connexion|tick }}</td> <td>{{ useroptions.allow_archived_connexion|tick }}</td>
</tr> </tr>
</table> </table>
@ -156,7 +156,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="panel panel-default" id="machines"> <div class="panel panel-default" id="machines">
<div class="panel-heading" data-toggle="collapse" href="#collapse_machines"> <div class="panel-heading" data-toggle="collapse" href="#collapse_machines">
<h4 class ="panel-title"> <h4 class ="panel-title">
<a><i class="fa fa-desktop"></i> {% trans "Machines preferences" %}</a> <a><i class="fa fa-desktop"></i> {% trans "Machine preferences" %}</a>
</h4> </h4>
</div> </div>
@ -177,7 +177,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr> <tr>
<th>{% trans "Maximum number of DNS aliases allowed for a standard user" %}</th> <th>{% trans "Maximum number of DNS aliases allowed for a standard user" %}</th>
<td>{{ machineoptions.max_lambdauser_aliases }}</td> <td>{{ machineoptions.max_lambdauser_aliases }}</td>
<th>{% trans "Default Time To Live (TTL) for CNAME, A and AAA records." %}</th> <th>{% trans "Default Time To Live (TTL) for CNAME, A and AAAA records." %}</th>
<td>{{ machineoptions.default_dns_ttl }}</td> <td>{{ machineoptions.default_dns_ttl }}</td>
</tr> </tr>
<tr> <tr>
@ -282,7 +282,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Edit" %} {% trans "Edit" %}
</a> </a>
{% include 'preferences/aff_radiusoptions.html' %} {% include 'preferences/aff_radiusoptions.html' %}
<h5>{% trans "Available RADIUS attributes"%}</h5> <h5>{% trans "Current RADIUS attributes"%}</h5>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-radiusattribute' %}"><i class="fa fa-plus"></i>{% trans "Add an attribute" %}</a> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-radiusattribute' %}"><i class="fa fa-plus"></i>{% trans "Add an attribute" %}</a>
{% include 'preferences/aff_radiusattributes.html' %} {% include 'preferences/aff_radiusattributes.html' %}
</div> </div>
@ -346,7 +346,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div id="collapse_templates" class="panel-collapse panel-body collapse"> <div id="collapse_templates" class="panel-collapse panel-body collapse">
{% can_create DocumentTemplate %} {% can_create DocumentTemplate %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-document-template' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-document-template' %}">
<i class="fa fa-cart-plus"></i> {% trans "Add a document template" %} <i class="fa fa-plus"></i> {% trans "Add a document template" %}
</a> </a>
{% acl_end %} {% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'preferences:del-document-template' %}"> <a class="btn btn-danger btn-sm" role="button" href="{% url 'preferences:del-document-template' %}">
@ -359,7 +359,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="panel panel-default" id="cotisation"> <div class="panel panel-default" id="cotisation">
<div class="panel-heading" data-toggle="collapse" href="#collapse_cotisation"> <div class="panel-heading" data-toggle="collapse" href="#collapse_cotisation">
<h4 class="panel-title"> <h4 class="panel-title">
<a><i class="fa fa-eur"></i> {% trans "Cotisation's options" %}</a> <a><i class="fa fa-eur"></i> {% trans "Subscription preferences" %}</a>
</h4> </h4>
</div> </div>
<div id="collapse_cotisation" class="panel-collapse panel-body collapse"> <div id="collapse_cotisation" class="panel-collapse panel-body collapse">
@ -414,7 +414,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="panel panel-default" id="rappels"> <div class="panel panel-default" id="rappels">
<div class="panel-heading" data-toggle="collapse" href="#collapse_rappels"> <div class="panel-heading" data-toggle="collapse" href="#collapse_rappels">
<h4 class="panel-title"> <h4 class="panel-title">
<a><i class="fa fa-bell"></i> {% trans "Options for the membership's end email" %}</a> <a><i class="fa fa-bell"></i> {% trans "Preferences for the membership's end email" %}</a>
</h4> </h4>
</div> </div>
<div id="collapse_rappels" class="panel-collapse panel-body collapse"> <div id="collapse_rappels" class="panel-collapse panel-body collapse">
@ -465,7 +465,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="panel panel-default" id="social"> <div class="panel panel-default" id="social">
<div class="panel-heading" data-toggle="collapse" href="#collapse_social"> <div class="panel-heading" data-toggle="collapse" href="#collapse_social">
<h4 class="panel-title"> <h4 class="panel-title">
<i class="fa fa-twitter"></i> {% trans "Social networks" %}</a> <a><i class="fa fa-twitter"></i> {% trans "Social networks" %}</a>
</h4> </h4>
</div> </div>
<div id="collapse_social" class="panel-collapse panel-body collapse"> <div id="collapse_social" class="panel-collapse panel-body collapse">

View file

@ -191,7 +191,7 @@ def add_service(request):
messages.success(request, _("The service was added.")) messages.success(request, _("The service was added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"preferenceform": service, "action_name": _("Add a service")}, {"preferenceform": service, "action_name": _("Add")},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -224,7 +224,7 @@ def del_service(request, service_instance, **_kwargs):
messages.success(request, _("The service was deleted.")) messages.success(request, _("The service was deleted."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": service_instance, "objet_name": "service"}, {"objet": service_instance, "objet_name": _("service")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -240,7 +240,7 @@ def add_reminder(request):
messages.success(request, _("The reminder was added.")) messages.success(request, _("The reminder was added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"preferenceform": reminder, "action_name": _("Add a reminder")}, {"preferenceform": reminder, "action_name": _("Add")},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -273,7 +273,7 @@ def del_reminder(request, reminder_instance, **_kwargs):
messages.success(request, _("The reminder was deleted.")) messages.success(request, _("The reminder was deleted."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": reminder_instance, "objet_name": "reminder"}, {"objet": reminder_instance, "objet_name": _("reminder")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -289,7 +289,7 @@ def add_radiuskey(request):
messages.success(request, _("The RADIUS key was added.")) messages.success(request, _("The RADIUS key was added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"preferenceform": radiuskey, "action_name": _("Add a RADIUS key")}, {"preferenceform": radiuskey, "action_name": _("Add")},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -328,7 +328,7 @@ def del_radiuskey(request, radiuskey_instance, **_kwargs):
) )
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": radiuskey_instance, "objet_name": "radiuskey"}, {"objet": radiuskey_instance, "objet_name": _("RADIUS key")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -346,7 +346,7 @@ def add_switchmanagementcred(request):
return form( return form(
{ {
"preferenceform": switchmanagementcred, "preferenceform": switchmanagementcred,
"action_name": _("Add switch management credentials"), "action_name": _("Add"),
}, },
"preferences/preferences.html", "preferences/preferences.html",
request, request,
@ -391,7 +391,7 @@ def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
) )
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": switchmanagementcred_instance, "objet_name": "switchmanagementcred"}, {"objet": switchmanagementcred_instance, "objet_name": _("switch management credentials")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -409,7 +409,7 @@ def add_mailcontact(request):
return form( return form(
{ {
"preferenceform": mailcontact, "preferenceform": mailcontact,
"action_name": _("Add a contact email address"), "action_name": _("Add"),
}, },
"preferences/preferences.html", "preferences/preferences.html",
request, request,
@ -524,8 +524,8 @@ def del_document_template(request, instances):
messages.error( messages.error(
request, request,
_( _(
"The document template %(document_template)s can't be deleted \ "The document template %(document_template)s can't be"
because it is currently being used." " deleted because it is currently being used."
) )
% {"document_template": document_template}, % {"document_template": document_template},
) )
@ -551,7 +551,7 @@ def add_radiusattribute(request):
messages.success(request, _("The attribute was added.")) messages.success(request, _("The attribute was added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"preferenceform": attribute, "action_name": _("Add a RADIUS attribute")}, {"preferenceform": attribute, "action_name": _("Add")},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -584,7 +584,7 @@ def del_radiusattribute(request, radiusattribute_instance, **_kwargs):
messages.success(request, _("The attribute was deleted.")) messages.success(request, _("The attribute was deleted."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": radiusattribute_instance, "objet_name": "attribute"}, {"objet": radiusattribute_instance, "objet_name": _("attribute")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -600,7 +600,7 @@ def add_mandate(request):
messages.success(request, _("The mandate was added.")) messages.success(request, _("The mandate was added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"preferenceform": mandate, "action_name": _("Add a mandate")}, {"preferenceform": mandate, "action_name": _("Add")},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -631,7 +631,7 @@ def del_mandate(request, mandate_instance, **_kwargs):
messages.success(request, _("The mandate was deleted.")) messages.success(request, _("The mandate was deleted."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": mandate_instance, "objet_name": "attribute"}, {"objet": mandate_instance, "objet_name": _("mandate")},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )

View file

@ -44,14 +44,14 @@ def acl_error_message(msg, permissions):
if permissions is None: if permissions is None:
return msg return msg
groups = ", ".join([g.name for g in get_group_having_permission(*permissions)]) groups = ", ".join([g.name for g in get_group_having_permission(*permissions)])
message = msg or _("You don't have the right to edit" " this option.") message = msg or _("You don't have the right to edit this option.")
if groups: if groups:
return ( return (
message message
+ _(" You need to be a member of one of those" " groups : %s") % groups + _("You need to be a member of one of these groups: %s.") % groups
) )
else: else:
return message + " No group have the %s permission(s) !" % " or ".join( return message + _("No group has the %s permission(s)!") % " or ".join(
[",".join(permissions[:-1]), permissions[-1]] [",".join(permissions[:-1]), permissions[-1]]
if len(permissions) > 2 if len(permissions) > 2
else permissions else permissions
@ -190,7 +190,7 @@ ModelC)
for msg in error_messages: for msg in error_messages:
messages.error( messages.error(
request, request,
msg or _("You don't have the right to access" " this menu."), msg or _("You don't have the right to access this menu."),
) )
if request.user.id is not None: if request.user.id is not None:
return redirect( return redirect(

View file

@ -96,9 +96,9 @@ def convert_datetime_format(format):
def get_input_formats_help_text(input_formats): def get_input_formats_help_text(input_formats):
"""Returns a help text about the possible input formats""" """Returns a help text about the possible input formats"""
if len(input_formats) > 1: if len(input_formats) > 1:
help_text_template = "Format: {main} {more}" help_text_template = _("Format: {main} {more}")
else: else:
help_text_template = "Format: {main}" help_text_template = _("Format: {main}")
more_text_template = '<i class="fa fa-question-circle" title="{}"></i>' more_text_template = '<i class="fa fa-question-circle" title="{}"></i>'
help_text = help_text_template.format( help_text = help_text_template.format(
main=convert_datetime_format(input_formats[0]), main=convert_datetime_format(input_formats[0]),

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-05 19:48+0200\n" "POT-Creation-Date: 2019-11-20 01:24+0100\n"
"PO-Revision-Date: 2018-03-31 16:09+0002\n" "PO-Revision-Date: 2018-03-31 16:09+0002\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -30,15 +30,29 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: re2o/acl.py:142 #: re2o/acl.py:47
msgid "You don't have the right to edit this option."
msgstr "Vous n'avez pas le droit de modifier cette option."
#: re2o/acl.py:51
#, python-format
msgid "You need to be a member of one of these groups: %s."
msgstr "Vous devez être membre de l'un de ces groupes : %s."
#: re2o/acl.py:54
#, python-format
msgid "No group has the %s permission(s)!"
msgstr "Aucun groupe ne possède la ou les permissions %s !"
#: re2o/acl.py:167
msgid "Nonexistent entry." msgid "Nonexistent entry."
msgstr "Entrée inexistante." msgstr "Entrée inexistante."
#: re2o/acl.py:159 re2o/acl.py:229 #: re2o/acl.py:193 re2o/acl.py:264
msgid "You don't have the right to access this menu." msgid "You don't have the right to access this menu."
msgstr "Vous n'avez pas le droit d'accéder à ce menu." msgstr "Vous n'avez pas le droit d'accéder à ce menu."
#: re2o/acl.py:279 #: re2o/acl.py:314
msgid "You don't have the right to edit the history." msgid "You don't have the right to edit the history."
msgstr "Vous n'avez pas le droit de modifier l'historique." msgstr "Vous n'avez pas le droit de modifier l'historique."
@ -50,57 +64,94 @@ msgstr "Ce domaine est déjà pris."
msgid "SMTP unreachable." msgid "SMTP unreachable."
msgstr "SMTP injoignable." msgstr "SMTP injoignable."
#: re2o/mixins.py:111 #: re2o/base.py:99
#, python-brace-format
msgid "Format: {main} {more}"
msgstr "Format : {main} {more}"
#: re2o/base.py:101
#, python-brace-format
msgid "Format: {main}"
msgstr "Format : {main}"
#: re2o/mixins.py:113
#, python-format #, python-format
msgid "You don't have the right to create a %s object." msgid "You don't have the right to create a %s object."
msgstr "Vous n'avez pas le droit de créer un objet %s." msgstr "Vous n'avez pas le droit de créer un objet %s."
#: re2o/mixins.py:125 #: re2o/mixins.py:129
#, python-format #, python-format
msgid "You don't have the right to edit a %s object." msgid "You don't have the right to edit a %s object."
msgstr "Vous n'avez pas le droit de modifier un objet %s." msgstr "Vous n'avez pas le droit de modifier un objet %s."
#: re2o/mixins.py:139 #: re2o/mixins.py:145
#, python-format #, python-format
msgid "You don't have the right to delete a %s object." msgid "You don't have the right to delete a %s object."
msgstr "Vous n'avez pas le droit de supprimer un objet %s." msgstr "Vous n'avez pas le droit de supprimer un objet %s."
#: re2o/mixins.py:153 #: re2o/mixins.py:161
#, python-format #, python-format
msgid "You don't have the right to view every %s object." msgid "You don't have the right to view every %s object."
msgstr "Vous n'avez pas le droit de voir tous les objets %s." msgstr "Vous n'avez pas le droit de voir tous les objets %s."
#: re2o/mixins.py:167 #: re2o/mixins.py:177
#, python-format #, python-format
msgid "You don't have the right to view a %s object." msgid "You don't have the right to view a %s object."
msgstr "Vous n'avez pas le droit de voir un objet %s." msgstr "Vous n'avez pas le droit de voir un objet %s."
#: re2o/settings.py:158 #: re2o/settings.py:150
msgid "English" msgid "English"
msgstr "Anglais" msgstr "Anglais"
#: re2o/settings.py:159 #: re2o/settings.py:150
msgid "French" msgid "French"
msgstr "Français" msgstr "Français"
#: re2o/templates/re2o/about.html:29 re2o/templates/re2o/about.html:35 #: re2o/templates/re2o/about.html:29 re2o/templates/re2o/about.html:54
msgid "About Re2o" msgid "About Re2o"
msgstr "À propos de Re2o" msgstr "À propos de Re2o"
#: re2o/templates/re2o/about.html:32 #: re2o/templates/re2o/about.html:32
#, python-format msgid "Legal notes"
msgid "About %(AssoName)s" msgstr "Mentions légales"
msgstr "À propos de %(AssoName)s"
#: re2o/templates/re2o/about.html:36 #: re2o/templates/re2o/about.html:34
msgid "Legal entity"
msgstr "Entité légale"
#: re2o/templates/re2o/about.html:37
msgid "Registered office"
msgstr "Siège enregistré"
#: re2o/templates/re2o/about.html:41
msgid "SIRET: "
msgstr "SIRET : "
#: re2o/templates/re2o/about.html:43
msgid "Publication manager"
msgstr "Gestionnaire de publication"
#: re2o/templates/re2o/about.html:44
msgid "President of "
msgstr "Président de "
#: re2o/templates/re2o/about.html:46
msgid "General Terms of Use"
msgstr "Conditions Générales d'Utilisation"
#: re2o/templates/re2o/about.html:50
msgid "Additional information"
msgstr "Informations supplémentaires"
#: re2o/templates/re2o/about.html:55
msgid "" msgid ""
"Re2o is an administration tool initiated by <a href=\"https://rezometz.org/" "Re2o is an administration tool initiated by <a href=\"https://rezometz.org/"
"\">Rezo Metz</a> and a few members of other <a href=\"https://federez.net" "\">Rezo Metz</a> and a few members of other <a href=\"https://federez.net"
"\">FedeRez</a> associations around the summer 2016.<br /> It is intended to " "\">FedeRez</a> associations around the summer 2016.<br /> It is intended to "
"be a tool independant from any network infrastructure so it can be setup in " "be a tool independent from any network infrastructure so it can be setup in "
"\"a few steps\". This tool is entirely free and available under a GNU Public " "\"a few steps\". This tool is entirely free and available under a GNU Public "
"License v2 (GPLv2) license on <a href=\"https://gitlab.federez.net/federez/" "License v2 (GPLv2) license on <a href=\"https://gitlab.federez.net/federez/"
"re2o/\">FedeRez gitlab</a>.<br /> Re2o's mainteners are volunteers mainly " "re2o/\">FedeRez gitlab</a>.<br /> Re2o's maintainers are volunteers mainly "
"from French schools. <br /> If you want to get involved in the development " "from French schools. <br /> If you want to get involved in the development "
"process, we will be glad to welcome you so do not hesitate to contact us and " "process, we will be glad to welcome you so do not hesitate to contact us and "
"come help us build the future of Re2o." "come help us build the future of Re2o."
@ -109,7 +160,7 @@ msgstr ""
"\">Rézo Metz</a> et quelques membres d'autres associations de <a href=" "\">Rézo Metz</a> et quelques membres d'autres associations de <a href="
"\"https://federez.net\">FedeRez</a> autour de l'été 2016.<br /> Il se veut " "\"https://federez.net\">FedeRez</a> autour de l'été 2016.<br /> Il se veut "
"être un outil indépendant de toute infrastructure réseau pour pouvoir être " "être un outil indépendant de toute infrastructure réseau pour pouvoir être "
"installé en \"quelques étapes\". Cet outil est entièrement gratuit et est " "installé en « quelques étapes ». Cet outil est entièrement gratuit et est "
"disponible sous licence GNU Public Licence v2 (GPLv2) sur le <a href=" "disponible sous licence GNU Public Licence v2 (GPLv2) sur le <a href="
"\"https://gitlab.federez.net/federez/re2o/\">gitlab de FedeRez</a>.<br />\n" "\"https://gitlab.federez.net/federez/re2o/\">gitlab de FedeRez</a>.<br />\n"
"Les mainteneurs de Re2o sont de fiers bénévoles venant principalement " "Les mainteneurs de Re2o sont de fiers bénévoles venant principalement "
@ -119,35 +170,35 @@ msgstr ""
"développement, nous serons heureux de vous accueillir donc n'hésitez pas à " "développement, nous serons heureux de vous accueillir donc n'hésitez pas à "
"nous contacter et à venir nous aider à construire le futur de Re2o." "nous contacter et à venir nous aider à construire le futur de Re2o."
#: re2o/templates/re2o/about.html:55 #: re2o/templates/re2o/about.html:74
msgid "Contributors list" msgid "Contributors list"
msgstr "Liste des contributeurs" msgstr "Liste des contributeurs"
#: re2o/templates/re2o/about.html:64 #: re2o/templates/re2o/about.html:83
msgid "Version information" msgid "Version information"
msgstr "Informations de versions" msgstr "Informations de versions"
#: re2o/templates/re2o/about.html:66 #: re2o/templates/re2o/about.html:85
#, python-format #, python-format
msgid "<b>Remote URL</b>: %(git_info_remote)s" msgid "<b>Remote URL</b>: %(git_info_remote)s"
msgstr "<b>URL distante</b> : %(git_info_remote)s" msgstr "<b>URL distante</b> : %(git_info_remote)s"
#: re2o/templates/re2o/about.html:69 #: re2o/templates/re2o/about.html:88
#, python-format #, python-format
msgid "<b>Branch</b>: %(git_info_branch)s" msgid "<b>Branch</b>: %(git_info_branch)s"
msgstr "<b>Branche</b> : %(git_info_branch)s" msgstr "<b>Branche</b> : %(git_info_branch)s"
#: re2o/templates/re2o/about.html:72 #: re2o/templates/re2o/about.html:91
#, python-format #, python-format
msgid "<b>Commit</b>: %(git_info_commit)s" msgid "<b>Commit</b>: %(git_info_commit)s"
msgstr "<b>Commit</b> : %(git_info_commit)s" msgstr "<b>Commit</b> : %(git_info_commit)s"
#: re2o/templates/re2o/about.html:75 #: re2o/templates/re2o/about.html:94
#, python-format #, python-format
msgid "<b>Commit date</b>: %(git_info_commit_date)s" msgid "<b>Commit date</b>: %(git_info_commit_date)s"
msgstr "<b>Date du commit</b> : %(git_info_commit_date)s" msgstr "<b>Date du commit</b> : %(git_info_commit_date)s"
#: re2o/templates/re2o/about.html:80 #: re2o/templates/re2o/about.html:99
msgid "Dependencies" msgid "Dependencies"
msgstr "Dépendances" msgstr "Dépendances"
@ -265,11 +316,9 @@ msgid "Follow @%(twitter_account_name)s"
msgstr "Suivre @%(twitter_account_name)s" msgstr "Suivre @%(twitter_account_name)s"
#: re2o/urls.py:57 #: re2o/urls.py:57
#, fuzzy
#| msgid "Home"
msgid "Homepage" msgid "Homepage"
msgstr "Accueil" msgstr "Page d'accueil"
#: re2o/views.py:89 #: re2o/views.py:96
msgid "Unable to get the information." msgid "Unable to get the information."
msgstr "Impossible d'obtenir l'information." msgstr "Impossible d'obtenir l'information."

View file

@ -80,21 +80,21 @@ def hash_password_salt(hashed_password):
try: try:
digest = b64decode(hashed_password[6:]) digest = b64decode(hashed_password[6:])
except TypeError as error: except TypeError as error:
raise ValueError("b64 error for `hashed_password` : %s" % error) raise ValueError("b64 error for `hashed_password`: %s." % error)
if len(digest) < 20: if len(digest) < 20:
raise ValueError("`hashed_password` too short") raise ValueError("`hashed_password` too short.")
return digest[20:] return digest[20:]
elif hashed_password.upper().startswith("{SMD5}"): elif hashed_password.upper().startswith("{SMD5}"):
try: try:
digest = b64decode(hashed_password[7:]) digest = b64decode(hashed_password[7:])
except TypeError as error: except TypeError as error:
raise ValueError("b64 error for `hashed_password` : %s" % error) raise ValueError("b64 error for `hashed_password`: %s." % error)
if len(digest) < 16: if len(digest) < 16:
raise ValueError("`hashed_password` too short") raise ValueError("`hashed_password` too short.")
return digest[16:] return digest[16:]
else: else:
raise ValueError( raise ValueError(
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'" "`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'."
) )

View file

@ -64,7 +64,7 @@ class Command(BaseCommand):
for item in os.popen("git shortlog -s -n").read().split("\n") for item in os.popen("git shortlog -s -n").read().split("\n")
if "\t" in item if "\t" in item
] ]
self.stdout.write(self.style.SUCCESS("Exportation Successful")) self.stdout.write(self.style.SUCCESS("Exportation successful!"))
with open("re2o/contributors.py", "w") as contrib_file: with open("re2o/contributors.py", "w") as contrib_file:
content = self._contrib_file_generator(contributors) content = self._contrib_file_generator(contributors)
contrib_file.write(content) contrib_file.write(content)

View file

@ -61,7 +61,7 @@ class FormRevMixin(object):
) )
elif self.changed_data: elif self.changed_data:
reversion.set_comment( reversion.set_comment(
"Field(s) altered : %s" "Field(s) edited: %s"
% ", ".join(field for field in self.changed_data) % ", ".join(field for field in self.changed_data)
) )
return super(FormRevMixin, self).save(*args, **kwargs) return super(FormRevMixin, self).save(*args, **kwargs)

View file

@ -53,7 +53,7 @@ def get_user(pseudo):
raise CommandError("Invalid user.") raise CommandError("Invalid user.")
if len(user) > 1: if len(user) > 1:
raise CommandError( raise CommandError(
"Several users match this username. This SHOULD" " NOT happen." "Several users match this username. This SHOULD NOT happen."
) )
return user[0] return user[0]
@ -95,5 +95,5 @@ def form_cli(Form, user, action, *args, **kwargs):
reversion.set_comment(action) reversion.set_comment(action)
sys.stdout.write( sys.stdout.write(
"%s : done. The edit may take several minutes to" " apply.\n" % action "%s: done. The edit may take several minutes to apply.\n" % action
) )

View file

@ -38,16 +38,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<p>{{ option.adresse1 | safe }}</p> <p>{{ option.adresse1 | safe }}</p>
<p>{{ option.adresse2 | safe }}</p> <p>{{ option.adresse2 | safe }}</p>
<p>SIRET : {{ option.siret | safe }}</p> <p>{% trans "SIRET: " %}{{ option.siret | safe }}</p>
<h4>{% trans "Publication manager" %}</h4> <h4>{% trans "Publication manager" %}</h4>
<p>{{ president }} - {% trans "President of " %} {{ option.pseudo }}</p> <p>{{ president }} - {% trans "President of " %} {{ option.pseudo }}</p>
<h4>{% trans "General conditions of use" %}</h4> <h4>{% trans "General Terms of Use" %}</h4>
<p><a href='{{ gtu.url }}' download='CGU'>{{ gtu }}</a></p> <p><a href='{{ gtu.url }}' download='CGU'>{{ gtu }}</a></p>
{% if option.description %} {% if option.description %}
<h4>Extra informations</h4> <h4>{% trans "Additional information" %}</h4>
<p>{{ option.description | safe }}</p> <p>{{ option.description | safe }}</p>
{% endif %} {% endif %}
@ -57,11 +57,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<a href="https://rezometz.org/">Rezo Metz</a> and a few <a href="https://rezometz.org/">Rezo Metz</a> and a few
members of other <a href="https://federez.net">FedeRez</a> associations members of other <a href="https://federez.net">FedeRez</a> associations
around the summer 2016.<br /> around the summer 2016.<br />
It is intended to be a tool independant from any network infrastructure It is intended to be a tool independent from any network infrastructure
so it can be setup in "a few steps". This tool is entirely free and so it can be setup in "a few steps". This tool is entirely free and
available under a GNU Public License v2 (GPLv2) license on available under a GNU Public License v2 (GPLv2) license on
<a href="https://gitlab.federez.net/federez/re2o/">FedeRez gitlab</a>.<br /> <a href="https://gitlab.federez.net/federez/re2o/">FedeRez gitlab</a>.<br />
Re2o's mainteners are volunteers mainly from French schools. <br /> Re2o's maintainers are volunteers mainly from French schools. <br />
If you want to get involved in the development process, we will be glad to If you want to get involved in the development process, we will be glad to
welcome you so do not hesitate to contact us and come help us build the welcome you so do not hesitate to contact us and come help us build the
future of Re2o. future of Re2o.

View file

@ -88,7 +88,7 @@ def get_model(model_name):
app_label, name = splitted app_label, name = splitted
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r is an inconsistent model name" % model_name "%r is an inconsistent model name." % model_name
) )
else: else:
app_label, name = None, splitted[0] app_label, name = None, splitted[0]
@ -101,7 +101,7 @@ def get_model(model_name):
content_type = ContentType.objects.get(model=name.lower()) content_type = ContentType.objects.get(model=name.lower())
except ContentType.DoesNotExist: except ContentType.DoesNotExist:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r is not a valid model for an acl tag" % model_name "%r is not a valid model for an acl tag." % model_name
) )
except ContentType.MultipleObjectsReturned: except ContentType.MultipleObjectsReturned:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
@ -178,7 +178,7 @@ def get_callback(tag_name, obj=None):
True, True,
) )
raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag" % tag_name) raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag." % tag_name)
def acl_fct(callback, reverse): def acl_fct(callback, reverse):
@ -264,7 +264,7 @@ def acl_change_filter(parser, token):
args = tag_content[3:] args = tag_content[3:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 2 argument: the model and the field" "%r tag require at least 2 argument: the model and the field."
% token.contents.split()[0] % token.contents.split()[0]
) )
@ -306,7 +306,7 @@ def acl_model_filter(parser, token):
args = tag_content[2:] args = tag_content[2:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the model" % token.contents.split()[0] "%r tag require at least 1 argument: the model." % token.contents.split()[0]
) )
model = get_model(model_name) model = get_model(model_name)
@ -345,7 +345,7 @@ def acl_instance_filter(parser, token):
args = tag_content[2:] args = tag_content[2:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the instance" "%r tag require at least 1 argument: the instance."
% token.contents.split()[0] % token.contents.split()[0]
) )

View file

@ -46,7 +46,7 @@ from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import RedirectView from django.views.generic import RedirectView
from .settings_local import OPTIONNAL_APPS_RE2O from .settings_local import OPTIONNAL_APPS_RE2O

View file

@ -34,7 +34,7 @@ CHOICES_USER = (
("1", _("Disabled")), ("1", _("Disabled")),
("2", _("Archived")), ("2", _("Archived")),
("3", _("Not yet active")), ("3", _("Not yet active")),
("4", _("Full archived")), ("4", _("Fully archived")),
) )
CHOICES_AFF = ( CHOICES_AFF = (

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-05 19:48+0200\n" "POT-Creation-Date: 2019-11-19 23:43+0100\n"
"PO-Revision-Date: 2018-06-24 20:10+0200\n" "PO-Revision-Date: 2018-06-24 20:10+0200\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -47,10 +47,8 @@ msgid "Not yet active"
msgstr "Pas encore adhéré" msgstr "Pas encore adhéré"
#: search/forms.py:37 #: search/forms.py:37
#, fuzzy msgid "Fully archived"
#| msgid "Archived" msgstr "Complètement archivés"
msgid "Full archived"
msgstr "Archivés"
#: search/forms.py:41 #: search/forms.py:41
msgid "Users" msgid "Users"
@ -84,12 +82,12 @@ msgstr "Ports"
msgid "Switches" msgid "Switches"
msgstr "Commutateurs réseau" msgstr "Commutateurs réseau"
#: search/forms.py:61 search/forms.py:73 search/templates/search/search.html:29 #: search/forms.py:62 search/forms.py:77 search/templates/search/search.html:29
#: search/templates/search/search.html:48 #: search/templates/search/search.html:48
msgid "Search" msgid "Search"
msgstr "Rechercher" msgstr "Rechercher"
#: search/forms.py:63 search/forms.py:75 #: search/forms.py:65 search/forms.py:80
msgid "" msgid ""
"Use « » and «,» to specify distinct words, «\"query\"» for an exact search " "Use « » and «,» to specify distinct words, «\"query\"» for an exact search "
"and «\\» to escape a character." "and «\\» to escape a character."
@ -97,19 +95,19 @@ msgstr ""
"Utilisez « » et «,» pour spécifier différents mots, «\"query\"» pour une " "Utilisez « » et «,» pour spécifier différents mots, «\"query\"» pour une "
"recherche exacte et «\\» pour échapper un caractère." "recherche exacte et «\\» pour échapper un caractère."
#: search/forms.py:82 #: search/forms.py:88
msgid "Users filter" msgid "Users filter"
msgstr "Filtre utilisateurs" msgstr "Filtre utilisateurs"
#: search/forms.py:89 #: search/forms.py:95
msgid "Display filter" msgid "Display filter"
msgstr "Filtre affichage" msgstr "Filtre affichage"
#: search/forms.py:97 #: search/forms.py:101
msgid "Start date" msgid "Start date"
msgstr "Date de début" msgstr "Date de début"
#: search/forms.py:101 #: search/forms.py:102
msgid "End date" msgid "End date"
msgstr "Date de fin" msgstr "Date de fin"
@ -159,10 +157,10 @@ msgstr "Pas de résultat"
#: search/templates/search/index.html:71 #: search/templates/search/index.html:71
#, python-format #, python-format
msgid "(Only the first %(max_result)s results are displayed in each category)" msgid "Only the first %(max_result)s results are displayed in each category."
msgstr "" msgstr ""
"(Seulement les %(max_result)s premiers résultats sont affichés dans chaque " "Seulement les %(max_result)s premiers résultats sont affichés dans chaque "
"catégorie)" "catégorie."
#: search/templates/search/sidebar.html:31 #: search/templates/search/sidebar.html:31
msgid "Simple search" msgid "Simple search"

View file

@ -68,7 +68,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if not users and not machines and not factures and not whitelists and not bans and not rooms and not ports and not switches %} {% if not users and not machines and not factures and not whitelists and not bans and not rooms and not ports and not switches %}
<h3>{% trans "No result" %}</h3> <h3>{% trans "No result" %}</h3>
{% else %} {% else %}
<h6>{% blocktrans %}(Only the first {{ max_result }} results are displayed in each category){% endblocktrans %}</h6> <h6>{% blocktrans %}Only the first {{ max_result }} results are displayed in each category.{% endblocktrans %}</h6>
{% endif %} {% endif %}
<br /> <br />
<br /> <br />

View file

@ -14,8 +14,7 @@ Copyright © 2019 Alexandre Iooss
{% block content %} {% block content %}
<div id="content-main"> <div id="content-main">
<p> <p>
{% blocktrans %}You are on the operator interface. Here you will be able to manage the network and users {% blocktrans %}You are on the operator interface. Here you will be able to manage the network and users from the top left menu. You can also go read the developer documentation.{% endblocktrans %}
from the top left menu. You can also go read the developer documentation.{% endblocktrans %}
</p> </p>
<p> <p>
{% blocktrans %}To go back to the main site, click "View site" button in top right menu.{% endblocktrans %} {% blocktrans %}To go back to the main site, click "View site" button in top right menu.{% endblocktrans %}
@ -26,12 +25,12 @@ Copyright © 2019 Alexandre Iooss
{% block sidebar %} {% block sidebar %}
<div id="content-related"> <div id="content-related">
<div class="module" id="recent-actions-module"> <div class="module" id="recent-actions-module">
<h2>{% trans 'My account' %}</h2> <h2>{% trans "My account" %}</h2>
<h3>{% trans 'My recent actions' %}</h3> <h3>{% trans "Recent actions" %}</h3>
{% load log %} {% load log %}
{% get_admin_log 10 as admin_log for_user user %} {% get_admin_log 10 as admin_log for_user user %}
{% if not admin_log %} {% if not admin_log %}
<p>{% trans 'None available' %}</p> <p>{% trans "None available" %}</p>
{% else %} {% else %}
<ul class="actionlist"> <ul class="actionlist">
{% for entry in admin_log %} {% for entry in admin_log %}
@ -46,7 +45,7 @@ Copyright © 2019 Alexandre Iooss
<span class="mini quiet">{% filter capfirst %} <span class="mini quiet">{% filter capfirst %}
{{ entry.content_type }}{% endfilter %}</span> {{ entry.content_type }}{% endfilter %}</span>
{% else %} {% else %}
<span class="mini quiet">{% trans 'Unknown content' %}</span> <span class="mini quiet">{% trans "Unknown content" %}</span>
{% endif %} {% endif %}
</li> </li>
{% endfor %} {% endfor %}

View file

@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<meta property="og:image" content="{% static 'images/logo_re2o.svg' %}"/> <meta property="og:image" content="{% static 'images/logo_re2o.svg' %}"/>
<meta property="og:image:type" content="image/svg"/> <meta property="og:image:type" content="image/svg"/>
<meta property="og:image:alt" content="The Re2o logo"/> <meta property="og:image:alt" content="The Re2o logo"/>
<meta property="og:description" content="{% trans "Networking managing website endorsed by FedeRez." %}" /> <meta property="og:description" content="Networking managing website endorsed by FedeRez." />
{# Preload JavaScript #} {# Preload JavaScript #}
{% bootstrap_javascript %} {% bootstrap_javascript %}
@ -142,7 +142,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<li><a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a></li> <li><a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a></li>
<li><a href="{% url 'contact' %}"><i class="fa fa-at"></i> {% trans "Contact" %}</a></li> <li><a href="{% url 'contact' %}"><i class="fa fa-at"></i> {% trans "Contact" %}</a></li>
{% comment %} {% comment %}
<li><a href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}</a><li> <li><a href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Open a ticket" %}</a><li>
{% endcomment %} {% endcomment %}
</ul> </ul>
</li> </li>
@ -284,7 +284,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<p class="pull-right"> <p class="pull-right">
<a href="#">{% trans "Back to top" %}</a> <a href="#">{% trans "Back to top" %}</a>
</p> </p>
<p>{{ name_website }} {% trans "powered by" %} Re2o 2016&ndash;2018</p> <p>{{ name_website }} {% trans "powered by" %} Re2o 2016&ndash;2019</p>
<p> <p>
{% blocktrans trimmed %} {% blocktrans trimmed %}
Brought to you with <i class="fa fa-heart text-danger"></i>. Brought to you with <i class="fa fa-heart text-danger"></i>.

View file

@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %} {% endcomment %}
{% load i18n %} {% load i18n %}
<a {% if class%}class="btn btn-info btn-sm"{% endif %} role="button" title="{% trans 'History' %}" href="{% url 'logs:history' application name id %}"> <a {% if class%}class="btn btn-info btn-sm"{% endif %} role="button" title="{% trans "History" %}" href="{% url 'logs:history' application name id %}">
<i class="fa fa-history"></i> {% if text %}{% trans 'History' %}{% endif %} <i class="fa fa-history"></i> {% if text %}{% trans "History" %}{% endif %}
</a> </a>

View file

@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<meta property="og:image" content="{% static 'images/logo_re2o.svg' %}"/> <meta property="og:image" content="{% static 'images/logo_re2o.svg' %}"/>
<meta property="og:image:type" content="image/svg"/> <meta property="og:image:type" content="image/svg"/>
<meta property="og:image:alt" content="The Re2o logo"/> <meta property="og:image:alt" content="The Re2o logo"/>
<meta property="og:description" content="{% trans "Networking managing website endorsed by FedeRez." %}" /> <meta property="og:description" content="Networking managing website endorsed by FedeRez." />
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="shortcut icon" type="image/svg" href="{% static 'images/logo_re2o.svg' %}"> <link rel="shortcut icon" type="image/svg" href="{% static 'images/logo_re2o.svg' %}">

View file

@ -38,7 +38,7 @@
</p> </p>
<p> <p>
<b>{% blocktrans trimmed %}An email has been automatically sent to the site administrators. Please avoid <b>{% blocktrans trimmed %}An email has been automatically sent to the site administrators. Please avoid
spamming them by trigerring the same issue multiple times.{% endblocktrans %}</b>{% blocktrans trimmed %} The mail should spamming them by trigerring the same issue multiple times.{% endblocktrans %}</b>{% blocktrans trimmed %} The email should
contains all the details necessary to understand what went wrong but if your help were contains all the details necessary to understand what went wrong but if your help were
needed, you will probably be contacted by them.{% endblocktrans %} needed, you will probably be contacted by them.{% endblocktrans %}
</p> </p>

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-05 19:48+0200\n" "POT-Creation-Date: 2019-11-19 23:43+0100\n"
"PO-Revision-Date: 2018-03-31 16:09+0002\n" "PO-Revision-Date: 2018-03-31 16:09+0002\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -30,11 +30,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: templates/admin/base_site.html:65 templates/base.html:281 #: templates/admin/base_site.html:65 templates/base.html:288
msgid "powered by" msgid "powered by"
msgstr "propulsé par" msgstr "propulsé par"
#: templates/admin/base_site.html:69 templates/base.html:289 #: templates/admin/base_site.html:69 templates/base.html:296
msgid "" msgid ""
"This software is under the terms of the <a href=\"http://www.gnu.org/" "This software is under the terms of the <a href=\"http://www.gnu.org/"
"licenses/gpl-2.0.txt\" target=\"_blank\" rel=\"nofollow\">GPLv2</a> License." "licenses/gpl-2.0.txt\" target=\"_blank\" rel=\"nofollow\">GPLv2</a> License."
@ -45,41 +45,41 @@ msgstr ""
#: templates/admin/custom_index.html:11 #: templates/admin/custom_index.html:11
#, python-format #, python-format
msgid "Welcome to %(name_website)s" msgid "Welcome to %(name_website)s"
msgstr "" msgstr "Bienvenue sur %(name_website)s"
#: templates/admin/custom_index.html:17 #: templates/admin/custom_index.html:17
msgid "" msgid ""
"You are on the operator interface. Here you will be able to manage the " "You are on the operator interface. Here you will be able to manage the "
"network and users\n" "network and users from the top left menu. You can also go read the developer "
" from the top left menu. You can also go read the developer "
"documentation." "documentation."
msgstr "" msgstr ""
"Vous êtes dans l'interface opérateur. Ici vous pourrez gérer le réseau et "
"les utilisateurs depuis le menu en haut à gauche. Vous pouvez aussi lire la "
"documentation du développeur."
#: templates/admin/custom_index.html:21 #: templates/admin/custom_index.html:20
msgid "" msgid ""
"To go back to the main site, click \"View site\" button in top right menu." "To go back to the main site, click \"View site\" button in top right menu."
msgstr "" msgstr ""
"Pour revenir au site principal, cliquez sur le bouton « Voir le site » dans "
"le menu en haut à droite."
#: templates/admin/custom_index.html:28
msgid "My account"
msgstr "Mon compte"
#: templates/admin/custom_index.html:29 #: templates/admin/custom_index.html:29
msgid "My account" msgid "Recent actions"
msgstr "" msgstr ""
#: templates/admin/custom_index.html:30 #: templates/admin/custom_index.html:33
msgid "My recent actions"
msgstr ""
#: templates/admin/custom_index.html:34
msgid "None available" msgid "None available"
msgstr "" msgstr ""
#: templates/admin/custom_index.html:49 #: templates/admin/custom_index.html:48
msgid "Unknown content" msgid "Unknown content"
msgstr "" msgstr ""
#: templates/base.html:43 templates/errors/404.html:35
msgid "Networking managing website endorsed by FedeRez."
msgstr "Site de gestion de réseau soutenu par FedeRez."
#: templates/base.html:70 templates/registration/logged_out.html:11 #: templates/base.html:70 templates/registration/logged_out.html:11
#: templates/registration/password_change_done.html:11 #: templates/registration/password_change_done.html:11
#: templates/registration/password_change_form.html:11 #: templates/registration/password_change_form.html:11
@ -88,7 +88,7 @@ msgstr "Site de gestion de réseau soutenu par FedeRez."
#: templates/registration/password_reset_done.html:11 #: templates/registration/password_reset_done.html:11
#: templates/registration/password_reset_form.html:11 #: templates/registration/password_reset_form.html:11
msgid "Home" msgid "Home"
msgstr "Accueil" msgstr ""
#: templates/base.html:91 #: templates/base.html:91
msgid "Users" msgid "Users"
@ -110,139 +110,139 @@ msgstr "Gérer les machines"
msgid "Manage the subscriptions" msgid "Manage the subscriptions"
msgstr "Gérer les cotisations" msgstr "Gérer les cotisations"
#: templates/base.html:112 #: templates/base.html:114
msgid "Topology" msgid "Topology"
msgstr "Topologie" msgstr "Topologie"
#: templates/base.html:114 #: templates/base.html:116
msgid "Switches" msgid "Switches"
msgstr "Commutateurs réseau" msgstr "Commutateurs réseau"
#: templates/base.html:115 #: templates/base.html:117
msgid "Access points" msgid "Access points"
msgstr "Points d'accès sans fil" msgstr "Points d'accès sans fil"
#: templates/base.html:116 #: templates/base.html:118
msgid "Rooms" msgid "Rooms"
msgstr "Chambres" msgstr "Chambres"
#: templates/base.html:121 #: templates/base.html:128
msgid "Statistics" msgid "Statistics"
msgstr "Statistiques" msgstr "Statistiques"
#: templates/base.html:126
msgid "Administration"
msgstr "Administration"
#: templates/base.html:133 #: templates/base.html:133
msgid "Information and contact" msgid "Administration"
msgstr "" msgstr ""
#: templates/base.html:135 #: templates/base.html:140
msgid "Information and contact"
msgstr "Informations et contact"
#: templates/base.html:142
msgid "About" msgid "About"
msgstr "À propos" msgstr "À propos"
#: templates/base.html:136 #: templates/base.html:143
msgid "Contact" msgid "Contact"
msgstr "Contact" msgstr "Contact"
#: templates/base.html:150 #: templates/base.html:157
msgid "Sign up" msgid "Sign up"
msgstr "S'inscrire" msgstr "S'inscrire"
#: templates/base.html:156 templates/registration/login.html:29 #: templates/base.html:163 templates/registration/login.html:29
#: templates/registration/login.html:36 #: templates/registration/login.html:36
msgid "Log in" msgid "Log in"
msgstr "Se connecter" msgstr ""
#: templates/base.html:164 #: templates/base.html:171
msgid "Search" msgid "Search"
msgstr "Rechercher" msgstr ""
#: templates/base.html:178 #: templates/base.html:185
msgid "My profile" msgid "My profile"
msgstr "Mon profil" msgstr "Mon profil"
#: templates/base.html:179 #: templates/base.html:186
msgid "Log out" msgid "Log out"
msgstr "Se déconnecter" msgstr ""
#: templates/base.html:214 #: templates/base.html:221
msgid "Username" msgid "Username"
msgstr "Pseudo" msgstr "Pseudo"
#: templates/base.html:218 #: templates/base.html:225
msgid "Room" msgid "Room"
msgstr "Chambre" msgstr "Chambre"
#: templates/base.html:222 #: templates/base.html:229
msgid "Internet access" msgid "Internet access"
msgstr "Accès Internet" msgstr "Accès Internet"
#: templates/base.html:225 #: templates/base.html:232
#, python-format #, python-format
msgid "Until %(end_access_date)s" msgid "Until %(end_access_date)s"
msgstr "Jusqu'au %(end_access_date)s" msgstr "Jusqu'au %(end_access_date)s"
#: templates/base.html:227 #: templates/base.html:234
msgid "Disabled" msgid "Disabled"
msgstr "Désactivé" msgstr "Désactivé"
#: templates/base.html:232 #: templates/base.html:239
msgid "Membership" msgid "Membership"
msgstr "Adhésion" msgstr "Adhésion"
#: templates/base.html:235 #: templates/base.html:242
#, python-format #, python-format
msgid "Until %(end_adhesion_date)s" msgid "Until %(end_adhesion_date)s"
msgstr "Jusqu'au %(end_adhesion_date)s" msgstr "Jusqu'au %(end_adhesion_date)s"
#: templates/base.html:237 #: templates/base.html:244
msgid "Non member" msgid "Non member"
msgstr "Non adhérent" msgstr "Non adhérent"
#: templates/base.html:245 #: templates/base.html:252
msgid "View my profile" msgid "View my profile"
msgstr "Voir mon profil" msgstr "Voir mon profil"
#: templates/base.html:250 #: templates/base.html:257
msgid "You are not logged in." msgid "You are not logged in."
msgstr "Vous n'êtes pas connecté." msgstr "Vous n'êtes pas connecté."
#: templates/base.html:257 #: templates/base.html:264
#, python-format #, python-format
msgid "%(nb)s active machine" msgid "%(nb)s active machine"
msgid_plural "%(nb)s active machines" msgid_plural "%(nb)s active machines"
msgstr[0] "%(nb)s machine active" msgstr[0] "%(nb)s machine active"
msgstr[1] "%(nb)s machines actives" msgstr[1] "%(nb)s machines actives"
#: templates/base.html:266 #: templates/base.html:273
msgid "View my machines" msgid "View my machines"
msgstr "Voir mes machines" msgstr "Voir mes machines"
#: templates/base.html:279 #: templates/base.html:286
msgid "Back to top" msgid "Back to top"
msgstr "Retour en haut" msgstr "Retour en haut"
#: templates/base.html:283 #: templates/base.html:290
msgid "Brought to you with <i class=\"fa fa-heart text-danger\"></i>." msgid "Brought to you with <i class=\"fa fa-heart text-danger\"></i>."
msgstr "Codé avec <i class=\"fa fa-heart text-danger\"></i>." msgstr "Codé avec <i class=\"fa fa-heart text-danger\"></i>."
#: templates/base.html:286 #: templates/base.html:293
msgid "About this website" msgid "About this website"
msgstr "À propos de ce site" msgstr "À propos de ce site"
#: templates/buttons/add.html:27 #: templates/buttons/add.html:27
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr ""
#: templates/buttons/edit.html:27 tickets/templates/tickets/preferences.html:14 #: templates/buttons/edit.html:27
msgid "Edit" msgid "Edit"
msgstr "Modifier" msgstr "Modifier"
#: templates/buttons/history.html:26 templates/buttons/history.html:27 #: templates/buttons/history.html:26 templates/buttons/history.html:27
msgid "History" msgid "History"
msgstr "Historique" msgstr ""
#: templates/buttons/setlang.html:34 #: templates/buttons/setlang.html:34
msgid "Translation in development" msgid "Translation in development"
@ -258,7 +258,7 @@ msgstr "Tri décroissant"
#: templates/buttons/suppr.html:27 #: templates/buttons/suppr.html:27
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr ""
#: templates/errors/404.html:39 #: templates/errors/404.html:39
msgid "404 error: page not found" msgid "404 error: page not found"
@ -312,7 +312,7 @@ msgstr ""
#: templates/errors/500.html:41 #: templates/errors/500.html:41
msgid "" msgid ""
"The mail should contains all the details necessary to understand what went " "The email should contains all the details necessary to understand what went "
"wrong but if your help were needed, you will probably be contacted by them." "wrong but if your help were needed, you will probably be contacted by them."
msgstr "" msgstr ""
" Le courrier électronique devrait contenir tous les détails nécessaires à la " " Le courrier électronique devrait contenir tous les détails nécessaires à la "
@ -360,10 +360,8 @@ msgid "Thanks for spending some quality time with the Web site today."
msgstr "" msgstr ""
#: templates/registration/logged_out.html:17 #: templates/registration/logged_out.html:17
#, fuzzy
#| msgid "Log in"
msgid "Log in again" msgid "Log in again"
msgstr "Se connecter" msgstr ""
#: templates/registration/login.html:40 #: templates/registration/login.html:40
msgid "Forgotten password?" msgid "Forgotten password?"
@ -381,10 +379,8 @@ msgid "Password reset"
msgstr "" msgstr ""
#: templates/registration/password_reset_confirm.html:11 #: templates/registration/password_reset_confirm.html:11
#, fuzzy
#| msgid "More information"
msgid "Password reset confirmation" msgid "Password reset confirmation"
msgstr "Plus d'informations" msgstr ""
#: templates/registration/password_reset_email.html:2 #: templates/registration/password_reset_email.html:2
#, python-format #, python-format
@ -405,186 +401,3 @@ msgstr ""
#, python-format #, python-format
msgid "The %(site_name)s team" msgid "The %(site_name)s team"
msgstr "" msgstr ""
#: tickets/models.py:27
msgid "Title of the ticket"
msgstr ""
#: tickets/models.py:32
msgid "Description of the ticket"
msgstr ""
#: tickets/models.py:37
msgid "An email address to get back to you"
msgstr ""
#: tickets/models.py:43 tickets/templates/tickets/form_preferences.html:30
#: tickets/templates/tickets/form_ticket.html:31
msgid "Ticket"
msgstr ""
#: tickets/models.py:44 tickets/templates/tickets/aff_ticket.html:30
#: tickets/templates/tickets/aff_tickets.html:35
#: tickets/templates/tickets/index.html:29
#: tickets/templates/tickets/index.html:32
#: tickets/templates/tickets/navbar.html:2
#: tickets/templates/tickets/preferences.html:6
msgid "Tickets"
msgstr ""
#: tickets/models.py:75
msgid "You don't have the right to view other tickets than yours."
msgstr ""
#: tickets/models.py:84
msgid "You don't have the right to view the list of tickets."
msgstr ""
#: tickets/preferences/models.py:8
msgid ""
"Email address to publish the new tickets (leave empty for no publications)"
msgstr ""
#: tickets/preferences/models.py:14
msgid "Français"
msgstr ""
#: tickets/preferences/models.py:15
msgid "English"
msgstr ""
#: tickets/preferences/models.py:19
msgid "Ticket's settings"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:36
msgid "Solved"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:38
msgid "Not Solved"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:44
#, fuzzy
#| msgid "powered by"
msgid "Opened by"
msgstr "propulsé par"
#: tickets/templates/tickets/aff_ticket.html:50
msgid "Anonymous User"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:54
msgid "Response address: "
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:54
msgid "Response to your ticket"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:59
msgid "Title:"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:60
msgid "Description"
msgstr ""
#: tickets/templates/tickets/aff_ticket.html:79
msgid "Tous les tickets"
msgstr ""
#: tickets/templates/tickets/aff_tickets.html:38
msgid "Not Solved Tickets"
msgstr ""
#: tickets/templates/tickets/aff_tickets.html:41
msgid "Last Ticket:"
msgstr ""
#: tickets/templates/tickets/contact.html:8
#, python-format
msgid ""
"If you are experiencing issues with the services offered by %(asso_name)s, "
"you can open a ticket that will be taken care of. If you want to contact us "
"on any other topic, please choose one address below."
msgstr ""
#: tickets/templates/tickets/contact.html:10
#: tickets/templates/tickets/navbar_logout.html:4
msgid "Ouvrir un ticket"
msgstr ""
#: tickets/templates/tickets/form_preferences.html:33
msgid "Tickets settings modification"
msgstr ""
#: tickets/templates/tickets/form_ticket.html:39
msgid ""
"Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous "
"puissions vous recontacter."
msgstr ""
#: tickets/templates/tickets/form_ticket.html:44
msgid ""
"Description de votre problème. Veuillez fournir le plus d'informations "
"possible afin de faciliter la recherche de solution. Voici quelques "
"informations dont nous pourions avoir besoin:"
msgstr ""
#: tickets/templates/tickets/form_ticket.html:47
msgid "Le type de votre problème (adhesion, connexion, paiement ou autre)."
msgstr ""
#: tickets/templates/tickets/form_ticket.html:50
msgid ""
"Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, "
"sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?"
msgstr ""
#: tickets/templates/tickets/form_ticket.html:53
msgid ""
"Les endroits dans lequels le problème survient (chez vous, dans une partie "
"commune, dans un batiment en particulier)."
msgstr ""
#: tickets/templates/tickets/preferences.html:21
msgid "Publication email address"
msgstr ""
#: tickets/templates/tickets/preferences.html:25
msgid "Pas d'adresse, les tickets ne sont pas annoncés"
msgstr ""
#: tickets/templates/tickets/preferences.html:29
msgid "Email language"
msgstr ""
#: tickets/templates/tickets/profil.html:6
msgid " Tickets"
msgstr ""
#: tickets/templates/tickets/profil.html:12
msgid " Open a Ticket"
msgstr ""
#: tickets/templates/tickets/profil.html:19
msgid "No tickets"
msgstr ""
#: tickets/views.py:83 tickets/views.py:87
msgid ""
"Your ticket has been succesfully open. We will take care of it as soon as "
"possible."
msgstr ""
#: tickets/views.py:90
msgid ""
"You are not authenticated. Please login or provide an email address so we "
"can get back to you."
msgstr ""
#: tickets/views.py:117 tickets/views.py:163
msgid "Never"
msgstr ""

View file

@ -8,11 +8,11 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> <a href="{% url 'index' %}">{% trans "Home" %}</a>
</div> </div>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<p>{% trans "Thanks for spending some quality time with the Web site today." %}</p> <p>{% trans "Thanks for spending some quality time with the Web site today." %}</p>
<p><a href="{% url 'login' %}">{% trans 'Log in again' %}</a></p> <p><a href="{% url 'login' %}">{% trans "Log in again" %}</a></p>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password change" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password change" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password reset" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset confirmation' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password reset confirmation" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password reset" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,6 +8,6 @@ Copyright © 2019 Alexandre Iooss
{% block breadcrumbs %} {% block breadcrumbs %}
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{% url 'index' %}">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %} <a href="{% url 'index' %}">{% trans "Home" %}</a> &rsaquo; {% trans "Password reset" %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,300 @@
# 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-11-20 01:24+0100\n"
"PO-Revision-Date: 2019-11-16 00:35+0100\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\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"
#: tickets/models.py:28
msgid "Title of the ticket."
msgstr "Titre du ticket."
#: tickets/models.py:32
msgid "Description of the ticket."
msgstr "Description du ticket."
#: tickets/models.py:38
msgid "An email address to get back to you."
msgstr "Une adresse mail pour vous recontacter."
#: tickets/models.py:43
msgid "Can view a ticket object"
msgstr "Peut voir un objet ticket"
#: tickets/models.py:44
msgid "ticket"
msgstr "ticket"
#: tickets/models.py:45
msgid "tickets"
msgstr "tickets"
#: tickets/models.py:49
#, python-format
msgid "Ticket from %(name)s. Date: %(date)s."
msgstr "Ticket de %(name)s. Date : %(date)s."
#: tickets/models.py:51
#, python-format
msgid "Anonymous ticket. Date: %s."
msgstr "Ticket anonyme. Date : %s."
#: tickets/models.py:82
msgid "You don't have the right to view other tickets than yours."
msgstr "Vous n'avez pas le droit de voir d'autres tickets que les vôtres."
#: tickets/models.py:94
msgid "You don't have the right to view the list of tickets."
msgstr "Vous n'avez pas le droit de voir la liste des tickets."
#: tickets/preferences/models.py:10
msgid ""
"Email address to publish the new tickets (leave empty for no publication)."
msgstr ""
"Adresse mail où publier les nouveaux tickets (laissez vide pour ne pas "
"publier)."
#: tickets/preferences/models.py:17
msgid "French"
msgstr "Français"
#: tickets/preferences/models.py:17
msgid "English"
msgstr "Anglais"
#: tickets/preferences/models.py:21
msgid "tickets preferences"
msgstr "préférences de tickets"
#: tickets/templates/tickets/aff_ticket.html:30
#: tickets/templates/tickets/contact.html:4
#: tickets/templates/tickets/index.html:29
#: tickets/templates/tickets/preferences.html:6
#: tickets/templates/tickets/profil.html:6
msgid "Tickets"
msgstr "Tickets"
#: tickets/templates/tickets/aff_ticket.html:34
#, python-format
msgid "Ticket #%(id)s"
msgstr "Ticket #%(id)s"
#: tickets/templates/tickets/aff_ticket.html:36
#: tickets/templates/tickets/aff_tickets.html:58
msgid "Solved"
msgstr "Résolu"
#: tickets/templates/tickets/aff_ticket.html:38
msgid "Not solved"
msgstr "Non résolu"
#: tickets/templates/tickets/aff_ticket.html:44
msgid "Opened by"
msgstr "Ouvert par"
#: tickets/templates/tickets/aff_ticket.html:50
msgid "Anonymous user"
msgstr "Utilisateur anonyme"
#: tickets/templates/tickets/aff_ticket.html:54
msgid "Response address: "
msgstr "Adresse de réponse : "
#: tickets/templates/tickets/aff_ticket.html:54
msgid "Response to your ticket"
msgstr "Réponse à votre ticket"
#: tickets/templates/tickets/aff_ticket.html:59
msgid "Title:"
msgstr "Titre :"
#: tickets/templates/tickets/aff_ticket.html:60
msgid "Description:"
msgstr "Description :"
#: tickets/templates/tickets/aff_ticket.html:68
msgid "Mark as solved"
msgstr "Marquer comme résolu"
#: tickets/templates/tickets/aff_ticket.html:71
msgid "Mark as not solved"
msgstr "Marquer comme non résolu"
#: tickets/templates/tickets/aff_ticket.html:81
msgid "All tickets"
msgstr "Tous les tickets"
#: tickets/templates/tickets/aff_tickets.html:35
#: tickets/templates/tickets/form_preferences.html:30
#: tickets/templates/tickets/form_ticket.html:31
msgid "Ticket"
msgid_plural "Tickets"
msgstr[0] "Ticket"
msgstr[1] "Tickets"
#: tickets/templates/tickets/aff_tickets.html:38
msgid "Ticket not solved"
msgid_plural "Tickets not solved"
msgstr[0] "Ticket non résolu"
msgstr[1] "Tickets non résolus"
#: tickets/templates/tickets/aff_tickets.html:41
msgid "Last ticket:"
msgstr "Dernier ticket :"
#: tickets/templates/tickets/aff_tickets.html:55
msgid "User"
msgstr "Utilisateur"
#: tickets/templates/tickets/aff_tickets.html:56
msgid "Title"
msgstr "Titre"
#: tickets/templates/tickets/aff_tickets.html:57
msgid "Date"
msgstr "Date"
#: tickets/templates/tickets/aff_tickets.html:70
msgid "Anonymous"
msgstr "Anonyme"
#: tickets/templates/tickets/contact.html:8
#, python-format
msgid ""
"If you are experiencing issues with the services offered by %(asso_name)s, "
"you can open a ticket that will be taken care of. If you want to contact us "
"on any other topic, please choose one address below."
msgstr ""
"Si vous rencontrez des problèmes avec les services proposés par "
"%(asso_name)s, vous pouvez ouvrir un ticket qui sera pris en compte. Si vous "
"voulez nous contacter pour n'importe quel autre sujet, veuillez choisir une "
"adresse ci-dessous."
#: tickets/templates/tickets/contact.html:10
#: tickets/templates/tickets/navbar_logout.html:4
#: tickets/templates/tickets/profil.html:12
msgid "Open a ticket"
msgstr "Ouvrir un ticket"
#: tickets/templates/tickets/form_preferences.html:33
msgid "Editing of tickets preferences"
msgstr "Modification des préférences de tickets"
#: tickets/templates/tickets/form_preferences.html:46
#: tickets/templates/tickets/preferences.html:14
msgid "Edit"
msgstr "Modifier"
#: tickets/templates/tickets/form_ticket.html:34
msgid "Ticket opening"
msgstr "Ouverture de ticket"
#: tickets/templates/tickets/form_ticket.html:39 tickets/views.py:88
msgid ""
"You are not authenticated. Please log in or provide an email address so we "
"can get back to you."
msgstr ""
"Vous n'êtes pas authentifié. Veuillez vous connecter ou fournir une adresse "
"mail pour que nous puissions vous recontacter."
#: tickets/templates/tickets/form_ticket.html:44
msgid ""
"Description of your problem. Please give as much information as possible to "
"help us searching for a solution. Here is some information we might need:"
msgstr ""
"Description de votre problème. Veuillez donner le plus d'informations "
"possible pour nous aider à chercher une solution. Voici quelques "
"informations dont nous pourrions avoir besoin :"
#: tickets/templates/tickets/form_ticket.html:47
msgid "The type of your problem (membership, connection, payment etc.)."
msgstr "Le type de votre problème (adhésion, connexion, paiement etc.)."
#: tickets/templates/tickets/form_ticket.html:50
msgid ""
"The conditions in which you encounter the problem (Wi-Fi/wired connection, "
"on every machines or only one, on a new machine etc.)."
msgstr ""
"Les conditions dans lesquelles vous rencontrez le problème (connexion Wi-Fi/"
"filaire, sur toutes les machines ou une seule, sur une nouvelle machine "
"etc.)."
#: tickets/templates/tickets/form_ticket.html:53
msgid ""
"The locations where you encounter the problem (in your room, in a common "
"space, in a specific building etc.)."
msgstr ""
"Les lieux où vous rencontrez le problème (dans votre chambre, dans un espace "
"commun, dans un bâtiment en particulier etc.)."
#: tickets/templates/tickets/form_ticket.html:56
msgid "Open the ticket"
msgstr "Ouvrir le ticket"
#: tickets/templates/tickets/index.html:32
msgid "List of tickets"
msgstr "Liste des tickets"
#: tickets/templates/tickets/navbar.html:2
msgid "Manage the tickets"
msgstr "Gérer les tickets"
#: tickets/templates/tickets/preferences.html:21
msgid "Publication email address"
msgstr "Adresse mail de publication"
#: tickets/templates/tickets/preferences.html:25
msgid "No email address, the tickets will not be published."
msgstr "Pas d'adresse mail, les tickets ne seront pas publiés."
#: tickets/templates/tickets/preferences.html:29
msgid "Email language"
msgstr "Langue du mail"
#: tickets/templates/tickets/profil.html:19
msgid "No tickets"
msgstr "Pas de tickets"
#: tickets/views.py:69 tickets/views.py:80
msgid ""
"Your ticket has been succesfully opened. We will take care of it as soon as "
"possible."
msgstr ""
"Votre ticket a bien été ouvert. Nous nous en occuperons dès que possible."
#: tickets/views.py:125 tickets/views.py:175
msgid "Never"
msgstr "Jamais"
#: tickets/views.py:152
msgid "The tickets preferences were edited."
msgstr "Les préférences de tickets ont été modifiées."
#: tickets/views.py:155
msgid "Invalid form."
msgstr "Formulaire invalide."

View file

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-11-20 00:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tickets', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='preferences',
options={'verbose_name': 'tickets preferences'},
),
migrations.AlterModelOptions(
name='ticket',
options={'permissions': (('view_tickets', 'Can view a ticket object'),), 'verbose_name': 'ticket', 'verbose_name_plural': 'tickets'},
),
migrations.AlterField(
model_name='preferences',
name='mail_language',
field=models.IntegerField(choices=[(0, 'French'), (1, 'English')], default=0),
),
migrations.AlterField(
model_name='preferences',
name='publish_address',
field=models.EmailField(help_text='Email address to publish the new tickets (leave empty for no publication).', max_length=1000, null=True),
),
migrations.AlterField(
model_name='ticket',
name='description',
field=models.TextField(help_text='Description of the ticket.', max_length=3000),
),
migrations.AlterField(
model_name='ticket',
name='email',
field=models.EmailField(help_text='An email address to get back to you.', max_length=100, null=True),
),
migrations.AlterField(
model_name='ticket',
name='title',
field=models.CharField(help_text='Title of the ticket.', max_length=255),
),
]

View file

@ -25,30 +25,30 @@ class Ticket(AclMixin, models.Model):
null=True, null=True,
) )
title = models.CharField( title = models.CharField(
max_length=255, help_text=_("Title of the ticket"), blank=False, null=False max_length=255, help_text=_("Title of the ticket."), blank=False, null=False
) )
description = models.TextField( description = models.TextField(
max_length=3000, max_length=3000,
help_text=_("Description of the ticket"), help_text=_("Description of the ticket."),
blank=False, blank=False,
null=False, null=False,
) )
date = models.DateTimeField(auto_now_add=True) date = models.DateTimeField(auto_now_add=True)
email = models.EmailField( email = models.EmailField(
help_text=_("An email address to get back to you"), max_length=100, null=True help_text=_("An email address to get back to you."), max_length=100, null=True
) )
solved = models.BooleanField(default=False) solved = models.BooleanField(default=False)
class Meta: class Meta:
permissions = (("view_tickets", _("Can view a ticket object")),) permissions = (("view_tickets", _("Can view a ticket object")),)
verbose_name = _("Ticket") verbose_name = _("ticket")
verbose_name_plural = _("Tickets") verbose_name_plural = _("tickets")
def __str__(self): def __str__(self):
if self.user: if self.user:
return "Ticket from {}. Date: {}".format(self.user.surname, self.date) return _("Ticket from %(name)s. Date: %(date)s.").format(name=self.user.surname, date=self.date)
else: else:
return "Anonymous Ticket. Date: {}".format(self.date) return _("Anonymous ticket. Date: %s.") % (self.date)
def publish_mail(self): def publish_mail(self):
site_url = GeneralOption.objects.first().main_site_url site_url = GeneralOption.objects.first().main_site_url
@ -57,7 +57,7 @@ class Ticket(AclMixin, models.Model):
lang = Preferences.objects.first().mail_language lang = Preferences.objects.first().mail_language
if lang == 0: if lang == 0:
obj = "Nouvelle ouverture de ticket" obj = "Nouveau ticket ouvert"
template = loader.get_template("tickets/publication_mail_fr") template = loader.get_template("tickets/publication_mail_fr")
else: else:
obj = "New ticket opened" obj = "New ticket opened"

View file

@ -7,15 +7,15 @@ class Preferences(models.Model):
publish_address = models.EmailField( publish_address = models.EmailField(
help_text=_( help_text=_(
"Email address to publish the new tickets (leave empty for no publications)" "Email address to publish the new tickets (leave empty for no publication)."
), ),
max_length=1000, max_length=1000,
null=True, null=True,
) )
LANG_FR = 0 LANG_FR = 0
LANG_EN = 1 LANG_EN = 1
LANGUES = ((0, _("Français")), (1, _("English"))) LANGUES = ((0, _("French")), (1, _("English")))
mail_language = models.IntegerField(choices=LANGUES, default=LANG_FR) mail_language = models.IntegerField(choices=LANGUES, default=LANG_FR)
class Meta: class Meta:
verbose_name = _("Ticket's settings") verbose_name = _("tickets preferences")

View file

@ -31,11 +31,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %} {% block content %}
<h2> Ticket #{{ticket.id}} <h2>{% blocktrans with id=ticket.id %}Ticket #{{id}}{% endblocktrans %}
{% if ticket.solved %} {% if ticket.solved %}
<span class="badge badge-success">{% trans "Solved" %}</span> <span class="badge badge-success">{% trans "Solved" %}</span>
{% else %} {% else %}
<span class="badge badge-danger">{% trans "Not Solved" %}</span> <span class="badge badge-danger">{% trans "Not solved" %}</span>
{% endif %} {% endif %}
</h2> </h2>
@ -47,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ ticket.user.get_full_name }} {{ ticket.user.get_full_name }}
</a> </a>
{% else %} {% else %}
{% trans "Anonymous User" %} {% trans "Anonymous user" %}
{% endif %} {% endif %}
{{ ticket.date | naturalday}}. {{ ticket.date | naturalday}}.
{% if not ticket.user %} {% if not ticket.user %}
@ -57,7 +57,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="panel-body"> <div class="panel-body">
<p><b>{% trans "Title:" %}</b> {{ticket.title}}</p> <p><b>{% trans "Title:" %}</b> {{ticket.title}}</p>
<p><b>{% trans "Description" %}</b> {{ ticket.description }}</p> <p><b>{% trans "Description:" %}</b> {{ ticket.description }}</p>
<div class="text-right"> <div class="text-right">
<form class="form" method="post"> <form class="form" method="post">
@ -65,9 +65,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% bootstrap_form changestatusform %} {% bootstrap_form changestatusform %}
{% if not ticket.solved %} {% if not ticket.solved %}
{% bootstrap_button "Mark as Solved" button_type="submit" button_class='btn-info' %} {% trans "Mark as solved" as tr_mark_solved %}
{% bootstrap_button tr_mark_solved button_type="submit" button_class='btn-info' %}
{% else %} {% else %}
{% bootstrap_button "Mark as not Solved" button_type="submit" button_class='btn-warning' %} {% trans "Mark as not solved" as tr_mark_not_solved %}
{% bootstrap_button tr_mark_not_solved button_type="submit" button_class='btn-warning' %}
{% endif %} {% endif %}
</form> </form>
</div> </div>
@ -76,7 +78,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<div class="text-right"> <div class="text-right">
<a type="button" href="{% url 'tickets:aff-tickets' %}" class="btn btn-primary"><p>{% trans "Tous les tickets" %}</p></a> <a type="button" href="{% url 'tickets:aff-tickets' %}" class="btn btn-primary"><p>{% trans "All tickets" %}</p></a>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -32,13 +32,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<hr class="col-sm-12"> <hr class="col-sm-12">
<div class="row justify-content-start"> <div class="row justify-content-start">
<div class="col-sm-4"> <div class="col-sm-4">
<span class="badge badge-light">{{ nbr_tickets }}</span> {% trans "Tickets" %} <span class="badge badge-light">{{ nbr_tickets }}</span> {% blocktrans count nb=nbr_tickets %}Ticket{% plural %}Tickets{% endblocktrans %}
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<span class="badge badge-light"> {{ nbr_tickets_unsolved }}</span>{% trans "Not Solved Tickets" %} <span class="badge badge-light"> {{ nbr_tickets_unsolved }}</span> {% blocktrans count nb=nbr_tickets_unsolved %}Ticket not solved{% plural %}Tickets not solved{% endblocktrans %}
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<span>{% trans "Last Ticket:" %} {{ last_ticket_date }}</span> <span>{% trans "Last ticket:" %} {{ last_ticket_date }}</span>
</div> </div>
</div> </div>
<hr class="col-sm-12"> <hr class="col-sm-12">
@ -52,10 +52,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<thead> <thead>
<tr> <tr>
<th scope="col"></th> <th scope="col"></th>
<th scope="col">User</th> <th scope="col">{% trans "User" %}</th>
<th scope="col">Titre</th> <th scope="col">{% trans "Title" %}</th>
<th scope="col">Date</th> <th scope="col">{% trans "Date" %}</th>
<th scope="col">Résolu</th> <th scope="col">{% trans "Solved" %}</th>
</tr> </tr>
{% for ticket in tickets_list %} {% for ticket in tickets_list %}
<tr> <tr>
@ -67,7 +67,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if ticket.user %} {% if ticket.user %}
<td><a href="{% url 'users:profil' ticket.user.id%}" role="button">{{ ticket.user.get_short_name }}</a></td> <td><a href="{% url 'users:profil' ticket.user.id%}" role="button">{{ ticket.user.get_short_name }}</a></td>
{% else %} {% else %}
<td> Anonyme </td> <td>{% trans "Anonymous" %}</td>
{% endif %} {% endif %}
<td>{{ ticket.title }}</td> <td>{{ ticket.title }}</td>
<td>{{ ticket.date }}</td> <td>{{ ticket.date }}</td>

View file

@ -1,13 +1,13 @@
{% load i18n %} {% load i18n %}
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"><h4>Tickets</h4></div> <div class="panel-heading"><h4>{% trans "Tickets" %}</h4></div>
<div class="panel-body"> <div class="panel-body">
<div class="row"> <div class="row">
<div class="col-sm-9"> <div class="col-sm-9">
{% blocktrans %}If you are experiencing issues with the services offered by {{asso_name}}, you can open a ticket that will be taken care of. If you want to contact us on any other topic, please choose one address below.{% endblocktrans %} {% blocktrans %}If you are experiencing issues with the services offered by {{asso_name}}, you can open a ticket that will be taken care of. If you want to contact us on any other topic, please choose one address below.{% endblocktrans %}
</div> </div>
<div class="col-sm-3"><a class="btn btn-primary" href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}</a></div> <div class="col-sm-3"><a class="btn btn-primary" href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Open a ticket" %}</a></div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Ticket" %}{% endblock %} {% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %} {% block content %}
<h2> {% trans "Tickets settings modification" %}</h2> <h2> {% trans "Editing of tickets preferences" %}</h2>
{% for message in messages %} {% for message in messages %}
<div class="{{ message| bootstrap_message_classes }} alert-dismissable"> <div class="{{ message| bootstrap_message_classes }} alert-dismissable">
@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% csrf_token %} {% csrf_token %}
{% bootstrap_field preferencesform.publish_address %} {% bootstrap_field preferencesform.publish_address %}
{% bootstrap_field preferencesform.mail_language %} {% bootstrap_field preferencesform.mail_language %}
{% bootstrap_button "Editer" button_type="submit" icon='ok' button_class='btn-success' %} {% trans "Edit" as tr_edit %}
{% bootstrap_button tr_edit button_type="submit" icon='ok' button_class='btn-success' %}
</form> </form>
{% endblock %} {% endblock %}

View file

@ -1,4 +1,4 @@
{% extends 'machines/sidebar.html' %} {% extends 'users/sidebar.html' %}
{% comment %} {% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il 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 se veut agnostique au réseau considéré, de manière à être installable en
@ -31,28 +31,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}{% trans "Ticket" %}{% endblock %} {% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %} {% block content %}
<h2> Ouverture d'un Ticket </h2> <h2>{% trans "Ticket opening" %}</h2>
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
{% if not user.is_authenticated %} {% if not user.is_authenticated %}
<p>{% trans "Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous puissions vous recontacter." %}</p> <p>{% trans "You are not authenticated. Please log in or provide an email address so we can get back to you." %}</p>
{% bootstrap_field ticketform.email %} {% bootstrap_field ticketform.email %}
{% endif %} {% endif %}
{% bootstrap_field ticketform.title %} {% bootstrap_field ticketform.title %}
<br> <br>
<p>{% trans "Description de votre problème. Veuillez fournir le plus d'informations possible afin de faciliter la recherche de solution. Voici quelques informations dont nous pourions avoir besoin:" %}</p> <p>{% trans "Description of your problem. Please give as much information as possible to help us searching for a solution. Here is some information we might need:" %}</p>
<ul class="list"> <ul class="list">
<li> <li>
<p> {% trans "Le type de votre problème (adhesion, connexion, paiement ou autre)." %}</p> <p> {% trans "The type of your problem (membership, connection, payment etc.)." %}</p>
</li> </li>
<li> <li>
<p> {% trans "Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?" %}</p> <p> {% trans "The conditions in which you encounter the problem (Wi-Fi/wired connection, on every machines or only one, on a new machine etc.)." %}</p>
</li> </li>
<li> <li>
<p> {% trans "Les endroits dans lequels le problème survient (chez vous, dans une partie commune, dans un batiment en particulier)." %}</p> <p> {% trans "The locations where you encounter the problem (in your room, in a common space, in a specific building etc.)." %}</p>
</ul> </ul>
{% bootstrap_field ticketform.description %} {% bootstrap_field ticketform.description %}
{% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %} {% trans "Open the ticket" as tr_open %}
{% bootstrap_button tr_open button_type="submit" icon='ok' button_class='btn-success' %}
</form> </form>
{% endblock %} {% endblock %}

View file

@ -29,6 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title%}{% trans "Tickets" %}{% endblock %} {% block title%}{% trans "Tickets" %}{% endblock %}
{% block content %} {% block content %}
<h2>{% trans "Tickets" %}</h2> <h2>{% trans "List of tickets" %}</h2>
{% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %}
{% endblock %} {% endblock %}

View file

@ -1,2 +1,2 @@
{% load i18n %} {% load i18n %}
<li><a href="{% url 'tickets:aff-tickets' %}"><i class="fa fa-ticket"></i> {% trans "Tickets" %}</a></li> <li><a href="{% url 'tickets:aff-tickets' %}"><i class="fa fa-ticket"></i> {% trans "Manage the tickets" %}</a></li>

View file

@ -1,6 +1,6 @@
{% load i18n %} {% load i18n %}
<li> <li>
<a href="{% url 'tickets:new-ticket' %}"> <a href="{% url 'tickets:new-ticket' %}">
<i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %} <i class="fa fa-ticket"></i> {% trans "Open a ticket" %}
</a> </a>
</li> </li>

View file

@ -22,7 +22,7 @@
{% if preferences.publish_address %} {% if preferences.publish_address %}
<td><p>{{ preferences.publish_address }}</p></td> <td><p>{{ preferences.publish_address }}</p></td>
{% else %} {% else %}
<td><p>{% trans "Pas d'adresse, les tickets ne sont pas annoncés" %}</p></td> <td><p>{% trans "No email address, the tickets will not be published." %}</p></td>
{% endif %} {% endif %}
</tr> </tr>
<tr> <tr>

View file

@ -9,7 +9,7 @@
<div id="ticket" class="panel-collapse collapse"> <div id="ticket" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
<a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:new-ticket' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:new-ticket' %}">
<i class="fa fa-ticket"></i>{% trans " Open a Ticket" %} <i class="fa fa-ticket"></i> {% trans "Open a ticket" %}
</a> </a>
</div> </div>
<div class="panel-body"> <div class="panel-body">

View file

@ -1,5 +1,5 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket. {% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket.
Profil: {{site_url}}{% url 'users:profil' ticket.user.id%} Profile: {{site_url}}{% url 'users:profil' ticket.user.id%}
Answer to the address: {{ticket.user.get_mail}}. Answer to the address: {{ticket.user.get_mail}}.
{% else %} {% else %}

Some files were not shown because too many files have changed in this diff Show more