Make file modale chooser and complete user profile

This commit is contained in:
Skia 2016-08-11 04:24:32 +02:00
parent a8858fa781
commit 43b709bfd5
40 changed files with 850 additions and 177 deletions

View File

@ -53,7 +53,7 @@
{% endif %} {% endif %}
<td>{{ o.remark }}</td> <td>{{ o.remark }}</td>
{% if o.invoice %} {% if o.invoice %}
<td><a href="{{ url('core:download') + '?file=' + o.invoice.name }}">{{ o.invoice.name }}</a></td> <td><a href="{{ url('core:download', file_id=o.invoice.id) }}">{{ o.invoice.name }}</a></td>
{% else %} {% else %}
<td>-</td> <td>-</td>
{% endif %} {% endif %}

View File

@ -4,10 +4,9 @@ from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
from django.forms import HiddenInput from django.forms import HiddenInput
from django.forms.extras.widgets import SelectDateWidget
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from core.views.forms import SelectFile from core.views.forms import SelectFile, SelectDate
from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company from accounting.models import BankAccount, ClubAccount, GeneralJournal, Operation, AccountingType, Company
# Accounting types # Accounting types
@ -168,7 +167,7 @@ class OperationCreateView(CanCreateMixin, CreateView):
form_class = modelform_factory(Operation, form_class = modelform_factory(Operation,
fields=['amount', 'label', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode', fields=['amount', 'label', 'remark', 'journal', 'target_type', 'target_id', 'target_label', 'date', 'mode',
'cheque_number', 'invoice', 'accounting_type', 'done'], 'cheque_number', 'invoice', 'accounting_type', 'done'],
widgets={'journal': HiddenInput, 'date': SelectDateWidget}) widgets={'journal': HiddenInput, 'date': SelectDate})
template_name = 'core/create.jinja' template_name = 'core/create.jinja'
def get_initial(self): def get_initial(self):
@ -188,7 +187,7 @@ class OperationEditView(CanEditMixin, UpdateView):
form_class = modelform_factory(Operation, form_class = modelform_factory(Operation,
fields = ['amount', 'label', 'remark', 'target_type', 'target_id', 'target_label', 'date', 'mode', 'cheque_number', fields = ['amount', 'label', 'remark', 'target_type', 'target_id', 'target_label', 'date', 'mode', 'cheque_number',
'invoice', 'accounting_type', 'done'], 'invoice', 'accounting_type', 'done'],
widgets={'date': SelectDateWidget, 'invoice': SelectFile}) widgets={'date': SelectDate, 'invoice': SelectFile})
template_name = 'core/edit.jinja' template_name = 'core/edit.jinja'
# Company views # Company views

View File

@ -38,6 +38,7 @@ class Command(BaseCommand):
is_superuser=True, is_staff=True) is_superuser=True, is_staff=True)
root.set_password("plop") root.set_password("plop")
root.save() root.save()
SithFile(parent=None, name="profiles", is_folder=True, owner=root).save()
home_root = SithFile(parent=None, name="users", is_folder=True, owner=root) home_root = SithFile(parent=None, name="users", is_folder=True, owner=root)
home_root.save() home_root.save()
club_root = SithFile(parent=None, name="clubs", is_folder=True, owner=root) club_root = SithFile(parent=None, name="clubs", is_folder=True, owner=root)

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_user_home'),
]
operations = [
migrations.AddField(
model_name='user',
name='avatar_pict',
field=models.OneToOneField(related_name='avatar_of', verbose_name='avatar', to='core.SithFile', null=True, blank=True),
),
migrations.AddField(
model_name='user',
name='profile_pict',
field=models.OneToOneField(related_name='profile_of', verbose_name='profile', to='core.SithFile', null=True, blank=True),
),
migrations.AddField(
model_name='user',
name='scrub_pict',
field=models.OneToOneField(related_name='scrub_of', verbose_name='scrub', to='core.SithFile', null=True, blank=True),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0003_auto_20160810_1949'),
]
operations = [
migrations.AlterField(
model_name='user',
name='nick_name',
field=models.CharField(verbose_name='nick name', max_length=30, blank=True),
),
]

View File

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import core.models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_auto_20160811_0206'),
]
operations = [
migrations.AddField(
model_name='user',
name='department',
field=models.CharField(max_length=15, choices=[('TC', 'TC'), ('IMSI', 'IMSI'), ('IMAP', 'IMAP'), ('INFO', 'INFO'), ('GI', 'GI'), ('E', 'E'), ('EE', 'EE'), ('GESC', 'GESC'), ('GMC', 'GMC'), ('MC', 'MC'), ('EDIM', 'EDIM'), ('HUMAN', 'Humanities'), ('NA', 'N/A')], default='NA', verbose_name='department'),
),
migrations.AddField(
model_name='user',
name='dpt_option',
field=models.CharField(max_length=32, default='', verbose_name='dpt option'),
),
migrations.AddField(
model_name='user',
name='forum_signature',
field=models.TextField(max_length=256, default='', verbose_name='forum signature'),
),
migrations.AddField(
model_name='user',
name='promo',
field=models.IntegerField(blank=True, null=True, validators=[core.models.validate_promo], verbose_name='promo'),
),
migrations.AddField(
model_name='user',
name='quote',
field=models.CharField(max_length=64, default='', verbose_name='quote'),
),
migrations.AddField(
model_name='user',
name='role',
field=models.CharField(max_length=15, choices=[('STUDENT', 'Student'), ('ADMINISTRATIVE', 'Administrative agent'), ('TEACHER', 'Teacher'), ('AGENT', 'Agent'), ('DOCTOR', 'Doctor'), ('FORMER STUDENT', 'Former student'), ('SERVICE', 'Service')], default='STUDENT', verbose_name='role'),
),
migrations.AddField(
model_name='user',
name='school',
field=models.CharField(max_length=32, default='', verbose_name='school'),
),
migrations.AddField(
model_name='user',
name='semester',
field=models.CharField(max_length=5, default='', verbose_name='semester'),
),
migrations.AddField(
model_name='user',
name='sex',
field=models.CharField(max_length=10, choices=[('MAN', 'Man'), ('WOMAN', 'Woman')], default='MAN', verbose_name='sex'),
),
migrations.AddField(
model_name='user',
name='tshirt_size',
field=models.CharField(max_length=5, choices=[('-', '-'), ('XS', 'XS'), ('S', 'S'), ('M', 'M'), ('L', 'L'), ('XL', 'XL'), ('XXL', 'XXL'), ('XXXL', 'XXXL')], default='M', verbose_name='tshirt size'),
),
]

View File

@ -7,7 +7,7 @@ from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
from datetime import datetime, timedelta from datetime import datetime, timedelta, date
import unicodedata import unicodedata
@ -46,6 +46,15 @@ class RealGroup(Group):
class Meta: class Meta:
proxy = True proxy = True
def validate_promo(value):
start_year = settings.SITH_SCHOOL_START_YEAR
delta = (date.today()+timedelta(days=180)).year - start_year
if value < 0 or delta < value:
raise ValidationError(
_('%(value)s is not a valid promo (between 0 and %(end)s)'),
params={'value': value, 'end': delta},
)
class User(AbstractBaseUser): class User(AbstractBaseUser):
""" """
Defines the base user class, useable in every app Defines the base user class, useable in every app
@ -77,7 +86,7 @@ class User(AbstractBaseUser):
last_name = models.CharField(_('last name'), max_length=30) last_name = models.CharField(_('last name'), max_length=30)
email = models.EmailField(_('email address'), unique=True) email = models.EmailField(_('email address'), unique=True)
date_of_birth = models.DateField(_('date of birth'), blank=True, null=True) date_of_birth = models.DateField(_('date of birth'), blank=True, null=True)
nick_name = models.CharField(max_length=30, blank=True) nick_name = models.CharField(_('nick name'), max_length=30, blank=True)
is_staff = models.BooleanField( is_staff = models.BooleanField(
_('staff status'), _('staff status'),
default=False, default=False,
@ -101,6 +110,51 @@ class User(AbstractBaseUser):
) )
groups = models.ManyToManyField(RealGroup, related_name='users', blank=True) groups = models.ManyToManyField(RealGroup, related_name='users', blank=True)
home = models.OneToOneField('SithFile', related_name='home_of', verbose_name=_("home"), null=True, blank=True) home = models.OneToOneField('SithFile', related_name='home_of', verbose_name=_("home"), null=True, blank=True)
profile_pict = models.OneToOneField('SithFile', related_name='profile_of', verbose_name=_("profile"), null=True, blank=True)
avatar_pict = models.OneToOneField('SithFile', related_name='avatar_of', verbose_name=_("avatar"), null=True, blank=True)
scrub_pict = models.OneToOneField('SithFile', related_name='scrub_of', verbose_name=_("scrub"), null=True, blank=True)
sex = models.CharField(_("sex"), max_length=10, choices=[("MAN", _("Man")), ("WOMAN", _("Woman"))], default="MAN")
tshirt_size = models.CharField(_("tshirt size"), max_length=5, choices=[
("-", _("-")),
("XS", _("XS")),
("S", _("S")),
("M", _("M")),
("L", _("L")),
("XL", _("XL")),
("XXL", _("XXL")),
("XXXL", _("XXXL")),
], default="M")
role = models.CharField(_("role"), max_length=15, choices=[
("STUDENT", _("Student")),
("ADMINISTRATIVE", _("Administrative agent")),
("TEACHER", _("Teacher")),
("AGENT", _("Agent")),
("DOCTOR", _("Doctor")),
("FORMER STUDENT", _("Former student")),
("SERVICE", _("Service")),
], default="STUDENT")
department = models.CharField(_("department"), max_length=15, choices=[
("TC", _("TC")),
("IMSI", _("IMSI")),
("IMAP", _("IMAP")),
("INFO", _("INFO")),
("GI", _("GI")),
("E", _("E")),
("EE", _("EE")),
("GESC", _("GESC")),
("GMC", _("GMC")),
("MC", _("MC")),
("EDIM", _("EDIM")),
("HUMAN", _("Humanities")),
("NA", _("N/A")),
], default="NA")
dpt_option = models.CharField(_("dpt option"), max_length=32, default="")
semester = models.CharField(_("semester"), max_length=5, default="")
quote = models.CharField(_("quote"), max_length=64, default="")
school = models.CharField(_("school"), max_length=32, default="")
promo = models.IntegerField(_("promo"), validators=[validate_promo], null=True, blank=True)
forum_signature = models.TextField(_("forum signature"), max_length=256, default="")
# TODO: add phone numbers with https://github.com/stefanfoulis/django-phonenumber-field
objects = UserManager() objects = UserManager()
@ -341,6 +395,15 @@ class SithFile(models.Model):
def is_owned_by(self, user): def is_owned_by(self, user):
return user.id == self.owner.id return user.id == self.owner.id
def can_be_viewed_by(self, user):
if hasattr(self, 'profile_of'):
return user.can_view(self.profile_of)
if hasattr(self, 'avatar_of'):
return user.can_view(self.avatar_of)
if hasattr(self, 'scrub_of'):
return user.can_view(self.scrub_of)
return False
def delete(self): def delete(self):
for c in self.children.all(): for c in self.children.all():
c.delete() c.delete()
@ -422,6 +485,9 @@ class SithFile(models.Model):
def get_display_name(self): def get_display_name(self):
return self.name return self.name
def get_download_url(self):
return reverse('core:download', kwargs={'file_id': self.id})
class LockError(Exception): class LockError(Exception):
"""There was a lock error on the object""" """There was a lock error on the object"""
pass pass

View File

@ -2,6 +2,11 @@
Super Form Reset Super Form Reset
----------------------------------------------------------------------------------------------------*/ ----------------------------------------------------------------------------------------------------*/
form {
margin: 0px auto;
width: 60%;
}
input, input,
label, label,
select, select,
@ -22,6 +27,10 @@ textarea
font-family: Arial; font-family: Arial;
} }
label {
min-width: 50%;
}
/* Remove the stupid outer glow in Webkit */ /* Remove the stupid outer glow in Webkit */
input:focus input:focus
{ {
@ -70,7 +79,8 @@ input[type=tel],
input[type=text], input[type=text],
input[type=time], input[type=time],
input[type=url], input[type=url],
input[type=week] input[type=week],
textarea
{ {
background-color: white; background-color: white;
border: 1px solid black; border: 1px solid black;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -1,11 +1,29 @@
console.log('Guy'); console.log('Guy');
$( function() { $( function() {
dialog = $( ".choose_file_widget" ).dialog({ buttons = $(".choose_file_button");
popups = $(".choose_file_widget");
popups.dialog({
autoOpen: false, autoOpen: false,
modal: true, modal: true,
width: "80%",
minHeight: "300",
buttons: {
"Choose": function() {
console.log($("#file_id"));
$("input[name="+$(this).attr('name')+"]").attr('value', $("#file_id").attr('value'));
$( this ).dialog( "close" );
}
}
});
$('.select_date').datepicker({
changeMonth: true,
changeYear: true
}); });
$( ".choose_file_button" ).button().on( "click", function() { $( ".choose_file_button" ).button().on( "click", function() {
dialog.dialog( "open" ); popup = popups.filter("[name="+$(this).attr('name')+"]");
console.log(popup);
popup.html('<iframe src="/file/popup" width="95%"></iframe><span id="file_id" value="null" />');
popup.dialog({title: $(this).attr('name')}).dialog( "open" );
}); });
} ); } );

View File

@ -118,12 +118,16 @@ ul, ol {
} }
table { table {
width: 100%; width: 100%;
font-size: 0.90em;
} }
td { td {
padding: 4px; padding: 4px;
border: solid 1px black; border: solid 1px black;
border-collapse: collapse; border-collapse: collapse;
vertical-align: top; vertical-align: top;
overflow: hidden;
text-overflow: ellipsis;
max-width: 0;
} }
td>ul { td>ul {
margin-top: 0px; margin-top: 0px;
@ -152,7 +156,27 @@ tbody>tr:hover {
} }
/*-----------------------------USER PROFILE----------------------------*/ /*-----------------------------USER PROFILE----------------------------*/
.user_profile { #user_profile {
width: 80%;
margin: 0px auto;
padding: 10px;
overflow: auto;
}
#user_profile h4 { border-bottom: 1px solid grey; max-width: 60%; }
#user_profile #pictures {
width: 30%;
float: right;
font-style: italic;
}
#user_profile #nickname {
font-style: italic;
}
#user_profile #pictures img {
max-width: 96%;
max-height: 96%;
}
#user_profile .promo_pict {
height: 45px;
} }
/*---------------------------------PAGE--------------------------------*/ /*---------------------------------PAGE--------------------------------*/
.page_content { .page_content {

View File

@ -60,23 +60,25 @@
{{ tests }} {{ tests }}
{% endblock %} {% endblock %}
--> -->
{% block script %}
<script src="{{ static('core/js/jquery-3.1.0.min.js') }}"></script> <script src="{{ static('core/js/jquery-3.1.0.min.js') }}"></script>
<script src="{{ static('core/js/ui/jquery-ui.min.js') }}"></script> <script src="{{ static('core/js/ui/jquery-ui.min.js') }}"></script>
<script src="{{ static('core/js/multiple-select.js') }}"></script> <script src="{{ static('core/js/multiple-select.js') }}"></script>
<script src="{{ static('core/js/script.js') }}"></script> <script src="{{ static('core/js/script.js') }}"></script>
<script> <script>
$('select:not([multiple])').multipleSelect({ $('.select_single').multipleSelect({
single: true, single: true,
{% if not popup %} {% if not popup %}
position: 'top', position: 'top',
{% endif %} {% endif %}
}); });
$('select[multiple=multiple]').multipleSelect({ $('.select_multiple').multipleSelect({
filter: true, filter: true,
{% if not popup %} {% if not popup %}
position: 'top', position: 'top',
{% endif %} {% endif %}
}); });
</script> </script>
{% endblock %}
</body> </body>
</html> </html>

View File

@ -1,5 +1,9 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{% block title %}
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
{% endblock %}
{% block content %} {% block content %}
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2> <h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
<form action="" method="post"> <form action="" method="post">

View File

@ -42,8 +42,18 @@
{% if not file.home_of and not file.home_of_club and file.parent %} {% if not file.home_of and not file.home_of_club and file.parent %}
<p><a href="{{ url('core:file_delete', file_id=file.id, popup=popup) }}">{% trans %}Delete{% endtrans %}</a></p> <p><a href="{{ url('core:file_delete', file_id=file.id, popup=popup) }}">{% trans %}Delete{% endtrans %}</a></p>
{% endif %} {% endif %}
{% if popup %}
{% endif %}
{% endblock %}
{% block script %}
{{ super() }}
{% if popup and file.is_file %}
<script>
parent.$("#file_id").replaceWith('<span id="file_id" value="{{ file.id }}">{{ file.name }}</span>');
</script>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -21,7 +21,9 @@
<form method="post" action="{{ url('core:login') }}"> <form method="post" action="{{ url('core:login') }}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} <p>{{ form.username.errors }}<label for="{{ form.username.name }}">{{ form.username.label }}
</label><input id="id_username" maxlength="254" name="username" type="text" autofocus="autofocus" /></p>
<p>{{ form.password.errors }}<label for="{{ form.password.name }}">{{ form.password.label }}</label>{{ form.password }}</p>
<input type="hidden" name="next" value="{{ next }}"> <input type="hidden" name="next" value="{{ next }}">
<p><input type="submit" value="{% trans %}login{% endtrans %}"></p> <p><input type="submit" value="{% trans %}login{% endtrans %}"></p>
</form> </form>

View File

@ -5,12 +5,26 @@
{% endblock %} {% endblock %}
{% block infos %} {% block infos %}
<h3>{% trans %}User Profile{% endtrans %}</h3>
<div class="user_profile"> <div id="user_profile">
<div id="pictures">
{% if profile.profile_pict %}
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" />
{% endif %}
<p><em>{{ profile.quote }}</em></p>
</div>
<h4>{{ profile.get_full_name() }}</h4> <h4>{{ profile.get_full_name() }}</h4>
<p>{{ profile.nick_name }}</p> <p id="nickname">&laquo; {{ profile.nick_name }} &raquo;</p>
<p>{% trans %}Born: {% endtrans %}{{ profile.date_of_birth|date("d/m/Y") }}</p> <p>{% trans %}Born: {% endtrans %}{{ profile.date_of_birth|date("d/m/Y") }}</p>
<p>{{ profile.department }}{{ profile.semester }}
{% if profile.dpt_option %}
<br>{% trans %}Option: {% endtrans %}{{ profile.dpt_option }}
{% endif %}
</p>
{% if profile.promo %}
<p><img src="{{ static('core/img/promo_%02d.png' % profile.promo) }}" alt="Promo {{ profile.promo }}" class="promo_pict" />
{% trans %}Promo: {% endtrans %}{{ profile.promo }}</p>
{% endif %}
</div> </div>
{% if user.membership.filter(end_date=None).exists() or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) %} {% if user.membership.filter(end_date=None).exists() or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) %}

View File

@ -1,15 +1,31 @@
{% extends "core/base.jinja" %} {% extends "core/user_base.jinja" %}
{% block content %} {% block infos %}
<h2>{% trans %}Edit user profile{% endtrans %}</h2> <h2>{% trans %}Edit user profile{% endtrans %}</h2>
<form action="" method="post"> <form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {% for field in form %}
<p>{{ field.errors }}<label for="{{ field.name }}">{{ field.label }}
{%- if field.name == "profile_pict" and form.instance.profile_pict -%}
<br>{% trans %}Current profile: {% endtrans %}
<img src="{{ form.instance.profile_pict.get_download_url() }}" title="{% trans %}Profile{% endtrans %}" width="50px" /><br>
{%- elif field.name == "avatar_pict" and form.instance.avatar_pict -%}
<br>{% trans %}Current avatar: {% endtrans %}
<img src="{{ form.instance.avatar_pict.get_download_url() }}" title="{% trans %}Avatar{% endtrans %}" width="50px" /><br>
{%- elif field.name == "scrub_pict" and form.instance.scrub_pict -%}
<br>{% trans %}Current scrub: {% endtrans %}
<img src="{{ form.instance.scrub_pict.get_download_url() }}" title="{% trans %}Scrub{% endtrans %}" width="50px" /><br>
{%- endif %}</label> {{ field }}</p>
{% endfor %}
<p><input type="submit" value="{% trans %}Update{% endtrans %}" /></p> <p><input type="submit" value="{% trans %}Update{% endtrans %}" /></p>
</form> <p>{% trans %}Username: {% endtrans %}{{ form.instance.username }}</p>
{% if form.instance.customer %}
<p>{% trans %}Account number: {% endtrans %}{{ form.instance.customer.account_id }}</p>
{% endif %}
{% if form.instance == user %} {% if form.instance == user %}
<p><a href="{{ url('core:password_change') }}">{% trans %}Change my password{% endtrans %}</a></p> <p><a href="{{ url('core:password_change') }}">{% trans %}Change my password{% endtrans %}</a></p>
{% endif %} {% endif %}
</form>
{% endblock %} {% endblock %}

View File

@ -1,6 +1,6 @@
{% extends "core/base.jinja" %} {% extends "core/user_base.jinja" %}
{% block content %} {% block infos %}
<h2>{% trans user_name=profile.get_full_name() %}Edit user groups for {{ user_name }}{% endtrans %}</h2> <h2>{% trans user_name=profile.get_full_name() %}Edit user groups for {{ user_name }}{% endtrans %}</h2>
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}

View File

@ -8,8 +8,11 @@ from django.contrib.auth.forms import AuthenticationForm
from core.models import Group from core.models import Group
def forbidden(request): def forbidden(request):
try:
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form':
AuthenticationForm(), 'popup': request.resolver_match.kwargs['popup'] or ""})) AuthenticationForm(), 'popup': request.resolver_match.kwargs['popup'] or ""}))
except:
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': AuthenticationForm()}))
def not_found(request): def not_found(request):
return HttpResponseNotFound(render(request, "core/404.jinja")) return HttpResponseNotFound(render(request, "core/404.jinja"))

View File

@ -37,7 +37,7 @@ def send_file(request, file_id):
response['Content-Disposition'] = 'inline; filename="%s"' % f.name response['Content-Disposition'] = 'inline; filename="%s"' % f.name
return response return response
class AddFileForm(forms.Form): class AddFilesForm(forms.Form):
folder_name = forms.CharField(label=_("Add a new folder"), max_length=30, required=False) folder_name = forms.CharField(label=_("Add a new folder"), max_length=30, required=False)
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), label=_("Files"), file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), label=_("Files"),
required=False) required=False)
@ -128,7 +128,7 @@ class FileView(CanViewMixin, DetailView, FormMixin):
pk_url_kwarg = "file_id" pk_url_kwarg = "file_id"
template_name = 'core/file_detail.jinja' template_name = 'core/file_detail.jinja'
context_object_name = "file" context_object_name = "file"
form_class = AddFileForm form_class = AddFilesForm
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.form = self.get_form() self.form = self.get_form()

View File

@ -1,11 +1,56 @@
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm
from django import forms from django import forms
from django.db import transaction
from django.core.exceptions import ValidationError
from django.contrib.auth import logout, login, authenticate from django.contrib.auth import logout, login, authenticate
from django.forms import CheckboxSelectMultiple, Select from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import logging import logging
from core.models import User, Page, RealGroup from core.models import User, Page, RealGroup, SithFile
# Widgets
class SelectSingle(Select):
def render(self, name, value, attrs=None):
if attrs:
attrs['class'] = "select_single"
else:
attrs = {'class': "select_single"}
return super(SelectSingle, self).render(name, value, attrs)
class SelectMultiple(Select):
def render(self, name, value, attrs=None):
if attrs:
attrs['class'] = "select_multiple"
else:
attrs = {'class': "select_multiple"}
return super(SelectMultiple, self).render(name, value, attrs)
class SelectDate(DateInput):
def render(self, name, value, attrs=None):
if attrs:
attrs['class'] = "select_date"
else:
attrs = {'class': "select_date"}
return super(SelectDate, self).render(name, value, attrs)
class SelectFile(TextInput):
def render(self, name, value, attrs=None):
if attrs:
attrs['class'] = "select_file"
else:
attrs = {'class': "select_file"}
output = '%(content)s<div name="%(name)s" class="choose_file_widget" title="%(title)s"></div>' % {
'content': super(SelectFile, self).render(name, value, attrs),
'title': _("Choose file"),
'name': name,
}
output += '<span name="' + name + '" class="choose_file_button">' + _("Choose file") + '</span>'
print(output)
return output
# Forms
class RegisteringForm(UserCreationForm): class RegisteringForm(UserCreationForm):
error_css_class = 'error' error_css_class = 'error'
@ -22,6 +67,69 @@ class RegisteringForm(UserCreationForm):
user.save() user.save()
return user return user
class UserProfileForm(forms.ModelForm):
"""
Form handling the user profile, managing the files
This form is actually pretty bad and was made in the rush before the migration. It should be refactored.
TODO: refactor this form
"""
class Meta:
model = User
fields = ['first_name', 'last_name', 'nick_name', 'email', 'date_of_birth', 'profile_pict', 'avatar_pict',
'scrub_pict', 'sex', 'tshirt_size', 'role', 'department', 'dpt_option', 'semester', 'quote', 'school',
'promo', 'forum_signature']
widgets = {
'date_of_birth': SelectDate,
'profile_pict': forms.ClearableFileInput,
'avatar_pict': forms.ClearableFileInput,
'scrub_pict': forms.ClearableFileInput,
}
labels = {
'profile_pict': _("Profile: you need to be visible on the picture, in order to be recognized (e.g. by the barmen)"),
'avatar_pict': _("Avatar: used on the forum"),
'scrub_pict': _("Scrub: let other know how your scrub looks like!"),
}
def __init__(self, *arg, **kwargs):
super(UserProfileForm, self).__init__(*arg, **kwargs)
def full_clean(self):
super(UserProfileForm, self).full_clean()
def generate_name(self, field_name, f):
field_name = field_name[:-4]
return field_name + str(self.instance.id) + "." + f.content_type.split('/')[-1]
def process(self, files):
avatar = self.instance.avatar_pict
profile = self.instance.profile_pict
scrub = self.instance.scrub_pict
self.full_clean()
self.cleaned_data['avatar_pict'] = avatar
self.cleaned_data['profile_pict'] = profile
self.cleaned_data['scrub_pict'] = scrub
parent = SithFile.objects.filter(parent=None, name="profiles").first()
for field,f in files:
with transaction.atomic():
new_file = SithFile(parent=parent, name=self.generate_name(field, f), file=f, owner=self.instance, is_folder=False,
mime_type=f.content_type, size=f._size)
try:
if not (f.content_type == "image/jpeg" or
f.content_type == "image/png" or
f.content_type == "image/gif"):
raise ValidationError(_("Bad image format, only jpeg, png, and gif are accepted"))
old = SithFile.objects.filter(parent=parent, name=new_file.name).first()
if old:
old.delete()
new_file.clean()
new_file.save()
self.cleaned_data[field] = new_file
self._errors.pop(field, None)
except ValidationError as e:
self._errors.pop(field, None)
self.add_error(field, _("Error uploading file %(file_name)s: %(msg)s") %
{'file_name': f, 'msg': str(e.message)})
self._post_clean()
class UserPropForm(forms.ModelForm): class UserPropForm(forms.ModelForm):
error_css_class = 'error' error_css_class = 'error'
@ -52,13 +160,3 @@ class PagePropForm(forms.ModelForm):
self.fields['edit_groups'].required = False self.fields['edit_groups'].required = False
self.fields['view_groups'].required = False self.fields['view_groups'].required = False
class SelectFile(Select):
def render(self, name, value, attrs=None):
output = '<span class="choose_file_widget" title="%(title)s">%(content)s</span>' % {
'title': _("Choose file"),
'content': super(SelectFile, self).render(name, value, attrs),
}
output += '<span class="choose_file_button">' + _("Choose file") + '</span>'
print(output)
return output

View File

@ -11,7 +11,7 @@ from django.conf import settings
import logging import logging
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin
from core.views.forms import RegisteringForm, UserPropForm from core.views.forms import RegisteringForm, UserPropForm, UserProfileForm
from core.models import User from core.models import User
def login(request): def login(request):
@ -115,7 +115,31 @@ class UserUpdateProfileView(CanEditMixin, UpdateView):
model = User model = User
pk_url_kwarg = "user_id" pk_url_kwarg = "user_id"
template_name = "core/user_edit.jinja" template_name = "core/user_edit.jinja"
fields = ('first_name', 'last_name', 'nick_name', 'email', 'date_of_birth', ) form_class = UserProfileForm
def get(self, request, *args, **kwargs):
self.object = self.get_object()
self.form = self.get_form()
if self.form.instance.profile_pict and not request.user.is_in_group(settings.SITH_MAIN_BOARD_GROUP):
self.form.fields.pop('profile_pict', None)
return self.render_to_response(self.get_context_data(form=self.form))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
self.form = self.get_form()
if self.form.instance.profile_pict and not request.user.is_in_group(settings.SITH_MAIN_BOARD_GROUP):
self.form.fields.pop('profile_pict', None)
files = request.FILES.items()
self.form.process(files)
if request.user.is_authenticated() and request.user.can_edit(self.object) and self.form.is_valid():
return super(UserUpdateProfileView, self).form_valid(self.form)
return self.form_invalid(self.form)
def get_context_data(self, **kwargs):
kwargs = super(UserUpdateProfileView, self).get_context_data(**kwargs)
kwargs['profile'] = self.form.instance
kwargs['form'] = self.form
return kwargs
class UserUpdateGroupView(CanEditPropMixin, UpdateView): class UserUpdateGroupView(CanEditPropMixin, UpdateView):
""" """

Binary file not shown.

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-10 05:00+0200\n" "POT-Creation-Date: 2016-08-11 04:02+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n" "Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -40,12 +40,12 @@ msgstr "numero de compte"
msgid "%(club_account)s on %(bank_account)s" msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s" msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:109 club/models.py:112 counter/models.py:268 #: accounting/models.py:109 club/models.py:147 counter/models.py:268
#: launderette/models.py:112 #: launderette/models.py:112
msgid "start date" msgid "start date"
msgstr "date de début" msgstr "date de début"
#: accounting/models.py:110 club/models.py:113 counter/models.py:269 #: accounting/models.py:110 club/models.py:148 counter/models.py:269
msgid "end date" msgid "end date"
msgstr "date de fin" msgstr "date de fin"
@ -66,8 +66,9 @@ msgstr "montant effectif"
msgid "number" msgid "number"
msgstr "numéro" msgstr "numéro"
#: accounting/models.py:154 core/models.py:560 counter/models.py:209 #: accounting/models.py:154 core/models.py:390 core/models.py:666
#: counter/models.py:244 eboutic/models.py:13 eboutic/models.py:46 #: counter/models.py:209 counter/models.py:244 eboutic/models.py:13
#: eboutic/models.py:46
msgid "date" msgid "date"
msgstr "date" msgstr "date"
@ -121,7 +122,7 @@ msgstr "Compte"
msgid "Company" msgid "Company"
msgstr "Entreprise" msgstr "Entreprise"
#: accounting/models.py:163 sith/settings.py:260 sith/settings_sample.py:260 #: accounting/models.py:163 sith/settings.py:263 sith/settings_sample.py:263
msgid "Other" msgid "Other"
msgstr "Autre" msgstr "Autre"
@ -205,7 +206,7 @@ msgstr "Nouveau compte club"
#: accounting/templates/accounting/bank_account_list.jinja:15 #: accounting/templates/accounting/bank_account_list.jinja:15
#: accounting/templates/accounting/club_account_details.jinja:44 #: accounting/templates/accounting/club_account_details.jinja:44
#: accounting/templates/accounting/journal_details.jinja:62 #: accounting/templates/accounting/journal_details.jinja:62
#: club/templates/club/club_detail.jinja:7 core/templates/core/file.jinja:46 #: club/templates/club/club_detail.jinja:7 core/templates/core/file.jinja:38
#: core/templates/core/page.jinja:31 core/templates/core/user_base.jinja:8 #: core/templates/core/page.jinja:31 core/templates/core/user_base.jinja:8
#: core/templates/core/user_tools.jinja:37 #: core/templates/core/user_tools.jinja:37
#: counter/templates/counter/counter_list.jinja:15 #: counter/templates/counter/counter_list.jinja:15
@ -216,7 +217,7 @@ msgstr "Éditer"
#: accounting/templates/accounting/bank_account_details.jinja:19 #: accounting/templates/accounting/bank_account_details.jinja:19
#: accounting/templates/accounting/bank_account_list.jinja:16 #: accounting/templates/accounting/bank_account_list.jinja:16
#: core/templates/core/file_detail.jinja:38 #: core/templates/core/file_detail.jinja:43
#: core/templates/core/group_list.jinja:13 #: core/templates/core/group_list.jinja:13
#: launderette/templates/launderette/launderette_admin.jinja:16 #: launderette/templates/launderette/launderette_admin.jinja:16
#: launderette/views.py:146 #: launderette/views.py:146
@ -296,7 +297,7 @@ msgid "No"
msgstr "Non" msgstr "Non"
#: accounting/templates/accounting/club_account_details.jinja:43 #: accounting/templates/accounting/club_account_details.jinja:43
#: core/templates/core/file.jinja:44 core/templates/core/page.jinja:28 #: core/templates/core/file.jinja:36 core/templates/core/page.jinja:28
msgid "View" msgid "View"
msgstr "Voir" msgstr "Voir"
@ -381,37 +382,45 @@ msgstr "Un club avec ce nom UNIX existe déjà."
msgid "address" msgid "address"
msgstr "Adresse" msgstr "Adresse"
#: club/models.py:45 #: club/models.py:38 core/models.py:112
msgid "home"
msgstr "home"
#: club/models.py:46
msgid "You can not make loops in clubs" msgid "You can not make loops in clubs"
msgstr "Vous ne pouvez pas faire de boucles dans les clubs" msgstr "Vous ne pouvez pas faire de boucles dans les clubs"
#: club/models.py:110 eboutic/models.py:12 eboutic/models.py:45 #: club/models.py:60
msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà."
#: club/models.py:145 eboutic/models.py:12 eboutic/models.py:45
#: launderette/models.py:81 launderette/models.py:116 #: launderette/models.py:81 launderette/models.py:116
msgid "user" msgid "user"
msgstr "nom d'utilisateur" msgstr "nom d'utilisateur"
#: club/models.py:111 #: club/models.py:146
msgid "club" msgid "club"
msgstr "club" msgstr "club"
#: club/models.py:114 #: club/models.py:149 core/models.py:127
msgid "role" msgid "role"
msgstr "rôle" msgstr "rôle"
#: club/models.py:116 core/models.py:27 counter/models.py:53 #: club/models.py:151 core/models.py:28 counter/models.py:53
#: counter/models.py:78 #: counter/models.py:78
msgid "description" msgid "description"
msgstr "description" msgstr "description"
#: club/models.py:121 #: club/models.py:156
msgid "User must be subscriber to take part to a club" msgid "User must be subscriber to take part to a club"
msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" msgstr "L'utilisateur doit être cotisant pour faire partie d'un club"
#: club/models.py:123 #: club/models.py:158
msgid "User is already member of that club" msgid "User is already member of that club"
msgstr "L'utilisateur est déjà membre de ce club" msgstr "L'utilisateur est déjà membre de ce club"
#: club/models.py:127 #: club/models.py:162
msgid "past member" msgid "past member"
msgstr "Anciens membres" msgstr "Anciens membres"
@ -420,7 +429,7 @@ msgstr "Anciens membres"
msgid "Back to list" msgid "Back to list"
msgstr "Retour à la liste" msgstr "Retour à la liste"
#: club/templates/club/club_detail.jinja:10 core/templates/core/file.jinja:49 #: club/templates/club/club_detail.jinja:10 core/templates/core/file.jinja:41
#: core/templates/core/page.jinja:34 #: core/templates/core/page.jinja:34
msgid "Prop" msgid "Prop"
msgstr "Propriétés" msgstr "Propriétés"
@ -435,7 +444,7 @@ msgstr "Éditer le club"
#: club/templates/club/club_edit.jinja:8 #: club/templates/club/club_edit.jinja:8
#: club/templates/club/club_edit_prop.jinja:8 #: club/templates/club/club_edit_prop.jinja:8
#: core/templates/core/create.jinja:8 core/templates/core/edit.jinja:8 #: core/templates/core/create.jinja:8 core/templates/core/edit.jinja:12
#: core/templates/core/file_edit.jinja:8 core/templates/core/page_prop.jinja:8 #: core/templates/core/file_edit.jinja:8 core/templates/core/page_prop.jinja:8
#: core/templates/core/pagerev_edit.jinja:24 #: core/templates/core/pagerev_edit.jinja:24
#: counter/templates/counter/counter_edit.jinja:8 #: counter/templates/counter/counter_edit.jinja:8
@ -463,7 +472,8 @@ msgstr "Il n'y a pas de club dans ce site web."
msgid "Club members" msgid "Club members"
msgstr "Membres du club" msgstr "Membres du club"
#: club/templates/club/club_members.jinja:13 launderette/views.py:146 #: club/templates/club/club_members.jinja:13
#: core/templates/core/file_detail.jinja:19 launderette/views.py:146
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
@ -476,25 +486,30 @@ msgstr "Outils club"
msgid "Counters:" msgid "Counters:"
msgstr "Comptoirs : " msgstr "Comptoirs : "
#: core/models.py:23 #: core/models.py:24
msgid "meta group status" msgid "meta group status"
msgstr "status du meta-groupe" msgstr "status du meta-groupe"
#: core/models.py:25 #: core/models.py:26
msgid "Whether a group is a meta group or not" msgid "Whether a group is a meta group or not"
msgstr "Si un groupe est un meta-groupe ou pas" msgstr "Si un groupe est un meta-groupe ou pas"
#: core/models.py:60 #: core/models.py:54
#, python-format
msgid "%(value)s is not a valid promo (between 0 and %(end)s)"
msgstr "%(value)s n'est pas une promo valide (doit être entre 0 et %(end)s)"
#: core/models.py:70
msgid "username" msgid "username"
msgstr "nom d'utilisateur" msgstr "nom d'utilisateur"
#: core/models.py:63 #: core/models.py:73
msgid "Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only." msgid "Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only."
msgstr "" msgstr ""
"Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et @/./" "Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et @/./"
"+/-/_" "+/-/_"
#: core/models.py:67 #: core/models.py:77
msgid "" msgid ""
"Enter a valid username. This value may contain only letters, numbers and @/./" "Enter a valid username. This value may contain only letters, numbers and @/./"
"+/-/_ characters." "+/-/_ characters."
@ -502,39 +517,43 @@ msgstr ""
"Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et @/./" "Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et @/./"
"+/-/_" "+/-/_"
#: core/models.py:72 #: core/models.py:82
msgid "A user with that username already exists." msgid "A user with that username already exists."
msgstr "Un utilisateur de ce nom existe déjà" msgstr "Un utilisateur de ce nom existe déjà"
#: core/models.py:75 #: core/models.py:85
msgid "first name" msgid "first name"
msgstr "Prénom" msgstr "Prénom"
#: core/models.py:76 #: core/models.py:86
msgid "last name" msgid "last name"
msgstr "Nom" msgstr "Nom"
#: core/models.py:77 #: core/models.py:87
msgid "email address" msgid "email address"
msgstr "adresse email" msgstr "adresse email"
#: core/models.py:78 #: core/models.py:88
msgid "date of birth" msgid "date of birth"
msgstr "date de naissance" msgstr "date de naissance"
#: core/models.py:81 #: core/models.py:89
msgid "nick name"
msgstr "surnom"
#: core/models.py:91
msgid "staff status" msgid "staff status"
msgstr "status \"staff\"" msgstr "status \"staff\""
#: core/models.py:83 #: core/models.py:93
msgid "Designates whether the user can log into this admin site." msgid "Designates whether the user can log into this admin site."
msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site." msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site."
#: core/models.py:86 #: core/models.py:96
msgid "active" msgid "active"
msgstr "actif" msgstr "actif"
#: core/models.py:89 #: core/models.py:99
msgid "" msgid ""
"Designates whether this user should be treated as active. Unselect this " "Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts." "instead of deleting accounts."
@ -542,121 +561,293 @@ msgstr ""
"Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au " "Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au "
"lieu de supprimer les comptes." "lieu de supprimer les comptes."
#: core/models.py:93 #: core/models.py:103
msgid "date joined" msgid "date joined"
msgstr "date d'inscription" msgstr "date d'inscription"
#: core/models.py:95 #: core/models.py:105
msgid "superuser" msgid "superuser"
msgstr "super-utilisateur" msgstr "super-utilisateur"
#: core/models.py:98 #: core/models.py:108
msgid "Designates whether this user is a superuser. " msgid "Designates whether this user is a superuser. "
msgstr "Est-ce que l'utilisateur est super-utilisateur." msgstr "Est-ce que l'utilisateur est super-utilisateur."
#: core/models.py:280 #: core/models.py:113
msgid "profile"
msgstr "profil"
#: core/models.py:114
msgid "avatar"
msgstr "avatar"
#: core/models.py:115
msgid "scrub"
msgstr "blouse"
#: core/models.py:116
msgid "sex"
msgstr "sexe"
#: core/models.py:116
msgid "Man"
msgstr "Homme"
#: core/models.py:116
msgid "Woman"
msgstr "Femme"
#: core/models.py:117
msgid "tshirt size"
msgstr "taille de tshirt"
#: core/models.py:118
msgid "-"
msgstr "-"
#: core/models.py:119
msgid "XS"
msgstr "XS"
#: core/models.py:120
msgid "S"
msgstr "S"
#: core/models.py:121
msgid "M"
msgstr "M"
#: core/models.py:122
msgid "L"
msgstr "L"
#: core/models.py:123
msgid "XL"
msgstr "XL"
#: core/models.py:124
msgid "XXL"
msgstr "XXL"
#: core/models.py:125
msgid "XXXL"
msgstr "XXXL"
#: core/models.py:128
msgid "Student"
msgstr "Étudiant"
#: core/models.py:129
msgid "Administrative agent"
msgstr "Personnel administratif"
#: core/models.py:130
msgid "Teacher"
msgstr "Enseignant"
#: core/models.py:131
msgid "Agent"
msgstr "Personnel"
#: core/models.py:132
msgid "Doctor"
msgstr "Doctorant"
#: core/models.py:133
msgid "Former student"
msgstr "Ancien étudiant"
#: core/models.py:134
msgid "Service"
msgstr "Service"
#: core/models.py:136
msgid "department"
msgstr "département"
#: core/models.py:137
msgid "TC"
msgstr "TC"
#: core/models.py:138
msgid "IMSI"
msgstr "IMSI"
#: core/models.py:139
msgid "IMAP"
msgstr "IMAP"
#: core/models.py:140
msgid "INFO"
msgstr "INFO"
#: core/models.py:141
msgid "GI"
msgstr "GI"
#: core/models.py:142
msgid "E"
msgstr "E"
#: core/models.py:143
msgid "EE"
msgstr "EE"
#: core/models.py:144
msgid "GESC"
msgstr "GESC"
#: core/models.py:145
msgid "GMC"
msgstr "GMC"
#: core/models.py:146
msgid "MC"
msgstr "MC"
#: core/models.py:147
msgid "EDIM"
msgstr "EDIM"
#: core/models.py:148
msgid "Humanities"
msgstr "Humanités"
#: core/models.py:149
msgid "N/A"
msgstr "N/A"
#: core/models.py:151
msgid "dpt option"
msgstr "Filière"
#: core/models.py:152
msgid "semester"
msgstr "semestre"
#: core/models.py:153
msgid "quote"
msgstr "citation"
#: core/models.py:154
msgid "school"
msgstr "école"
#: core/models.py:155
msgid "promo"
msgstr "promo"
#: core/models.py:156
msgid "forum signature"
msgstr "signature du forum"
#: core/models.py:240
msgid "A user with that username already exists"
msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
#: core/models.py:367
msgid "Visitor" msgid "Visitor"
msgstr "Visiteur" msgstr "Visiteur"
#: core/models.py:285 #: core/models.py:372
msgid "define if we show a users stats" msgid "define if we show a users stats"
msgstr "Definit si l'on montre les statistiques de l'utilisateur" msgstr "Definit si l'on montre les statistiques de l'utilisateur"
#: core/models.py:287 #: core/models.py:374
msgid "Show your account statistics to others" msgid "Show your account statistics to others"
msgstr "Montrez vos statistiques de compte aux autres" msgstr "Montrez vos statistiques de compte aux autres"
#: core/models.py:294 #: core/models.py:381
msgid "file name" msgid "file name"
msgstr "nom du fichier" msgstr "nom du fichier"
#: core/models.py:295 core/models.py:409 #: core/models.py:382 core/models.py:515
msgid "parent" msgid "parent"
msgstr "parent" msgstr "parent"
#: core/models.py:296 core/models.py:305 #: core/models.py:383 core/models.py:393
msgid "file" msgid "file"
msgstr "fichier" msgstr "fichier"
#: core/models.py:297 #: core/models.py:384
msgid "owner" msgid "owner"
msgstr "propriétaire" msgstr "propriétaire"
#: core/models.py:298 core/models.py:415 #: core/models.py:385 core/models.py:521
msgid "edit group" msgid "edit group"
msgstr "groupe d'édition" msgstr "groupe d'édition"
#: core/models.py:299 core/models.py:416 #: core/models.py:386 core/models.py:522
msgid "view group" msgid "view group"
msgstr "groupe de vue" msgstr "groupe de vue"
#: core/models.py:300 #: core/models.py:387
msgid "is folder" msgid "is folder"
msgstr "est un dossier" msgstr "est un dossier"
#: core/models.py:301 #: core/models.py:388
msgid "mime type" msgid "mime type"
msgstr "type mime" msgstr "type mime"
#: core/models.py:302 #: core/models.py:389
msgid "size" msgid "size"
msgstr "taille" msgstr "taille"
#: core/models.py:316 #: core/models.py:419
msgid "Character '/' not authorized in name" msgid "Character '/' not authorized in name"
msgstr "Le caractère '/' n'est pas autorisé dans les noms de fichier" msgstr "Le caractère '/' n'est pas autorisé dans les noms de fichier"
#: core/models.py:319 core/models.py:324 #: core/models.py:422 core/models.py:427
msgid "Loop in folder tree" msgid "Loop in folder tree"
msgstr "Boucle dans l'arborescence des dossiers" msgstr "Boucle dans l'arborescence des dossiers"
#: core/models.py:328 #: core/models.py:431
msgid "You can not make a file be a children of a non folder file" msgid "You can not make a file be a children of a non folder file"
msgstr "" msgstr ""
"Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas " "Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas "
"un dossier" "un dossier"
#: core/models.py:332 #: core/models.py:435
msgid "Duplicate file" msgid "Duplicate file"
msgstr "Un fichier de ce nom existe déjà" msgstr "Un fichier de ce nom existe déjà"
#: core/models.py:342 #: core/models.py:445
msgid "You must provide a file" msgid "You must provide a file"
msgstr "Vous devez fournir un fichier" msgstr "Vous devez fournir un fichier"
#: core/models.py:367 #: core/models.py:470
msgid "Folder: " msgid "Folder: "
msgstr "Dossier : " msgstr "Dossier : "
#: core/models.py:369 #: core/models.py:472
msgid "File: " msgid "File: "
msgstr "Fichier : " msgstr "Fichier : "
#: core/models.py:408 core/models.py:412 #: core/models.py:514 core/models.py:518
msgid "page name" msgid "page name"
msgstr "nom de la page" msgstr "nom de la page"
#: core/models.py:413 #: core/models.py:519
msgid "owner group" msgid "owner group"
msgstr "groupe propriétaire" msgstr "groupe propriétaire"
#: core/models.py:444 #: core/models.py:550
msgid "Duplicate page" msgid "Duplicate page"
msgstr "Une page de ce nom existe déjà" msgstr "Une page de ce nom existe déjà"
#: core/models.py:450 #: core/models.py:556
msgid "Loop in page tree" msgid "Loop in page tree"
msgstr "Boucle dans l'arborescence des pages" msgstr "Boucle dans l'arborescence des pages"
#: core/models.py:557 #: core/models.py:663
msgid "revision" msgid "revision"
msgstr "révision" msgstr "révision"
#: core/models.py:558 #: core/models.py:664
msgid "page title" msgid "page title"
msgstr "titre de la page" msgstr "titre de la page"
#: core/models.py:559 #: core/models.py:665
msgid "page content" msgid "page content"
msgstr "contenu de la page" msgstr "contenu de la page"
@ -672,48 +863,48 @@ msgstr "404. Non trouvé"
msgid "Welcome!" msgid "Welcome!"
msgstr "Bienvenue!" msgstr "Bienvenue!"
#: core/templates/core/base.jinja:17 #: core/templates/core/base.jinja:18
msgid "Logo" msgid "Logo"
msgstr "Logo" msgstr "Logo"
#: core/templates/core/base.jinja:20 core/templates/core/login.jinja:4 #: core/templates/core/base.jinja:21 core/templates/core/login.jinja:4
#: core/templates/core/password_reset_complete.jinja:5 #: core/templates/core/password_reset_complete.jinja:5
msgid "Login" msgid "Login"
msgstr "Connexion" msgstr "Connexion"
#: core/templates/core/base.jinja:21 core/templates/core/register.jinja:18 #: core/templates/core/base.jinja:22 core/templates/core/register.jinja:18
msgid "Register" msgid "Register"
msgstr "S'enregister" msgstr "S'enregister"
#: core/templates/core/base.jinja:24 #: core/templates/core/base.jinja:25
msgid "Tools" msgid "Tools"
msgstr "Outils" msgstr "Outils"
#: core/templates/core/base.jinja:25 #: core/templates/core/base.jinja:26
msgid "Logout" msgid "Logout"
msgstr "Déconnexion" msgstr "Déconnexion"
#: core/templates/core/base.jinja:31 #: core/templates/core/base.jinja:36
msgid "Users" msgid "Users"
msgstr "Utilisateurs" msgstr "Utilisateurs"
#: core/templates/core/base.jinja:32 #: core/templates/core/base.jinja:37
msgid "Wiki" msgid "Wiki"
msgstr "Wiki" msgstr "Wiki"
#: core/templates/core/base.jinja:33 #: core/templates/core/base.jinja:38
msgid "Pages" msgid "Pages"
msgstr "Pages" msgstr "Pages"
#: core/templates/core/base.jinja:34 #: core/templates/core/base.jinja:39
msgid "Clubs" msgid "Clubs"
msgstr "Clubs" msgstr "Clubs"
#: core/templates/core/base.jinja:35 #: core/templates/core/base.jinja:40
msgid "Services" msgid "Services"
msgstr "Services" msgstr "Services"
#: core/templates/core/base.jinja:49 #: core/templates/core/base.jinja:55
msgid "Site made by good people" msgid "Site made by good people"
msgstr "Site réalisé par des gens biens" msgstr "Site réalisé par des gens biens"
@ -723,24 +914,29 @@ msgid "Create %(name)s"
msgstr "Créer %(name)s" msgstr "Créer %(name)s"
#: core/templates/core/delete_confirm.jinja:4 #: core/templates/core/delete_confirm.jinja:4
#: core/templates/core/file_delete_confirm.jinja:4
msgid "Delete confirmation" msgid "Delete confirmation"
msgstr "Confirmation de suppression" msgstr "Confirmation de suppression"
#: core/templates/core/delete_confirm.jinja:6 #: core/templates/core/delete_confirm.jinja:6
#: core/templates/core/file_delete_confirm.jinja:6
#, python-format #, python-format
msgid "Are you sure you want to delete \"%(obj)s\"?" msgid "Are you sure you want to delete \"%(obj)s\"?"
msgstr "Êtes-vous sûr de vouloir supprimer \"%(obj)s\" ?" msgstr "Êtes-vous sûr de vouloir supprimer \"%(obj)s\" ?"
#: core/templates/core/delete_confirm.jinja:7 #: core/templates/core/delete_confirm.jinja:7
#: core/templates/core/file_delete_confirm.jinja:7
msgid "Confirm" msgid "Confirm"
msgstr "Confirmation" msgstr "Confirmation"
#: core/templates/core/delete_confirm.jinja:8 #: core/templates/core/delete_confirm.jinja:8
#: core/templates/core/file_delete_confirm.jinja:8
#: counter/templates/counter/counter_click.jinja:71 #: counter/templates/counter/counter_click.jinja:71
msgid "Cancel" msgid "Cancel"
msgstr "Annuler" msgstr "Annuler"
#: core/templates/core/edit.jinja:4 core/templates/core/file_edit.jinja:4 #: core/templates/core/edit.jinja:4 core/templates/core/edit.jinja.py:8
#: core/templates/core/file_edit.jinja:4
#, python-format #, python-format
msgid "Edit %(obj)s" msgid "Edit %(obj)s"
msgstr "Éditer %(obj)s" msgstr "Éditer %(obj)s"
@ -757,35 +953,39 @@ msgstr "Nouveau fichier"
msgid "Not found" msgid "Not found"
msgstr "Non trouvé" msgstr "Non trouvé"
#: core/templates/core/file.jinja:20 core/views/files.py:103 #: core/templates/core/file.jinja:20 core/views/files.py:42
msgid "Files" msgid "Files"
msgstr "Fichiers" msgstr "Fichiers"
#: core/templates/core/file_detail.jinja:15 #: core/templates/core/file.jinja:32
msgid "My files"
msgstr "Mes fichiers"
#: core/templates/core/file_detail.jinja:13
msgid "Owner: " msgid "Owner: "
msgstr "Propriétaire : " msgstr "Propriétaire : "
#: core/templates/core/file_detail.jinja:20
msgid "Upload"
msgstr "Téléverser"
#: core/templates/core/file_detail.jinja:34 #: core/templates/core/file_detail.jinja:34
msgid "Real name: " msgid "Real name: "
msgstr "Nom réel : " msgstr "Nom réel : "
#: core/templates/core/file_detail.jinja:35 #: core/templates/core/file_detail.jinja:35
msgid "Date: "
msgstr "Date : "
#: core/templates/core/file_detail.jinja:37
msgid "Type: " msgid "Type: "
msgstr "Type : " msgstr "Type : "
#: core/templates/core/file_detail.jinja:36 #: core/templates/core/file_detail.jinja:38
msgid "Size: " msgid "Size: "
msgstr "Taille : " msgstr "Taille : "
#: core/templates/core/file_detail.jinja:36 #: core/templates/core/file_detail.jinja:38
msgid "bytes" msgid "bytes"
msgstr "octets" msgstr "octets"
#: core/templates/core/file_detail.jinja:37 #: core/templates/core/file_detail.jinja:40
msgid "Download" msgid "Download"
msgstr "Télécharger" msgstr "Télécharger"
@ -797,7 +997,8 @@ msgstr "Il n'y a pas de fichier sur ce site web."
msgid "Edit group" msgid "Edit group"
msgstr "Éditer le groupe" msgstr "Éditer le groupe"
#: core/templates/core/group_edit.jinja:9 core/templates/core/user_edit.jinja:8 #: core/templates/core/group_edit.jinja:9
#: core/templates/core/user_edit.jinja:20
#: core/templates/core/user_group.jinja:8 #: core/templates/core/user_group.jinja:8
msgid "Update" msgid "Update"
msgstr "Mettre à jour" msgstr "Mettre à jour"
@ -833,12 +1034,12 @@ msgstr ""
msgid "Please login to see this page." msgid "Please login to see this page."
msgstr "Merci de vous identifier pour voir cette page." msgstr "Merci de vous identifier pour voir cette page."
#: core/templates/core/login.jinja:26 #: core/templates/core/login.jinja:28
#: counter/templates/counter/counter_main.jinja:48 #: counter/templates/counter/counter_main.jinja:48
msgid "login" msgid "login"
msgstr "login" msgstr "login"
#: core/templates/core/login.jinja:30 #: core/templates/core/login.jinja:32
msgid "Lost password?" msgid "Lost password?"
msgstr "Mot de passe perdu ?" msgstr "Mot de passe perdu ?"
@ -1041,24 +1242,29 @@ msgstr "Groupes"
msgid "%(user_name)s's profile" msgid "%(user_name)s's profile"
msgstr "Profil de %(user_name)s" msgstr "Profil de %(user_name)s"
#: core/templates/core/user_detail.jinja:8 #: core/templates/core/user_detail.jinja:12
msgid "User Profile" #: core/templates/core/user_edit.jinja:11
msgstr "Profil de l'utilisateur" msgid "Profile"
msgstr "Profil"
#: core/templates/core/user_detail.jinja:13 #: core/templates/core/user_detail.jinja:17
msgid "Born: " msgid "Born: "
msgstr "Né le : " msgstr "Né le : "
#: core/templates/core/user_detail.jinja:20 #: core/templates/core/user_detail.jinja:20
msgid "Option: "
msgstr "Filière : "
#: core/templates/core/user_detail.jinja:29
#, python-format #, python-format
msgid "User is subscriber until %(subscription_end)s" msgid "User is subscriber until %(subscription_end)s"
msgstr "L'utilisateur est cotisant jusqu'au %(subscription_end)s" msgstr "L'utilisateur est cotisant jusqu'au %(subscription_end)s"
#: core/templates/core/user_detail.jinja:22 #: core/templates/core/user_detail.jinja:31
msgid "User is not subscribed. " msgid "User is not subscribed. "
msgstr "L'utilisateur n'est pas cotisant." msgstr "L'utilisateur n'est pas cotisant."
#: core/templates/core/user_detail.jinja:23 #: core/templates/core/user_detail.jinja:32
#: subscription/templates/subscription/subscription.jinja:4 #: subscription/templates/subscription/subscription.jinja:4
#: subscription/templates/subscription/subscription.jinja:8 #: subscription/templates/subscription/subscription.jinja:8
msgid "New subscription" msgid "New subscription"
@ -1068,7 +1274,35 @@ msgstr "Nouvelle cotisation"
msgid "Edit user profile" msgid "Edit user profile"
msgstr "Éditer le profil de l'utilisateur" msgstr "Éditer le profil de l'utilisateur"
#: core/templates/core/user_edit.jinja:11 #: core/templates/core/user_edit.jinja:10
msgid "Current profile: "
msgstr "Profil actuel : "
#: core/templates/core/user_edit.jinja:13
msgid "Current avatar: "
msgstr "Avatar actuel : "
#: core/templates/core/user_edit.jinja:14
msgid "Avatar"
msgstr "Avatar"
#: core/templates/core/user_edit.jinja:16
msgid "Current scrub: "
msgstr "Blouse actuelle : "
#: core/templates/core/user_edit.jinja:17
msgid "Scrub"
msgstr "Blouse"
#: core/templates/core/user_edit.jinja:21
msgid "Username: "
msgstr "Nom d'utilisateur : "
#: core/templates/core/user_edit.jinja:23
msgid "Account number: "
msgstr "Numero de compte : "
#: core/templates/core/user_edit.jinja:26
msgid "Change my password" msgid "Change my password"
msgstr "Changer mon mot de passe" msgstr "Changer mon mot de passe"
@ -1134,15 +1368,44 @@ msgstr "Comptabilité générale"
msgid "Club account: " msgid "Club account: "
msgstr "Compte club : " msgstr "Compte club : "
#: core/views/files.py:134 #: core/views/files.py:41
msgid "Add a new folder"
msgstr "Ajouter un nouveau dossier"
#: core/views/files.py:52
#, python-format
msgid "Error creating folder %(folder_name)s: %(msg)s"
msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s"
#: core/views/files.py:62 core/views/forms.py:130
#, python-format #, python-format
msgid "Error uploading file %(file_name)s: %(msg)s" msgid "Error uploading file %(file_name)s: %(msg)s"
msgstr "Erreur d'envoie du fichier %(file_name)s : %(msg)s" msgstr "Erreur d'envoie du fichier %(file_name)s : %(msg)s"
#: core/views/forms.py:58 core/views/forms.py:61 #: core/views/forms.py:46 core/views/forms.py:49
msgid "Choose file" msgid "Choose file"
msgstr "Choisir un fichier" msgstr "Choisir un fichier"
#: core/views/forms.py:88
msgid ""
"Profile: you need to be visible on the picture, in order to be recognized (e."
"g. by the barmen)"
msgstr ""
"Photo de profil: vous devez être visible sur la photo afin d'être reconnu "
"(par exemple par les barmen)"
#: core/views/forms.py:89
msgid "Avatar: used on the forum"
msgstr "Avatar : utilisé sur le forum"
#: core/views/forms.py:90
msgid "Scrub: let other know how your scrub looks like!"
msgstr "Blouse : montrez aux autres à quoi ressemble votre blouse !"
#: core/views/forms.py:120
msgid "Bad image format, only jpeg, png, and gif are accepted"
msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés"
#: counter/models.py:24 #: counter/models.py:24
msgid "account id" msgid "account id"
msgstr "numéro de compte" msgstr "numéro de compte"
@ -1379,7 +1642,7 @@ msgstr "ANN"
msgid "You have not enough money to buy all the basket" msgid "You have not enough money to buy all the basket"
msgstr "Vous n'avez pas assez d'argent pour acheter le panier" msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
#: eboutic/models.py:47 sith/settings.py:254 sith/settings_sample.py:254 #: eboutic/models.py:47 sith/settings.py:257 sith/settings_sample.py:257
msgid "Credit card" msgid "Credit card"
msgstr "Carte banquaire" msgstr "Carte banquaire"
@ -1520,12 +1783,12 @@ msgid "Washing and drying"
msgstr "Lavage et séchage" msgstr "Lavage et séchage"
#: launderette/templates/launderette/launderette_book.jinja:26 #: launderette/templates/launderette/launderette_book.jinja:26
#: sith/settings.py:342 sith/settings_sample.py:342 #: sith/settings.py:345 sith/settings_sample.py:345
msgid "Washing" msgid "Washing"
msgstr "Lavage" msgstr "Lavage"
#: launderette/templates/launderette/launderette_book.jinja:30 #: launderette/templates/launderette/launderette_book.jinja:30
#: sith/settings.py:342 sith/settings_sample.py:342 #: sith/settings.py:345 sith/settings_sample.py:345
msgid "Drying" msgid "Drying"
msgstr "Séchage" msgstr "Séchage"
@ -1580,83 +1843,83 @@ msgstr "L'utilisateur n'a pas réservé de créneau"
msgid "Token not found" msgid "Token not found"
msgstr "Jeton non trouvé" msgstr "Jeton non trouvé"
#: sith/settings.py:251 sith/settings.py:258 sith/settings.py:276 #: sith/settings.py:254 sith/settings.py:261 sith/settings.py:279
#: sith/settings_sample.py:251 sith/settings_sample.py:258 #: sith/settings_sample.py:254 sith/settings_sample.py:261
#: sith/settings_sample.py:276 #: sith/settings_sample.py:279
msgid "Check" msgid "Check"
msgstr "Chèque" msgstr "Chèque"
#: sith/settings.py:252 sith/settings.py:259 sith/settings.py:277 #: sith/settings.py:255 sith/settings.py:262 sith/settings.py:280
#: sith/settings_sample.py:252 sith/settings_sample.py:259 #: sith/settings_sample.py:255 sith/settings_sample.py:262
#: sith/settings_sample.py:277 #: sith/settings_sample.py:280
msgid "Cash" msgid "Cash"
msgstr "Espèces" msgstr "Espèces"
#: sith/settings.py:253 sith/settings_sample.py:253 #: sith/settings.py:256 sith/settings_sample.py:256
msgid "Transfert" msgid "Transfert"
msgstr "Virement" msgstr "Virement"
#: sith/settings.py:264 sith/settings_sample.py:264 #: sith/settings.py:267 sith/settings_sample.py:267
msgid "Belfort" msgid "Belfort"
msgstr "Belfort" msgstr "Belfort"
#: sith/settings.py:265 sith/settings_sample.py:265 #: sith/settings.py:268 sith/settings_sample.py:268
msgid "Sevenans" msgid "Sevenans"
msgstr "Sevenans" msgstr "Sevenans"
#: sith/settings.py:266 sith/settings_sample.py:266 #: sith/settings.py:269 sith/settings_sample.py:269
msgid "Montbéliard" msgid "Montbéliard"
msgstr "Montbéliard" msgstr "Montbéliard"
#: sith/settings.py:290 sith/settings_sample.py:290 #: sith/settings.py:293 sith/settings_sample.py:293
msgid "One semester" msgid "One semester"
msgstr "Un semestre" msgstr "Un semestre"
#: sith/settings.py:295 sith/settings_sample.py:295 #: sith/settings.py:298 sith/settings_sample.py:298
msgid "Two semesters" msgid "Two semesters"
msgstr "Deux semestres" msgstr "Deux semestres"
#: sith/settings.py:300 sith/settings_sample.py:300 #: sith/settings.py:303 sith/settings_sample.py:303
msgid "Common core cursus" msgid "Common core cursus"
msgstr "Cursus tronc commun" msgstr "Cursus tronc commun"
#: sith/settings.py:305 sith/settings_sample.py:305 #: sith/settings.py:308 sith/settings_sample.py:308
msgid "Branch cursus" msgid "Branch cursus"
msgstr "Cursus branche" msgstr "Cursus branche"
#: sith/settings.py:313 sith/settings_sample.py:313 #: sith/settings.py:316 sith/settings_sample.py:316
msgid "President" msgid "President"
msgstr "Président" msgstr "Président"
#: sith/settings.py:314 sith/settings_sample.py:314 #: sith/settings.py:317 sith/settings_sample.py:317
msgid "Vice-President" msgid "Vice-President"
msgstr "Vice-Président" msgstr "Vice-Président"
#: sith/settings.py:315 sith/settings_sample.py:315 #: sith/settings.py:318 sith/settings_sample.py:318
msgid "Treasurer" msgid "Treasurer"
msgstr "Trésorier" msgstr "Trésorier"
#: sith/settings.py:316 sith/settings_sample.py:316 #: sith/settings.py:319 sith/settings_sample.py:319
msgid "Communication supervisor" msgid "Communication supervisor"
msgstr "Responsable com" msgstr "Responsable com"
#: sith/settings.py:317 sith/settings_sample.py:317 #: sith/settings.py:320 sith/settings_sample.py:320
msgid "Secretary" msgid "Secretary"
msgstr "Secrétaire" msgstr "Secrétaire"
#: sith/settings.py:318 sith/settings_sample.py:318 #: sith/settings.py:321 sith/settings_sample.py:321
msgid "IT supervisor" msgid "IT supervisor"
msgstr "Responsable info" msgstr "Responsable info"
#: sith/settings.py:319 sith/settings_sample.py:319 #: sith/settings.py:322 sith/settings_sample.py:322
msgid "Board member" msgid "Board member"
msgstr "Membre du bureau" msgstr "Membre du bureau"
#: sith/settings.py:320 sith/settings_sample.py:320 #: sith/settings.py:323 sith/settings_sample.py:323
msgid "Active member" msgid "Active member"
msgstr "Membre actif" msgstr "Membre actif"
#: sith/settings.py:321 sith/settings_sample.py:321 #: sith/settings.py:324 sith/settings_sample.py:324
msgid "Curious" msgid "Curious"
msgstr "Curieux" msgstr "Curieux"
@ -1696,3 +1959,6 @@ msgstr "Un utilisateur avec cette adresse email existe déjà"
msgid "You must either choose an existing user or create a new one properly" msgid "You must either choose an existing user or create a new one properly"
msgstr "" msgstr ""
"Vous devez soit choisir un utilisateur existant, ou en créer un proprement." "Vous devez soit choisir un utilisateur existant, ou en créer un proprement."
#~ msgid "User Profile"
#~ msgstr "Profil de l'utilisateur"

View File

@ -214,6 +214,9 @@ SITH_LAUNDERETTE_MANAGER = {
# (month, day) # (month, day)
SITH_START_DATE = (8, 15) # 15th August SITH_START_DATE = (8, 15) # 15th August
# Used to determine the valid promos
SITH_SCHOOL_START_YEAR = 1999
SITH_GROUPS = { SITH_GROUPS = {
'root': { 'root': {
'id': 1, 'id': 1,