Finish profile of users

This commit is contained in:
Skia 2016-08-13 05:33:09 +02:00
parent 5113d8fda5
commit c0a66f9a38
9 changed files with 208 additions and 31 deletions

View File

@ -32,7 +32,7 @@ class Command(BaseCommand):
for g in settings.SITH_GROUPS.values():
Group(id=g['id'], name=g['name']).save()
self.reset_index("core", "auth")
root = User(username='root', last_name="", first_name="Bibou",
root = User(id=0, username='root', last_name="", first_name="Bibou",
email="ae.info@utbm.fr",
date_of_birth="1942-06-12",
is_superuser=True, is_staff=True)
@ -76,6 +76,19 @@ class Command(BaseCommand):
p.save()
PageRev(page=p, title="Wiki index", author=root, content="""
Welcome to the wiki page!
""").save()
p = Page(name="services")
p.set_lock(root)
p.save()
p.view_groups=[settings.SITH_GROUPS['public']['id']]
p.set_lock(root)
PageRev(page=p, title="Services", author=root, content="""
| | | |
| :---: | :---: | :---: | :---: |
| [Eboutic](/eboutic) | [Laverie](/launderette) | Matmat | [Fichiers](/file) |
| SAS | Weekmail | Forum | |
""").save()
p = Page(name="launderette")

View File

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import phonenumber_field.modelfields
from django.utils.timezone import utc
import datetime
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0006_auto_20160811_0450'),
]
operations = [
migrations.AddField(
model_name='user',
name='address',
field=models.CharField(default='', verbose_name='address', max_length=128, blank=True),
),
migrations.AddField(
model_name='user',
name='last_update',
field=models.DateField(default=datetime.datetime(2016, 8, 13, 3, 22, 21, 699918, tzinfo=utc), verbose_name='last update', auto_now=True),
preserve_default=False,
),
migrations.AddField(
model_name='user',
name='parent_address',
field=models.CharField(default='', verbose_name='parent address', max_length=128, blank=True),
),
migrations.AddField(
model_name='user',
name='parent_phone',
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, verbose_name='parent phone', max_length=128, null=True),
),
migrations.AddField(
model_name='user',
name='phone',
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, verbose_name='phone', max_length=128, null=True),
),
migrations.AddField(
model_name='user',
name='second_email',
field=models.EmailField(blank=True, verbose_name='second email address', max_length=254, null=True),
),
migrations.AlterField(
model_name='user',
name='avatar_pict',
field=models.OneToOneField(verbose_name='avatar', on_delete=django.db.models.deletion.SET_NULL, related_name='avatar_of', blank=True, to='core.SithFile', null=True),
),
migrations.AlterField(
model_name='user',
name='department',
field=models.CharField(default='NA', verbose_name='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'), ('HUMA', 'Humanities'), ('NA', 'N/A')], blank=True),
),
migrations.AlterField(
model_name='user',
name='dpt_option',
field=models.CharField(default='', verbose_name='dpt option', max_length=32, blank=True),
),
migrations.AlterField(
model_name='user',
name='first_name',
field=models.CharField(verbose_name='first name', max_length=64),
),
migrations.AlterField(
model_name='user',
name='forum_signature',
field=models.TextField(default='', verbose_name='forum signature', max_length=256, blank=True),
),
migrations.AlterField(
model_name='user',
name='last_name',
field=models.CharField(verbose_name='last name', max_length=64),
),
migrations.AlterField(
model_name='user',
name='nick_name',
field=models.CharField(blank=True, verbose_name='nick name', max_length=64, null=True),
),
migrations.AlterField(
model_name='user',
name='profile_pict',
field=models.OneToOneField(verbose_name='profile', on_delete=django.db.models.deletion.SET_NULL, related_name='profile_of', blank=True, to='core.SithFile', null=True),
),
migrations.AlterField(
model_name='user',
name='quote',
field=models.CharField(default='', verbose_name='quote', max_length=256, blank=True),
),
migrations.AlterField(
model_name='user',
name='role',
field=models.CharField(default='', verbose_name='role', max_length=15, choices=[('STUDENT', 'Student'), ('ADMINISTRATIVE', 'Administrative agent'), ('TEACHER', 'Teacher'), ('AGENT', 'Agent'), ('DOCTOR', 'Doctor'), ('FORMER STUDENT', 'Former student'), ('SERVICE', 'Service')], blank=True),
),
migrations.AlterField(
model_name='user',
name='school',
field=models.CharField(default='', verbose_name='school', max_length=80, blank=True),
),
migrations.AlterField(
model_name='user',
name='scrub_pict',
field=models.OneToOneField(verbose_name='scrub', on_delete=django.db.models.deletion.SET_NULL, related_name='scrub_of', blank=True, to='core.SithFile', null=True),
),
migrations.AlterField(
model_name='user',
name='semester',
field=models.CharField(default='', verbose_name='semester', max_length=5, blank=True),
),
migrations.AlterField(
model_name='user',
name='tshirt_size',
field=models.CharField(default='-', verbose_name='tshirt size', max_length=5, choices=[('-', '-'), ('XS', 'XS'), ('S', 'S'), ('M', 'M'), ('L', 'L'), ('XL', 'XL'), ('XXL', 'XXL'), ('XXXL', 'XXXL')]),
),
]

View File

@ -7,6 +7,8 @@ from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.conf import settings
from django.db import transaction
from phonenumber_field.modelfields import PhoneNumberField
from datetime import datetime, timedelta, date
import unicodedata
@ -82,11 +84,11 @@ class User(AbstractBaseUser):
'unique': _("A user with that username already exists."),
},
)
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=30)
first_name = models.CharField(_('first name'), max_length=64)
last_name = models.CharField(_('last name'), max_length=64)
email = models.EmailField(_('email address'), unique=True)
date_of_birth = models.DateField(_('date of birth'), blank=True, null=True)
nick_name = models.CharField(_('nick name'), max_length=30, blank=True)
nick_name = models.CharField(_('nick name'), max_length=64, null=True, blank=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
@ -101,6 +103,7 @@ class User(AbstractBaseUser):
),
)
date_joined = models.DateField(_('date joined'), auto_now_add=True)
last_update = models.DateField(_('last update'), auto_now=True)
is_superuser = models.BooleanField(
_('superuser'),
default=False,
@ -110,9 +113,12 @@ 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)
profile_pict = models.OneToOneField('SithFile', related_name='profile_of', verbose_name=_("profile"), null=True,
blank=True, on_delete=models.SET_NULL)
avatar_pict = models.OneToOneField('SithFile', related_name='avatar_of', verbose_name=_("avatar"), null=True,
blank=True, on_delete=models.SET_NULL)
scrub_pict = models.OneToOneField('SithFile', related_name='scrub_of', verbose_name=_("scrub"), null=True,
blank=True, on_delete=models.SET_NULL)
sex = models.CharField(_("sex"), max_length=10, choices=[("MAN", _("Man")), ("WOMAN", _("Woman"))], default="MAN")
tshirt_size = models.CharField(_("tshirt size"), max_length=5, choices=[
("-", _("-")),
@ -123,7 +129,7 @@ class User(AbstractBaseUser):
("XL", _("XL")),
("XXL", _("XXL")),
("XXXL", _("XXXL")),
], default="M")
], default="-")
role = models.CharField(_("role"), max_length=15, choices=[
("STUDENT", _("Student")),
("ADMINISTRATIVE", _("Administrative agent")),
@ -132,7 +138,7 @@ class User(AbstractBaseUser):
("DOCTOR", _("Doctor")),
("FORMER STUDENT", _("Former student")),
("SERVICE", _("Service")),
], default="STUDENT")
], blank=True, default="")
department = models.CharField(_("department"), max_length=15, choices=[
("TC", _("TC")),
("IMSI", _("IMSI")),
@ -145,16 +151,20 @@ class User(AbstractBaseUser):
("GMC", _("GMC")),
("MC", _("MC")),
("EDIM", _("EDIM")),
("HUMAN", _("Humanities")),
("HUMA", _("Humanities")),
("NA", _("N/A")),
], default="NA")
dpt_option = models.CharField(_("dpt option"), max_length=32, null=True, blank=True)
semester = models.CharField(_("semester"), max_length=5, null=True, blank=True)
quote = models.CharField(_("quote"), max_length=64, null=True, blank=True)
school = models.CharField(_("school"), max_length=32, null=True, blank=True)
], default="NA", blank=True)
dpt_option = models.CharField(_("dpt option"), max_length=32, blank=True, default="")
semester = models.CharField(_("semester"), max_length=5, blank=True, default="")
quote = models.CharField(_("quote"), max_length=256, blank=True, default="")
school = models.CharField(_("school"), max_length=80, blank=True, default="")
promo = models.IntegerField(_("promo"), validators=[validate_promo], null=True, blank=True)
forum_signature = models.TextField(_("forum signature"), max_length=256, null=True, blank=True)
# TODO: add phone numbers with https://github.com/stefanfoulis/django-phonenumber-field
forum_signature = models.TextField(_("forum signature"), max_length=256, blank=True, default="")
second_email = models.EmailField(_('second email address'), null=True, blank=True)
phone = PhoneNumberField(_("phone"), null=True, blank=True)
parent_phone = PhoneNumberField(_("parent phone"), null=True, blank=True)
address = models.CharField(_("address"), max_length=128, blank=True, default="")
parent_address = models.CharField(_("parent address"), max_length=128, blank=True, default="")
objects = UserManager()
@ -217,7 +227,7 @@ class User(AbstractBaseUser):
with transaction.atomic():
if self.id:
old = User.objects.filter(id=self.id).first()
if old.username != self.username:
if old and old.username != self.username:
self._change_username(self.username)
super(User, self).save(*args, **kwargs)
@ -263,8 +273,8 @@ class User(AbstractBaseUser):
Returns the display name of the user.
A nickname if possible, otherwise, the full name
"""
if self.nick_name != "":
return self.nick_name
if self.nick_name:
return "%s (%s)" % (self.get_full_name(), self.nick_name)
return self.get_full_name()
def email_user(self, subject, message, from_email=None, **kwargs):
@ -463,7 +473,7 @@ class SithFile(models.Model):
if attr == "is_file":
return not self.is_folder
else:
return object.__getattribute__(self, attr)
return super(SithFile, self).__getattribute__(attr)
def __str__(self):
if self.is_folder:

View File

@ -60,6 +60,7 @@ nav a:hover {
margin: 0px auto;
padding: 1em 1%;
background: white;
overflow: auto;
}
h1, h2, h3, h4, h5, h6 {

View File

@ -37,7 +37,7 @@
<a href="{{ url('core:page', page_name="Index") }}">{% trans %}Wiki{% endtrans %}</a>
<a href="{{ url('core:page_list') }}">{% trans %}Pages{% endtrans %}</a>
<a href="{{ url('club:club_list') }}">{% trans %}Clubs{% endtrans %}</a>
<a href="{{ url('core:page', "Services") }}">{% trans %}Services{% endtrans %}</a>
<a href="{{ url('core:page', "services") }}">{% trans %}Services{% endtrans %}</a>
</nav>
{% endif %}
{% endblock %}

View File

@ -2,6 +2,7 @@
{% block content %}
<div class="tool-bar">
<div>{{ profile.get_display_name() }}</div>
<div class="tools">
<a href="{{ url('core:user_profile', user_id=profile.id) }}">{% trans %}Infos{% endtrans %}</a>
{% if can_edit(profile, request.user) or user.id == profile.id %}
@ -16,7 +17,6 @@
<a href="{{ url('core:user_account', user_id=profile.id) }}">{% trans %}Account{% endtrans %}</a>
{% endif %}
</div>
<h5>{{ profile.get_display_name() }}</h5>
</div>
<hr>

View File

@ -1,5 +1,9 @@
{% extends "core/user_base.jinja" %}
{% block title %}
{% trans %}Edit user{% endtrans %}
{% endblock %}
{% block infos %}
<h2>{% trans %}Edit user profile{% endtrans %}</h2>
<form action="" method="post" enctype="multipart/form-data">

View File

@ -5,10 +5,13 @@ from django.core.exceptions import ValidationError
from django.contrib.auth import logout, login, authenticate
from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput
from django.utils.translation import ugettext as _
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
import logging
from core.models import User, Page, RealGroup, SithFile
# Widgets
class SelectSingle(Select):
@ -67,6 +70,26 @@ class RegisteringForm(UserCreationForm):
user.save()
return user
# Image utils
from io import BytesIO
from PIL import Image
def scale_dimension(width, height, long_edge):
if width > height:
ratio = long_edge * 1. / width
else:
ratio = long_edge * 1. / height
return int(width * ratio), int(height * ratio)
def resize_image(im, edge, format):
from django.core.files.base import ContentFile
(w, h) = im.size
(width, height) = scale_dimension(w, h, long_edge=edge)
content = BytesIO()
im.resize((width, height), Image.ANTIALIAS).save(fp=content, format=format, dpi=[72, 72])
return ContentFile(content.getvalue())
class UserProfileForm(forms.ModelForm):
"""
Form handling the user profile, managing the files
@ -76,13 +99,16 @@ class UserProfileForm(forms.ModelForm):
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']
'scrub_pict', 'sex', 'second_email', 'address', 'parent_address', 'phone', 'parent_phone',
'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,
'phone': PhoneNumberInternationalFallbackWidget,
'parent_phone': PhoneNumberInternationalFallbackWidget,
}
labels = {
'profile_pict': _("Profile: you need to be visible on the picture, in order to be recognized (e.g. by the barmen)"),
@ -111,13 +137,12 @@ class UserProfileForm(forms.ModelForm):
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"))
im = Image.open(BytesIO(f.read()))
new_file = SithFile(parent=parent, name=self.generate_name(field, f),
file=resize_image(im, 400, f.content_type.split('/')[-1]),
owner=self.instance, is_folder=False, mime_type=f.content_type, size=f._size)
new_file.file.name = new_file.name
old = SithFile.objects.filter(parent=parent, name=new_file.name).first()
if old:
old.delete()
@ -129,6 +154,10 @@ class UserProfileForm(forms.ModelForm):
self._errors.pop(field, None)
self.add_error(field, _("Error uploading file %(file_name)s: %(msg)s") %
{'file_name': f, 'msg': str(e.message)})
except IOError:
self._errors.pop(field, None)
self.add_error(field, _("Error uploading file %(file_name)s: %(msg)s") %
{'file_name': f, 'msg': _("Bad image format, only jpeg, png, and gif are accepted")})
self._post_clean()
class UserPropForm(forms.ModelForm):

View File

@ -6,3 +6,4 @@ django-jinja
pyopenssl
pytz
djangorestframework
django-phonenumber-field