mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-26 02:54:20 +00:00
Finish profile of users
This commit is contained in:
parent
5113d8fda5
commit
c0a66f9a38
@ -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")
|
||||
|
119
core/migrations/0007_auto_20160813_0522.py
Normal file
119
core/migrations/0007_auto_20160813_0522.py
Normal 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')]),
|
||||
),
|
||||
]
|
@ -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:
|
||||
|
@ -60,6 +60,7 @@ nav a:hover {
|
||||
margin: 0px auto;
|
||||
padding: 1em 1%;
|
||||
background: white;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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):
|
||||
|
@ -6,3 +6,4 @@ django-jinja
|
||||
pyopenssl
|
||||
pytz
|
||||
djangorestframework
|
||||
django-phonenumber-field
|
||||
|
Loading…
Reference in New Issue
Block a user