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 %}
<td>{{ o.remark }}</td>
{% 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 %}
<td>-</td>
{% endif %}

View File

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

View File

@ -38,6 +38,7 @@ class Command(BaseCommand):
is_superuser=True, is_staff=True)
root.set_password("plop")
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.save()
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.conf import settings
from django.db import transaction
from datetime import datetime, timedelta
from datetime import datetime, timedelta, date
import unicodedata
@ -46,6 +46,15 @@ class RealGroup(Group):
class Meta:
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):
"""
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)
email = models.EmailField(_('email address'), unique=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(
_('staff status'),
default=False,
@ -101,6 +110,51 @@ class User(AbstractBaseUser):
)
groups = models.ManyToManyField(RealGroup, related_name='users', 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()
@ -341,6 +395,15 @@ class SithFile(models.Model):
def is_owned_by(self, user):
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):
for c in self.children.all():
c.delete()
@ -422,6 +485,9 @@ class SithFile(models.Model):
def get_display_name(self):
return self.name
def get_download_url(self):
return reverse('core:download', kwargs={'file_id': self.id})
class LockError(Exception):
"""There was a lock error on the object"""
pass

View File

@ -2,6 +2,11 @@
Super Form Reset
----------------------------------------------------------------------------------------------------*/
form {
margin: 0px auto;
width: 60%;
}
input,
label,
select,
@ -22,6 +27,10 @@ textarea
font-family: Arial;
}
label {
min-width: 50%;
}
/* Remove the stupid outer glow in Webkit */
input:focus
{
@ -70,7 +79,8 @@ input[type=tel],
input[type=text],
input[type=time],
input[type=url],
input[type=week]
input[type=week],
textarea
{
background-color: white;
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');
$( function() {
dialog = $( ".choose_file_widget" ).dialog({
buttons = $(".choose_file_button");
popups = $(".choose_file_widget");
popups.dialog({
autoOpen: false,
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() {
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 {
width: 100%;
font-size: 0.90em;
}
td {
padding: 4px;
border: solid 1px black;
border-collapse: collapse;
vertical-align: top;
overflow: hidden;
text-overflow: ellipsis;
max-width: 0;
}
td>ul {
margin-top: 0px;
@ -152,7 +156,27 @@ tbody>tr:hover {
}
/*-----------------------------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_content {

View File

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

View File

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

View File

@ -42,8 +42,18 @@
{% 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>
{% 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 %}

View File

@ -21,7 +21,9 @@
<form method="post" action="{{ url('core:login') }}">
{% 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 }}">
<p><input type="submit" value="{% trans %}login{% endtrans %}"></p>
</form>

View File

@ -5,12 +5,26 @@
{% endblock %}
{% 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>
<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>{{ 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>
{% 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>
<form action="" method="post">
<form action="" method="post" enctype="multipart/form-data">
{% 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>
</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 %}
<p><a href="{{ url('core:password_change') }}">{% trans %}Change my password{% endtrans %}</a></p>
{% endif %}
</form>
{% 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>
<form action="" method="post">
{% csrf_token %}

View File

@ -8,8 +8,11 @@ from django.contrib.auth.forms import AuthenticationForm
from core.models import Group
def forbidden(request):
try:
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form':
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):
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
return response
class AddFileForm(forms.Form):
class AddFilesForm(forms.Form):
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"),
required=False)
@ -128,7 +128,7 @@ class FileView(CanViewMixin, DetailView, FormMixin):
pk_url_kwarg = "file_id"
template_name = 'core/file_detail.jinja'
context_object_name = "file"
form_class = AddFileForm
form_class = AddFilesForm
def get(self, request, *args, **kwargs):
self.form = self.get_form()

View File

@ -1,11 +1,56 @@
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm
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.forms import CheckboxSelectMultiple, Select
from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput
from django.utils.translation import ugettext as _
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):
error_css_class = 'error'
@ -22,6 +67,69 @@ class RegisteringForm(UserCreationForm):
user.save()
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):
error_css_class = 'error'
@ -52,13 +160,3 @@ class PagePropForm(forms.ModelForm):
self.fields['edit_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
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
def login(request):
@ -115,7 +115,31 @@ class UserUpdateProfileView(CanEditMixin, UpdateView):
model = User
pk_url_kwarg = "user_id"
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):
"""

Binary file not shown.

View File

@ -6,7 +6,7 @@
msgid ""
msgstr ""
"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"
"Last-Translator: Skia <skia@libskia.so>\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"
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
msgid "start date"
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"
msgstr "date de fin"
@ -66,8 +66,9 @@ msgstr "montant effectif"
msgid "number"
msgstr "numéro"
#: accounting/models.py:154 core/models.py:560 counter/models.py:209
#: counter/models.py:244 eboutic/models.py:13 eboutic/models.py:46
#: accounting/models.py:154 core/models.py:390 core/models.py:666
#: counter/models.py:209 counter/models.py:244 eboutic/models.py:13
#: eboutic/models.py:46
msgid "date"
msgstr "date"
@ -121,7 +122,7 @@ msgstr "Compte"
msgid "Company"
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"
msgstr "Autre"
@ -205,7 +206,7 @@ msgstr "Nouveau compte club"
#: accounting/templates/accounting/bank_account_list.jinja:15
#: accounting/templates/accounting/club_account_details.jinja:44
#: 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/user_tools.jinja:37
#: 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_list.jinja:16
#: core/templates/core/file_detail.jinja:38
#: core/templates/core/file_detail.jinja:43
#: core/templates/core/group_list.jinja:13
#: launderette/templates/launderette/launderette_admin.jinja:16
#: launderette/views.py:146
@ -296,7 +297,7 @@ msgid "No"
msgstr "Non"
#: 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"
msgstr "Voir"
@ -381,37 +382,45 @@ msgstr "Un club avec ce nom UNIX existe déjà."
msgid "address"
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"
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
msgid "user"
msgstr "nom d'utilisateur"
#: club/models.py:111
#: club/models.py:146
msgid "club"
msgstr "club"
#: club/models.py:114
#: club/models.py:149 core/models.py:127
msgid "role"
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
msgid "description"
msgstr "description"
#: club/models.py:121
#: club/models.py:156
msgid "User must be subscriber to take part to a 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"
msgstr "L'utilisateur est déjà membre de ce club"
#: club/models.py:127
#: club/models.py:162
msgid "past member"
msgstr "Anciens membres"
@ -420,7 +429,7 @@ msgstr "Anciens membres"
msgid "Back to list"
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
msgid "Prop"
msgstr "Propriétés"
@ -435,7 +444,7 @@ msgstr "Éditer le club"
#: club/templates/club/club_edit.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/pagerev_edit.jinja:24
#: 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"
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"
msgstr "Ajouter"
@ -476,25 +486,30 @@ msgstr "Outils club"
msgid "Counters:"
msgstr "Comptoirs : "
#: core/models.py:23
#: core/models.py:24
msgid "meta group status"
msgstr "status du meta-groupe"
#: core/models.py:25
#: core/models.py:26
msgid "Whether a group is a meta group or not"
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"
msgstr "nom d'utilisateur"
#: core/models.py:63
#: core/models.py:73
msgid "Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only."
msgstr ""
"Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et @/./"
"+/-/_"
#: core/models.py:67
#: core/models.py:77
msgid ""
"Enter a valid username. This value may contain only letters, numbers and @/./"
"+/-/_ characters."
@ -502,39 +517,43 @@ msgstr ""
"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."
msgstr "Un utilisateur de ce nom existe déjà"
#: core/models.py:75
#: core/models.py:85
msgid "first name"
msgstr "Prénom"
#: core/models.py:76
#: core/models.py:86
msgid "last name"
msgstr "Nom"
#: core/models.py:77
#: core/models.py:87
msgid "email address"
msgstr "adresse email"
#: core/models.py:78
#: core/models.py:88
msgid "date of birth"
msgstr "date de naissance"
#: core/models.py:81
#: core/models.py:89
msgid "nick name"
msgstr "surnom"
#: core/models.py:91
msgid "staff status"
msgstr "status \"staff\""
#: core/models.py:83
#: core/models.py:93
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."
#: core/models.py:86
#: core/models.py:96
msgid "active"
msgstr "actif"
#: core/models.py:89
#: core/models.py:99
msgid ""
"Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts."
@ -542,121 +561,293 @@ msgstr ""
"Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au "
"lieu de supprimer les comptes."
#: core/models.py:93
#: core/models.py:103
msgid "date joined"
msgstr "date d'inscription"
#: core/models.py:95
#: core/models.py:105
msgid "superuser"
msgstr "super-utilisateur"
#: core/models.py:98
#: core/models.py:108
msgid "Designates whether this user is a superuser. "
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"
msgstr "Visiteur"
#: core/models.py:285
#: core/models.py:372
msgid "define if we show a users stats"
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"
msgstr "Montrez vos statistiques de compte aux autres"
#: core/models.py:294
#: core/models.py:381
msgid "file name"
msgstr "nom du fichier"
#: core/models.py:295 core/models.py:409
#: core/models.py:382 core/models.py:515
msgid "parent"
msgstr "parent"
#: core/models.py:296 core/models.py:305
#: core/models.py:383 core/models.py:393
msgid "file"
msgstr "fichier"
#: core/models.py:297
#: core/models.py:384
msgid "owner"
msgstr "propriétaire"
#: core/models.py:298 core/models.py:415
#: core/models.py:385 core/models.py:521
msgid "edit group"
msgstr "groupe d'édition"
#: core/models.py:299 core/models.py:416
#: core/models.py:386 core/models.py:522
msgid "view group"
msgstr "groupe de vue"
#: core/models.py:300
#: core/models.py:387
msgid "is folder"
msgstr "est un dossier"
#: core/models.py:301
#: core/models.py:388
msgid "mime type"
msgstr "type mime"
#: core/models.py:302
#: core/models.py:389
msgid "size"
msgstr "taille"
#: core/models.py:316
#: core/models.py:419
msgid "Character '/' not authorized in name"
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"
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"
msgstr ""
"Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas "
"un dossier"
#: core/models.py:332
#: core/models.py:435
msgid "Duplicate file"
msgstr "Un fichier de ce nom existe déjà"
#: core/models.py:342
#: core/models.py:445
msgid "You must provide a file"
msgstr "Vous devez fournir un fichier"
#: core/models.py:367
#: core/models.py:470
msgid "Folder: "
msgstr "Dossier : "
#: core/models.py:369
#: core/models.py:472
msgid "File: "
msgstr "Fichier : "
#: core/models.py:408 core/models.py:412
#: core/models.py:514 core/models.py:518
msgid "page name"
msgstr "nom de la page"
#: core/models.py:413
#: core/models.py:519
msgid "owner group"
msgstr "groupe propriétaire"
#: core/models.py:444
#: core/models.py:550
msgid "Duplicate page"
msgstr "Une page de ce nom existe déjà"
#: core/models.py:450
#: core/models.py:556
msgid "Loop in page tree"
msgstr "Boucle dans l'arborescence des pages"
#: core/models.py:557
#: core/models.py:663
msgid "revision"
msgstr "révision"
#: core/models.py:558
#: core/models.py:664
msgid "page title"
msgstr "titre de la page"
#: core/models.py:559
#: core/models.py:665
msgid "page content"
msgstr "contenu de la page"
@ -672,48 +863,48 @@ msgstr "404. Non trouvé"
msgid "Welcome!"
msgstr "Bienvenue!"
#: core/templates/core/base.jinja:17
#: core/templates/core/base.jinja:18
msgid "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
msgid "Login"
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"
msgstr "S'enregister"
#: core/templates/core/base.jinja:24
#: core/templates/core/base.jinja:25
msgid "Tools"
msgstr "Outils"
#: core/templates/core/base.jinja:25
#: core/templates/core/base.jinja:26
msgid "Logout"
msgstr "Déconnexion"
#: core/templates/core/base.jinja:31
#: core/templates/core/base.jinja:36
msgid "Users"
msgstr "Utilisateurs"
#: core/templates/core/base.jinja:32
#: core/templates/core/base.jinja:37
msgid "Wiki"
msgstr "Wiki"
#: core/templates/core/base.jinja:33
#: core/templates/core/base.jinja:38
msgid "Pages"
msgstr "Pages"
#: core/templates/core/base.jinja:34
#: core/templates/core/base.jinja:39
msgid "Clubs"
msgstr "Clubs"
#: core/templates/core/base.jinja:35
#: core/templates/core/base.jinja:40
msgid "Services"
msgstr "Services"
#: core/templates/core/base.jinja:49
#: core/templates/core/base.jinja:55
msgid "Site made by good people"
msgstr "Site réalisé par des gens biens"
@ -723,24 +914,29 @@ msgid "Create %(name)s"
msgstr "Créer %(name)s"
#: core/templates/core/delete_confirm.jinja:4
#: core/templates/core/file_delete_confirm.jinja:4
msgid "Delete confirmation"
msgstr "Confirmation de suppression"
#: core/templates/core/delete_confirm.jinja:6
#: core/templates/core/file_delete_confirm.jinja:6
#, python-format
msgid "Are you sure you want to delete \"%(obj)s\"?"
msgstr "Êtes-vous sûr de vouloir supprimer \"%(obj)s\" ?"
#: core/templates/core/delete_confirm.jinja:7
#: core/templates/core/file_delete_confirm.jinja:7
msgid "Confirm"
msgstr "Confirmation"
#: core/templates/core/delete_confirm.jinja:8
#: core/templates/core/file_delete_confirm.jinja:8
#: counter/templates/counter/counter_click.jinja:71
msgid "Cancel"
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
msgid "Edit %(obj)s"
msgstr "Éditer %(obj)s"
@ -757,35 +953,39 @@ msgstr "Nouveau fichier"
msgid "Not found"
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"
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: "
msgstr "Propriétaire : "
#: core/templates/core/file_detail.jinja:20
msgid "Upload"
msgstr "Téléverser"
#: core/templates/core/file_detail.jinja:34
msgid "Real name: "
msgstr "Nom réel : "
#: core/templates/core/file_detail.jinja:35
msgid "Date: "
msgstr "Date : "
#: core/templates/core/file_detail.jinja:37
msgid "Type: "
msgstr "Type : "
#: core/templates/core/file_detail.jinja:36
#: core/templates/core/file_detail.jinja:38
msgid "Size: "
msgstr "Taille : "
#: core/templates/core/file_detail.jinja:36
#: core/templates/core/file_detail.jinja:38
msgid "bytes"
msgstr "octets"
#: core/templates/core/file_detail.jinja:37
#: core/templates/core/file_detail.jinja:40
msgid "Download"
msgstr "Télécharger"
@ -797,7 +997,8 @@ msgstr "Il n'y a pas de fichier sur ce site web."
msgid "Edit group"
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
msgid "Update"
msgstr "Mettre à jour"
@ -833,12 +1034,12 @@ msgstr ""
msgid "Please login to see this 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
msgid "login"
msgstr "login"
#: core/templates/core/login.jinja:30
#: core/templates/core/login.jinja:32
msgid "Lost password?"
msgstr "Mot de passe perdu ?"
@ -1041,24 +1242,29 @@ msgstr "Groupes"
msgid "%(user_name)s's profile"
msgstr "Profil de %(user_name)s"
#: core/templates/core/user_detail.jinja:8
msgid "User Profile"
msgstr "Profil de l'utilisateur"
#: core/templates/core/user_detail.jinja:12
#: core/templates/core/user_edit.jinja:11
msgid "Profile"
msgstr "Profil"
#: core/templates/core/user_detail.jinja:13
#: core/templates/core/user_detail.jinja:17
msgid "Born: "
msgstr "Né le : "
#: core/templates/core/user_detail.jinja:20
msgid "Option: "
msgstr "Filière : "
#: core/templates/core/user_detail.jinja:29
#, python-format
msgid "User is subscriber until %(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. "
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:8
msgid "New subscription"
@ -1068,7 +1274,35 @@ msgstr "Nouvelle cotisation"
msgid "Edit user profile"
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"
msgstr "Changer mon mot de passe"
@ -1134,15 +1368,44 @@ msgstr "Comptabilité générale"
msgid "Club account: "
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
msgid "Error uploading file %(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"
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
msgid "account id"
msgstr "numéro de compte"
@ -1379,7 +1642,7 @@ msgstr "ANN"
msgid "You have not enough money to buy all the basket"
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"
msgstr "Carte banquaire"
@ -1520,12 +1783,12 @@ msgid "Washing and drying"
msgstr "Lavage et séchage"
#: 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"
msgstr "Lavage"
#: 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"
msgstr "Séchage"
@ -1580,83 +1843,83 @@ msgstr "L'utilisateur n'a pas réservé de créneau"
msgid "Token not found"
msgstr "Jeton non trouvé"
#: sith/settings.py:251 sith/settings.py:258 sith/settings.py:276
#: sith/settings_sample.py:251 sith/settings_sample.py:258
#: sith/settings_sample.py:276
#: sith/settings.py:254 sith/settings.py:261 sith/settings.py:279
#: sith/settings_sample.py:254 sith/settings_sample.py:261
#: sith/settings_sample.py:279
msgid "Check"
msgstr "Chèque"
#: sith/settings.py:252 sith/settings.py:259 sith/settings.py:277
#: sith/settings_sample.py:252 sith/settings_sample.py:259
#: sith/settings_sample.py:277
#: sith/settings.py:255 sith/settings.py:262 sith/settings.py:280
#: sith/settings_sample.py:255 sith/settings_sample.py:262
#: sith/settings_sample.py:280
msgid "Cash"
msgstr "Espèces"
#: sith/settings.py:253 sith/settings_sample.py:253
#: sith/settings.py:256 sith/settings_sample.py:256
msgid "Transfert"
msgstr "Virement"
#: sith/settings.py:264 sith/settings_sample.py:264
#: sith/settings.py:267 sith/settings_sample.py:267
msgid "Belfort"
msgstr "Belfort"
#: sith/settings.py:265 sith/settings_sample.py:265
#: sith/settings.py:268 sith/settings_sample.py:268
msgid "Sevenans"
msgstr "Sevenans"
#: sith/settings.py:266 sith/settings_sample.py:266
#: sith/settings.py:269 sith/settings_sample.py:269
msgid "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"
msgstr "Un semestre"
#: sith/settings.py:295 sith/settings_sample.py:295
#: sith/settings.py:298 sith/settings_sample.py:298
msgid "Two semesters"
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"
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"
msgstr "Cursus branche"
#: sith/settings.py:313 sith/settings_sample.py:313
#: sith/settings.py:316 sith/settings_sample.py:316
msgid "President"
msgstr "Président"
#: sith/settings.py:314 sith/settings_sample.py:314
#: sith/settings.py:317 sith/settings_sample.py:317
msgid "Vice-President"
msgstr "Vice-Président"
#: sith/settings.py:315 sith/settings_sample.py:315
#: sith/settings.py:318 sith/settings_sample.py:318
msgid "Treasurer"
msgstr "Trésorier"
#: sith/settings.py:316 sith/settings_sample.py:316
#: sith/settings.py:319 sith/settings_sample.py:319
msgid "Communication supervisor"
msgstr "Responsable com"
#: sith/settings.py:317 sith/settings_sample.py:317
#: sith/settings.py:320 sith/settings_sample.py:320
msgid "Secretary"
msgstr "Secrétaire"
#: sith/settings.py:318 sith/settings_sample.py:318
#: sith/settings.py:321 sith/settings_sample.py:321
msgid "IT supervisor"
msgstr "Responsable info"
#: sith/settings.py:319 sith/settings_sample.py:319
#: sith/settings.py:322 sith/settings_sample.py:322
msgid "Board member"
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"
msgstr "Membre actif"
#: sith/settings.py:321 sith/settings_sample.py:321
#: sith/settings.py:324 sith/settings_sample.py:324
msgid "Curious"
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"
msgstr ""
"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)
SITH_START_DATE = (8, 15) # 15th August
# Used to determine the valid promos
SITH_SCHOOL_START_YEAR = 1999
SITH_GROUPS = {
'root': {
'id': 1,