diff options
Diffstat (limited to 'project/scipycon/user')
-rw-r--r-- | project/scipycon/user/__init__.py | 0 | ||||
-rw-r--r-- | project/scipycon/user/admin.py | 17 | ||||
-rw-r--r-- | project/scipycon/user/forms.py | 135 | ||||
-rw-r--r-- | project/scipycon/user/models.py | 26 | ||||
-rw-r--r-- | project/scipycon/user/utils.py | 138 | ||||
-rw-r--r-- | project/scipycon/user/views.py | 386 |
6 files changed, 702 insertions, 0 deletions
diff --git a/project/scipycon/user/__init__.py b/project/scipycon/user/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/project/scipycon/user/__init__.py diff --git a/project/scipycon/user/admin.py b/project/scipycon/user/admin.py new file mode 100644 index 0000000..3d4813b --- /dev/null +++ b/project/scipycon/user/admin.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +#django +from django.contrib import admin + +#scipycon +from .models import UserProfile + +class UserProfileAdmin(admin.ModelAdmin): + list_display = ('user', 'email', 'url', 'about') + + def email(self, obj): + return obj.user.email + +admin.site.register(UserProfile, UserProfileAdmin) + diff --git a/project/scipycon/user/forms.py b/project/scipycon/user/forms.py new file mode 100644 index 0000000..46ad2f6 --- /dev/null +++ b/project/scipycon/user/forms.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +#django +from django import forms +from django.contrib.auth.models import User + +class RegistrantForm(forms.Form): + """Form to register an attendee + """ + username = forms.RegexField(label="Nickname", max_length=30, + regex=r'^\w+$', + help_text = "30 characters or fewer. Alphanumeric" \ + + " characters only (letters, digits and underscores).", + error_message = "This value must contain only letters, numbers and underscores.") + name = forms.CharField(label=u"Name", max_length=50, required=True) + email = forms.EmailField(label=u"E-mail", max_length=50, required=True) + + def clean_email(self): + """Validates that the entered e-mail is unique. + """ + email = self.cleaned_data.get("email") + if email and User.objects.filter(email=email).count() > 0: + raise forms.ValidationError( + u"That email address is already in use. Are you a member of " \ + "site? Please log in.") + + return email + + def clean_username(self): + """Validates that the entered username is unique. + """ + username = self.cleaned_data.get("username") + if username and User.objects.filter(username=username).count() > 0: + raise forms.ValidationError( + u"That username is already in use.") + + return username + +class RegisterForm(forms.Form): + """Form to register speaker + """ + username = forms.RegexField(label="Username", max_length=30, + regex=r'^\w+$', + help_text = "Required. 30 characters or fewer. Alphanumeric" \ + + " characters only (letters, digits and underscores).", + error_message = "This value must contain only letters, numbers and underscores.") + first_name = forms.CharField(label=u"First name", max_length=50) + last_name = forms.CharField(label=u"Last name", max_length=50) + email = forms.EmailField(label=u"E-mail", max_length=50) + url = forms.URLField(required=False) + about = forms.CharField(label=u'Short Bio', max_length=50, required=False) + photo = forms.FileField(label=u'Profile Photo', required=False) + password_1 = forms.CharField( + label=u"Password", widget=forms.PasswordInput(), max_length=20) + password_2 = forms.CharField( + label=u"Confirm password", widget=forms.PasswordInput(), max_length=20) + + def clean_password_2(self): + """Validates that password 1 and password 2 are the same. + """ + p1 = self.cleaned_data.get('password_1') + p2 = self.cleaned_data.get('password_2') + + if not (p1 and p2 and p1 == p2): + raise forms.ValidationError(u"The two passwords do not match.") + + return p2 + + def clean_email(self): + """Validates that the entered e-mail is unique. + """ + email = self.cleaned_data.get("email") + if email and User.objects.filter(email=email).count() > 0: + raise forms.ValidationError( + u"That email address is already in use.") + + return email + + def clean_username(self): + """Validates that the entered username is unique. + """ + username = self.cleaned_data.get("username") + if username and User.objects.filter(username=username).count() > 0: + raise forms.ValidationError( + u"That username is already in use.") + + return username + +class EditProfileForm(forms.Form): + """Edit user profile form + """ + first_name = forms.CharField(max_length=50) + last_name = forms.CharField(max_length=50) + email = forms.EmailField(max_length=50) + email2 = forms.CharField(widget=forms.HiddenInput) + url = forms.URLField(required=False) + about = forms.CharField(label=u'Short Bio', + widget=forms.Textarea, required=False) + photo = forms.FileField(label=u'Profile Photo', + required=False) + + def clean_email(self): + """Validates that the entered e-mail is unique. + """ + email = self.cleaned_data.get("email") + email2 = self.data.get("email2").strip() + print email, email2 + if email != email2: # email has been changed + if email and User.objects.filter(email=email).count() > 0: + raise forms.ValidationError( + u"That email address is already in use.") + + return email + +class UsernameForm(forms.Form): + """Form to edit email address + """ + username = forms.RegexField(label="Username", max_length=30, + regex=r'^\w+$', + help_text = "Required. 30 characters or fewer. Alphanumeric" \ + + " characters only (letters, digits and underscores).", + error_message = "This value must contain only letters, numbers and underscores.") + + def clean_username(self): + """Validates that the entered username is unique. + """ + username = self.cleaned_data.get("username") + if username and User.objects.filter(username=username).count() > 0: + raise forms.ValidationError( + u"That username is already in use.") + + return username + + diff --git a/project/scipycon/user/models.py b/project/scipycon/user/models.py new file mode 100644 index 0000000..4688b79 --- /dev/null +++ b/project/scipycon/user/models.py @@ -0,0 +1,26 @@ +from django.db import models +from django.conf import settings +from django.db.models.signals import post_save +from django.contrib.auth.models import User + +from project.scipycon.base import models as base_models + + +class UserProfile(base_models.ScopedBase): + """Extend atributes for django User + """ + + user = models.ForeignKey(User, unique=True) + + url = models.URLField(blank=True, verify_exists=False) + + photo = models.CharField(max_length=64, blank=True) + + about = models.TextField(blank=True) + + def __unicode__(self): + return 'UserProfile for user: <%s %s> %s' % (self.user.first_name, + self.user.last_name, self.user.email) + + def fullname(self): + return '%s %s' % (self.user.first_name, self.user.last_name) diff --git a/project/scipycon/user/utils.py b/project/scipycon/user/utils.py new file mode 100644 index 0000000..f4b4741 --- /dev/null +++ b/project/scipycon/user/utils.py @@ -0,0 +1,138 @@ +import os + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.auth.models import User + +from PIL import Image + +from project.scipycon.base.models import Event +from project.scipycon.user.models import UserProfile + + +def scipycon_createregistrant(request, data, scope): + """Create user + """ + + email = data.get('email') + name = data.get('name') + username = data.get('username') + + n = name.split(' ') + if len(n) > 1: + first_name = ' '.join(n[:-1]) + last_name = n[-1] + else: + first_name = '' + last_name = n[0] + + + # Create user + user = User.objects.create_user(username=username, email=email) + user.first_name = first_name + user.last_name = last_name + user.save() + + scope_entity = Event.objects.get(scope=scope) + try: + profile = user.get_profile() + except: + profile, new = UserProfile.objects.get_or_create( + user=user, scope=scope_entity) + profile.save() + + return user + +def scipycon_createuser(request, data, scope): + """Create user + """ + + from django.contrib.auth import authenticate + from django.contrib.auth import login + + email = data.get('email') + username = data.get('username') + password = data.get('password_1') + password = data.get('password_1') + + # Create user + user = User.objects.create_user( + username=username, email=email, password=password) + user.first_name = data.get('first_name') + user.last_name = data.get('last_name') + user.save() + + # Log in user + + user = authenticate(username=username, password=password) + + login(request, user) + + scope_entity = Event.objects.get(scope=scope) + + try: + profile = user.get_profile() + except: + profile, new = UserProfile.objects.get_or_create( + user=user, scope=scope_entity) + + photo = request.FILES.get('photo', None) + filename= None + if photo: + filename = handle_uploaded_photo(user, request.FILES['photo']) + if filename: + profile.photo = filename + + profile.url = data.get('url') + profile.about = data.get('about') + profile.save() + + return user + +def handle_uploaded_photo(user, ufile): + """Handles the upload and gives the file path to be saved. + """ + + usermedia = settings.USER_MEDIA_ROOT + filename = ufile.name + ext = filename.split('.')[-1] + + filecontent = ufile.read() + userfilename = 'user-%d.%s' % (user.id, ext) + if not filecontent: + return None + + #save + foutname = os.path.join(usermedia, userfilename) + + fout = file(foutname, 'wb') + fout.write(filecontent) + fout.close() + + # crop and resize + image = Image.open(foutname) + pw = image.size[0] + ph = image.size[1] + nw = nh = 80 + if (pw, ph) != (nw, nh): + pr = float(pw) / float(ph) + nr = float(nw) / float(nh) + + if pr > nr: + # photo aspect is wider than destination ratio + tw = int(round(nh * pr)) + image = image.resize((tw, nh), Image.ANTIALIAS) + l = int(round(( tw - nw ) / 2.0)) + image = image.crop((l, 0, l + nw, nh)) + elif pr < nr: + # photo aspect is taller than destination ratio + th = int(round(nw / pr)) + image = image.resize((nw, th), Image.ANTIALIAS) + t = int(round(( th - nh ) / 2.0)) + image = image.crop((0, t, nw, t + nh)) + else: + # photo aspect matches the destination ratio + image = image.resize((nw, nh), Image.ANTIALIAS) + + image.save(str(foutname)) + return userfilename diff --git a/project/scipycon/user/views.py b/project/scipycon/user/views.py new file mode 100644 index 0000000..d46e77d --- /dev/null +++ b/project/scipycon/user/views.py @@ -0,0 +1,386 @@ +from urlparse import urlparse + +import simplejson as json +import os + +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.forms import PasswordChangeForm +from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse +from django.db.models import Q +from django.http import HttpResponse +from django.shortcuts import render_to_response +from django.template import RequestContext + +from PIL import Image + +from project.scipycon.base.models import Event +from project.scipycon.registration.models import Registration +from project.scipycon.registration.models import Wifi +from project.scipycon.registration.forms import WifiForm +from project.scipycon.talk.models import Talk +from project.scipycon.user.forms import EditProfileForm +from project.scipycon.user.forms import RegisterForm +from project.scipycon.user.forms import UsernameForm +from project.scipycon.user.utils import handle_uploaded_photo +from project.scipycon.user.utils import scipycon_createuser +from project.scipycon.utils import set_message_cookie + +#User_dump Http404 Error +from django.http import Http404 +#for user_dump creation +from project.scipycon.registration.models import Accommodation + +#Pdf badge generation +from reportlab.pdfgen import canvas +from reportlab.lib.units import cm +from reportlab.platypus import Image as reportlabImage +from django.core.exceptions import ObjectDoesNotExist + + +@login_required +def account(request, scope, template_name="user/account.html"): + """Displays the main screen of the current user's account. + """ + + user = request.user + profile = user.get_profile() + + talks = Talk.objects.filter(speaker=user) + + try: + registration = Registration.objects.get(registrant=user) + except ObjectDoesNotExist: + registration = None + + try: + wifiobj = Wifi.objects.get(user=user) + except ObjectDoesNotExist: + wifiobj = None + + event = Event.objects.get(scope=scope) + + if profile.photo: + photo = os.path.join(settings.USER_MEDIA_URL, profile.photo) + else: + photo = '/img/user-default.png' + + return render_to_response(template_name, RequestContext(request, { + 'params': {'scope': scope}, + 'user' : user, + 'profile' : profile, + 'photo' : photo, + 'talks' : talks, + 'registration' : registration, + 'event': event})) + +@login_required +def edit_profile(request, scope, template_name="user/editprofile.html"): + """Allows user to edit profile + """ + + user = request.user + profile = user.get_profile() + + if request.method == "POST": + form = EditProfileForm(data=request.POST, + files=request.FILES) + + if form.is_valid(): + photo = request.FILES.get('photo', None) + filename= None + if photo: + filename = handle_uploaded_photo(user, request.FILES['photo']) + if filename: + profile.photo = filename + + user.email = form.data.get("email") + user.first_name = form.data.get("first_name") + user.last_name = form.data.get("last_name") + user.save() + + profile.url = form.data.get("url") + profile.about = form.data.get("about") + profile.save() + + redirect_to = reverse('scipycon_account', + kwargs={'scope': scope}) + return set_message_cookie(redirect_to, + msg = u'Your profile has been changed.') + + else: + form = EditProfileForm( + initial={ + 'email' : user.email, + 'email2' : user.email, # hidden field + 'first_name' : user.first_name, + 'last_name' : user.last_name, + 'url' : profile.url, + 'about' : profile.about, + }) + + return render_to_response(template_name, RequestContext(request, { + 'params': {'scope': scope}, + 'form': form + })) + +def login(request, scope, template_name="user/login.html"): + """Custom view to login or register/login a user. + Integration of register and login form + It uses Django's standard AuthenticationForm, though. + """ + + user = request.user + if user.is_authenticated(): + redirect_to = reverse("scipycon_account", kwargs={'scope': scope}) + return set_message_cookie(redirect_to, + msg = u"Redirected to account from login form.") + + # Using Djangos default AuthenticationForm + login_form = AuthenticationForm() + register_form = RegisterForm() + + if request.POST.get("action") == "login": + login_form = AuthenticationForm(data=request.POST) + + if login_form.is_valid(): + redirect_to = request.POST.get("next") + # Light security check -- make sure redirect_to isn't garbage. + if not redirect_to or '//' in redirect_to or ' ' in redirect_to: + redirect_to = reverse('scipycon_account', + kwargs={'scope': scope}) + + from django.contrib.auth import login + login(request, login_form.get_user()) + + return set_message_cookie(redirect_to, msg = u"You have been logged in.") + + elif request.POST.get("action") == "register": + register_form = RegisterForm(data=request.POST) + if register_form.is_valid(): + + user = scipycon_createuser(request, register_form.data, scope) + + redirect_to = request.POST.get("next") + if not redirect_to or '//' in redirect_to or ' ' in redirect_to: + redirect_to = reverse('scipycon_account', + kwargs={'scope': scope}) + + return set_message_cookie( + redirect_to, msg = u"You have been registered and logged in.") + + # Get next_url + next_url = request.REQUEST.get("next") + if next_url is None: + next_url = request.META.get("HTTP_REFERER") + if next_url is None: + next_url = reverse('scipycon_account', kwargs={'scope': scope}) + + # Get just the path of the url. + # See django.contrib.auth.views.login for more + next_url = urlparse(next_url) + next_url = next_url[2] + + try: + login_form_errors = login_form.errors["__all__"] + except KeyError: + login_form_errors = None + + return render_to_response(template_name, RequestContext(request, { + 'params': {'scope': scope}, + 'login_form' : login_form, + 'login_form_errors' : login_form_errors, + 'register_form' : register_form, + 'next_url' : next_url, + })) + +def logout(request, scope): + """Custom method to logout a user. + + The reason to use a custom logout method is just to provide a login and a + logoutmethod on one place. + """ + + from django.contrib.auth import logout + logout(request) + + redirect_to = '/%s' % (scope) + return set_message_cookie(redirect_to, msg = u"You have been logged out.") + +@login_required +def password(request, scope, template_name='user/password.html'): + """Changes the password of current user. + """ + + if request.method == 'POST': + form = PasswordChangeForm(request.user, request.POST) + if form.is_valid(): + form.save() + redirect_to = reverse('scipycon_account', kwargs={'scope': scope}) + return set_message_cookie(redirect_to, + msg = u'Your password has been changed.') + else: + form = PasswordChangeForm(request.user) + + return render_to_response(template_name, RequestContext(request, { + 'params': {'scope': scope}, + 'form' : form + })) + +@login_required +def username(request, scope, template_name='user/username.html'): + """Saves the username from the data form. + """ + if request.method == 'POST': + username_form = UsernameForm( + initial={'username' : request.user.username}, + data=request.POST) + if username_form.is_valid(): + request.user.username = username_form.cleaned_data.get("username") + request.user.save() + redirect_to = reverse('scipycon_account', + kwargs={'scope': scope}) + return set_message_cookie(redirect_to, + msg = u"Your username has been changed.") + else: + username_form = UsernameForm(initial={"username" : request.user.username}) + + return render_to_response(template_name, RequestContext(request, { + 'params': {'scope': scope}, + 'form': username_form + })) + + +def get_usernames(request, scope): + """Returns in json the list of ten possible usernames + starting with the last pattern in the comma separated string + """ + + get_params = request.GET + authors_str = get_params.get('input') + + if not authors_str: + return HttpResponse(json.dumps('')) + + authors = authors_str.split(',') + search_author = authors[-1].strip() + + users = User.objects.filter( + Q(username__istartswith=search_author) | Q( + first_name__istartswith=search_author) | Q( + last_name__istartswith=search_author)) + + results = [{'id': '', + 'info': 'plugin_header', + 'value': 'User Names' + }] + + for user in users: + results.append( + {'id': 'author_name', + 'info': str(user.get_full_name()), + 'value': str(user.username) + }) + + json_response = {'results': results} + + return HttpResponse(json.dumps(json_response)) + + +@login_required +def get_user_dump(request, scope,template_name='user/dump.html'): + """ Gets a general dump of user related info + """ + print request.user.is_staff + if request.user.is_staff: + qs=Registration.objects.all() + rows=[] + for obj in qs: + row = {} + row['first_name'] = obj.registrant.first_name + row['last_name'] = obj.registrant.last_name + try: + accomodation_require = Accommodation.objects.filter(user__username=obj.registrant.username)[0] + row['sex'] = accomodation_require.sex + except: + row['sex'] = '-' + row['city'] = obj.city + row['organization'] = obj.organisation + row['occupation'] = obj.occupation + row['conference'] = obj.conference + row['sprint'] = obj.sprint + row['tutorial'] = obj.tutorial + try: + wifi_require = Wifi.objects.filter(user__username=obj.registrant.username)[0] + row['wifi'] = wifi_require.wifi + except: + row['wifi']='Wifi Unspecified' + rows.append(row) + return render_to_response(template_name, RequestContext(request, { + 'rows': rows})) + + + else: + raise Http404 + + +@login_required +def badge(request,scope): + + from django.conf import settings + + # Create the HttpResponse object with the appropriate PDF headers. + response = HttpResponse(mimetype='application/pdf') + response['Content-Disposition'] = 'attachment; filename=scipybadge.pdf' + + # Create the PDF object, using the response object as its "file." + c = canvas.Canvas(response) + + ref=5*cm + # Draw things on the PDF. Here's where the PDF generation happens. + # See the ReportLab documentation for the full list of functionality. + c.rect(ref,ref,9*cm,6*cm) + + img_path = os.path.join(settings.STATIC_ROOT, 'img', 'scipyshiny_small.png') + im = reportlabImage(img_path, width=1.75*cm, height=1.75*cm) + im.drawOn(c,(ref+0.8*cm),(ref+4.3*cm)) + c.setFont('Helvetica', 6) + c.drawString((ref+1.0*cm),(ref+4.2*cm),'scipy.in 2010') + c.drawString((ref+1.1*cm),(ref+4.0*cm),'Hyderabad') + + c.setFont('Helvetica', 14) + print request.user.id + reg_obj=Registration.objects.get(registrant=request.user.id) + c.drawString((ref+3.4*cm),(ref+4.9*cm),str(reg_obj.slug)) + + c.setFont('Helvetica-Bold', 15) + c.drawString((ref+0.6*cm),(ref+3.4*cm),str(request.user.get_full_name())) + c.setFont('Helvetica', 11) + c.drawString((ref+2.8*cm),(ref+2.7*cm),reg_obj.organisation) + c.setFont('Helvetica', 11) + try: + c.drawString((ref+2.8*cm),(ref+2.2*cm),reg_obj.occupation.split(':')[1]) + except IndexError: + c.drawString((ref+2.8*cm),(ref+2.3*cm),reg_obj.occupation) + + c.setFont('Helvetica', 10) + c.drawString((ref+2.8*cm),(ref+1.7*cm),reg_obj.city) + c.setFont('Helvetica', 10) + c.drawString((ref+2.8*cm),(ref+1*cm),'Participant') + + + try: + wifi_obj=Wifi.objects.get(user=request.user.id) + c.setFont('Helvetica', 10) + c.drawString((ref+5.6*cm),(ref+0.5*cm),wifi_obj.registration_id) + except : + pass + + + # Close the PDF object cleanly, and we're done. + c.showPage() + c.save() + return response |