2017-04-24 15:51:12 +00:00
|
|
|
# -*- coding:utf-8 -*
|
|
|
|
#
|
|
|
|
# Copyright 2016,2017
|
|
|
|
# - Skia <skia@libskia.so>
|
|
|
|
#
|
|
|
|
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
|
|
|
# http://ae.utbm.fr.
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU General Public License a published by the Free Software
|
|
|
|
# Foundation; either version 3 of the License, or (at your option) any later
|
|
|
|
# version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
# details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
|
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
|
2015-11-24 13:01:10 +00:00
|
|
|
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UserChangeForm
|
2015-11-18 16:09:06 +00:00
|
|
|
from django import forms
|
2016-08-11 02:24:32 +00:00
|
|
|
from django.db import transaction
|
|
|
|
from django.core.exceptions import ValidationError
|
2015-11-18 16:09:06 +00:00
|
|
|
from django.contrib.auth import logout, login, authenticate
|
2017-06-10 17:39:40 +00:00
|
|
|
from django.forms import CheckboxSelectMultiple, Select, DateInput, TextInput, DateTimeInput, Textarea
|
2017-03-27 12:31:58 +00:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2017-03-27 20:47:24 +00:00
|
|
|
from django.utils.translation import ugettext
|
2016-08-13 03:33:09 +00:00
|
|
|
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
|
2016-09-19 18:29:43 +00:00
|
|
|
from ajax_select.fields import AutoCompleteSelectField
|
2016-08-13 03:33:09 +00:00
|
|
|
|
2015-11-18 16:09:06 +00:00
|
|
|
import logging
|
2016-08-31 00:43:49 +00:00
|
|
|
import re
|
2015-11-18 16:09:06 +00:00
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
from core.models import User, Page, RealGroup, SithFile
|
|
|
|
|
2016-08-13 03:33:09 +00:00
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
# 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)
|
|
|
|
|
2016-09-08 01:29:49 +00:00
|
|
|
class SelectDateTime(DateTimeInput):
|
|
|
|
def render(self, name, value, attrs=None):
|
|
|
|
if attrs:
|
|
|
|
attrs['class'] = "select_datetime"
|
|
|
|
else:
|
|
|
|
attrs = {'class': "select_datetime"}
|
|
|
|
return super(SelectDateTime, self).render(name, value, attrs)
|
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
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)
|
|
|
|
|
2017-06-10 17:39:40 +00:00
|
|
|
class MarkdownInput(Textarea):
|
|
|
|
def render(self, name, value, attrs=None):
|
|
|
|
output = '<div class="markdown_editor">%(content)s</div>' % {
|
|
|
|
'content': super(MarkdownInput, self).render(name, value, attrs),
|
|
|
|
}
|
|
|
|
return output
|
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
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,
|
|
|
|
}
|
2017-03-27 20:47:24 +00:00
|
|
|
output += '<span name="' + name + '" class="choose_file_button">' + ugettext("Choose file") + '</span>'
|
2016-08-11 02:24:32 +00:00
|
|
|
return output
|
|
|
|
|
2016-08-19 21:24:23 +00:00
|
|
|
class SelectUser(TextInput):
|
|
|
|
def render(self, name, value, attrs=None):
|
|
|
|
if attrs:
|
|
|
|
attrs['class'] = "select_user"
|
|
|
|
else:
|
|
|
|
attrs = {'class': "select_user"}
|
|
|
|
output = '%(content)s<div name="%(name)s" class="choose_user_widget" title="%(title)s"></div>' % {
|
|
|
|
'content': super(SelectUser, self).render(name, value, attrs),
|
|
|
|
'title': _("Choose user"),
|
|
|
|
'name': name,
|
|
|
|
}
|
2017-03-27 20:47:24 +00:00
|
|
|
output += '<span name="' + name + '" class="choose_user_button">' + ugettext("Choose user") + '</span>'
|
2016-08-19 21:24:23 +00:00
|
|
|
return output
|
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
# Forms
|
2015-11-18 08:44:06 +00:00
|
|
|
|
2016-08-31 00:43:49 +00:00
|
|
|
class LoginForm(AuthenticationForm):
|
|
|
|
def __init__(self, *arg, **kwargs):
|
|
|
|
if 'data' in kwargs.keys():
|
|
|
|
from counter.models import Customer
|
|
|
|
data = kwargs['data'].copy()
|
|
|
|
account_code = re.compile(r"^[0-9]+[A-Za-z]$")
|
2016-09-01 15:50:13 +00:00
|
|
|
try:
|
|
|
|
if account_code.match(data['username']):
|
|
|
|
user = Customer.objects.filter(account_id__iexact=data['username']).first().user
|
|
|
|
elif '@' in data['username']:
|
|
|
|
user = User.objects.filter(email__iexact=data['username']).first()
|
|
|
|
else:
|
|
|
|
user = User.objects.filter(username=data['username']).first()
|
2016-09-01 14:43:21 +00:00
|
|
|
data['username'] = user.username
|
2016-09-01 15:50:13 +00:00
|
|
|
except: pass
|
2016-08-31 00:43:49 +00:00
|
|
|
kwargs['data'] = data
|
|
|
|
super(LoginForm, self).__init__(*arg, **kwargs)
|
|
|
|
self.fields['username'].label = _("Username, email, or account number")
|
|
|
|
|
2015-11-18 08:44:06 +00:00
|
|
|
class RegisteringForm(UserCreationForm):
|
|
|
|
error_css_class = 'error'
|
|
|
|
required_css_class = 'required'
|
|
|
|
class Meta:
|
|
|
|
model = User
|
2016-07-17 22:47:56 +00:00
|
|
|
fields = ('first_name', 'last_name', 'email')
|
2015-11-18 16:09:06 +00:00
|
|
|
|
|
|
|
def save(self, commit=True):
|
|
|
|
user = super(RegisteringForm, self).save(commit=False)
|
|
|
|
user.set_password(self.cleaned_data["password1"])
|
|
|
|
user.generate_username()
|
|
|
|
if commit:
|
|
|
|
user.save()
|
|
|
|
return user
|
|
|
|
|
2016-08-22 00:56:27 +00:00
|
|
|
from core.utils import resize_image
|
2016-08-13 03:33:09 +00:00
|
|
|
from io import BytesIO
|
|
|
|
from PIL import Image
|
|
|
|
|
2016-08-11 02:24:32 +00:00
|
|
|
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',
|
2016-08-13 03:33:09 +00:00
|
|
|
'scrub_pict', 'sex', 'second_email', 'address', 'parent_address', 'phone', 'parent_phone',
|
|
|
|
'tshirt_size', 'role', 'department', 'dpt_option', 'semester', 'quote', 'school', 'promo',
|
2016-08-22 16:44:03 +00:00
|
|
|
'forum_signature', 'is_subscriber_viewable']
|
2016-08-11 02:24:32 +00:00
|
|
|
widgets = {
|
|
|
|
'date_of_birth': SelectDate,
|
|
|
|
'profile_pict': forms.ClearableFileInput,
|
|
|
|
'avatar_pict': forms.ClearableFileInput,
|
|
|
|
'scrub_pict': forms.ClearableFileInput,
|
2016-08-13 03:33:09 +00:00
|
|
|
'phone': PhoneNumberInternationalFallbackWidget,
|
|
|
|
'parent_phone': PhoneNumberInternationalFallbackWidget,
|
2016-08-11 02:24:32 +00:00
|
|
|
}
|
|
|
|
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():
|
|
|
|
try:
|
2016-08-13 03:33:09 +00:00
|
|
|
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]),
|
2017-03-24 07:43:13 +00:00
|
|
|
owner=self.instance, is_folder=False, mime_type=f.content_type, size=f._size,
|
|
|
|
moderator=self.instance, is_moderated=True)
|
2016-08-13 03:33:09 +00:00
|
|
|
new_file.file.name = new_file.name
|
2016-08-11 02:24:32 +00:00
|
|
|
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)})
|
2016-08-13 03:33:09 +00:00
|
|
|
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")})
|
2016-08-11 02:24:32 +00:00
|
|
|
self._post_clean()
|
2015-11-18 16:09:06 +00:00
|
|
|
|
2015-12-09 10:01:11 +00:00
|
|
|
class UserPropForm(forms.ModelForm):
|
2015-11-24 13:01:10 +00:00
|
|
|
error_css_class = 'error'
|
|
|
|
required_css_class = 'required'
|
|
|
|
class Meta:
|
|
|
|
model = User
|
2016-07-17 22:47:56 +00:00
|
|
|
fields = ['groups']
|
2015-12-14 09:49:15 +00:00
|
|
|
help_texts = {
|
|
|
|
'groups': "Which groups this user belongs to",
|
|
|
|
}
|
2015-11-26 15:32:56 +00:00
|
|
|
widgets = {
|
|
|
|
'groups': CheckboxSelectMultiple,
|
|
|
|
}
|
2015-11-24 13:01:10 +00:00
|
|
|
|
2016-09-19 18:29:43 +00:00
|
|
|
class UserGodfathersForm(forms.Form):
|
|
|
|
type = forms.ChoiceField(choices=[('godfather', _("Godfather")), ('godchild', _("Godchild"))], label=_("Add"))
|
|
|
|
user = AutoCompleteSelectField('users', required=True, label=_("Select user"), help_text=None)
|
|
|
|
|
2015-11-27 14:39:42 +00:00
|
|
|
class PagePropForm(forms.ModelForm):
|
|
|
|
error_css_class = 'error'
|
|
|
|
required_css_class = 'required'
|
|
|
|
class Meta:
|
|
|
|
model = Page
|
2016-02-05 15:59:42 +00:00
|
|
|
fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups', ]
|
2015-11-27 14:39:42 +00:00
|
|
|
widgets = {
|
2016-02-05 15:59:42 +00:00
|
|
|
'edit_groups': CheckboxSelectMultiple,
|
|
|
|
'view_groups': CheckboxSelectMultiple,
|
2015-11-27 14:39:42 +00:00
|
|
|
}
|
|
|
|
|
2015-11-27 15:09:47 +00:00
|
|
|
def __init__(self, *arg, **kwargs):
|
|
|
|
super(PagePropForm, self).__init__(*arg, **kwargs)
|
2016-02-05 15:59:42 +00:00
|
|
|
self.fields['edit_groups'].required = False
|
|
|
|
self.fields['view_groups'].required = False
|
2015-11-27 15:09:47 +00:00
|
|
|
|