summaryrefslogtreecommitdiff
path: root/project/kiwipycon
diff options
context:
space:
mode:
Diffstat (limited to 'project/kiwipycon')
-rw-r--r--project/kiwipycon/__init__.py0
-rw-r--r--project/kiwipycon/context_processors.py17
-rw-r--r--project/kiwipycon/registration/__init__.py0
-rw-r--r--project/kiwipycon/registration/admin.py37
-rw-r--r--project/kiwipycon/registration/forms.py179
-rw-r--r--project/kiwipycon/registration/labels.py7
-rw-r--r--project/kiwipycon/registration/migrations/0001_initial.py70
-rw-r--r--project/kiwipycon/registration/migrations/0002_create_wifi.py60
-rw-r--r--project/kiwipycon/registration/migrations/__init__.py0
-rw-r--r--project/kiwipycon/registration/models.py68
-rw-r--r--project/kiwipycon/registration/pdf.py20
-rw-r--r--project/kiwipycon/registration/tests.py19
-rw-r--r--project/kiwipycon/registration/utils.py215
-rw-r--r--project/kiwipycon/registration/views.py336
-rw-r--r--project/kiwipycon/sponsor/__init__.py0
-rw-r--r--project/kiwipycon/sponsor/admin.py15
-rw-r--r--project/kiwipycon/sponsor/migrations/0001_initial.py50
-rw-r--r--project/kiwipycon/sponsor/migrations/__init__.py0
-rw-r--r--project/kiwipycon/sponsor/models.py28
-rw-r--r--project/kiwipycon/sponsor/views.py17
-rw-r--r--project/kiwipycon/talk/__init__.py0
-rw-r--r--project/kiwipycon/talk/admin.py23
-rw-r--r--project/kiwipycon/talk/forms.py62
-rw-r--r--project/kiwipycon/talk/migrations/0001_initial.py68
-rw-r--r--project/kiwipycon/talk/migrations/__init__.py0
-rw-r--r--project/kiwipycon/talk/models.py73
-rw-r--r--project/kiwipycon/talk/templatetags/__init__.py1
-rw-r--r--project/kiwipycon/talk/templatetags/talk_extras.py8
-rw-r--r--project/kiwipycon/talk/views.py183
-rw-r--r--project/kiwipycon/user/__init__.py0
-rw-r--r--project/kiwipycon/user/admin.py17
-rw-r--r--project/kiwipycon/user/forms.py135
-rw-r--r--project/kiwipycon/user/migrations/0001_initial.py44
-rw-r--r--project/kiwipycon/user/migrations/__init__.py0
-rw-r--r--project/kiwipycon/user/models.py36
-rw-r--r--project/kiwipycon/user/utils.py122
-rw-r--r--project/kiwipycon/user/views.py238
-rw-r--r--project/kiwipycon/utils.py40
38 files changed, 2188 insertions, 0 deletions
diff --git a/project/kiwipycon/__init__.py b/project/kiwipycon/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/__init__.py
diff --git a/project/kiwipycon/context_processors.py b/project/kiwipycon/context_processors.py
new file mode 100644
index 0000000..2aebf5f
--- /dev/null
+++ b/project/kiwipycon/context_processors.py
@@ -0,0 +1,17 @@
+from datetime import datetime
+
+from django.conf import settings
+
+from project.kiwipycon.sponsor.models import Sponsor
+
+def sponsors(request):
+ sponsors = Sponsor.objects.all()
+ gold_sponsors = sponsors.filter(type='gold')
+ silver_sponsors = sponsors.filter(type='silver')
+ schwag_sponsors = sponsors.filter(type='schwag')
+ return {
+ 'sponsors': {'gold': gold_sponsors,
+ 'silver': silver_sponsors,
+ 'schwag': schwag_sponsors}
+ }
+
diff --git a/project/kiwipycon/registration/__init__.py b/project/kiwipycon/registration/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/registration/__init__.py
diff --git a/project/kiwipycon/registration/admin.py b/project/kiwipycon/registration/admin.py
new file mode 100644
index 0000000..b609899
--- /dev/null
+++ b/project/kiwipycon/registration/admin.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django.contrib
+from django.contrib import admin
+
+#kiwipycon
+from .models import Registration
+from .models import Wifi
+
+class RegistrationAdmin(admin.ModelAdmin):
+ list_display = ('registrant', 'slug', 'email', 'city',
+ 'organisation', 'occupation', 'postcode',
+ 'tshirt', 'conference', 'tutorial', 'sprint',
+ 'allow_contact')
+ fieldsets = (
+ ('Details', {
+ 'fields': ('slug', 'registrant', 'organisation', 'occupation',
+ 'city', 'tshirt')
+ }),
+ ('Information', {
+ 'fields': ('allow_contact',),
+ }),
+ )
+
+ def email(self, obj):
+ return obj.registrant.email
+
+
+admin.site.register(Registration, RegistrationAdmin)
+
+class WifiAdmin(admin.ModelAdmin):
+ list_display = ('user', 'wifi',)
+ list_filter = ('wifi',)
+
+admin.site.register(Wifi, WifiAdmin)
+
diff --git a/project/kiwipycon/registration/forms.py b/project/kiwipycon/registration/forms.py
new file mode 100644
index 0000000..8d366c6
--- /dev/null
+++ b/project/kiwipycon/registration/forms.py
@@ -0,0 +1,179 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django import forms
+from django.core.exceptions import ObjectDoesNotExist
+
+#django.contrib
+from django.contrib.auth.models import User
+
+from .models import SIZE_CHOICES
+from .models import Registration
+from .models import Wifi
+from project.kiwipycon.sponsor.models import Sponsor
+
+class RegistrationSubmitForm(forms.Form):
+ """PyCon registration form
+ """
+ tshirt = forms.ChoiceField(choices=SIZE_CHOICES, required=True,
+ label=u'T-shirt size', help_text=u'Yes, we all get a t-shirt!')
+# beverage = forms.CharField(required=True, label=u'Beverage',
+# help_text=u'Your beverage of choice - coffee, tea etc',
+# max_length=255,
+# widget=forms.TextInput(attrs={'size':'50'}))
+# diet = forms.CharField(required=False, label=u'Dietary',
+# help_text=u'Special dietary requirements - vegetarian etc',
+# max_length=255,
+# widget=forms.TextInput(attrs={'size':'50'}))
+ organisation = forms.CharField(required=True, label=u'Organisation',
+ help_text=u'The primary organisation that you are a member of.',
+ max_length=255,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ occupation = forms.CharField(required=True, label=u'Occupation',
+ help_text=u'Title of your occupation',
+ max_length=255,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ city = forms.CharField(required=True, label=u'City',
+ help_text=u'City of residence',
+ max_length=255,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ postcode = forms.CharField(required=False, label=u'Postcode',
+ help_text=u'This field is optional',
+ max_length=10,
+ widget=forms.TextInput(attrs={'size':'10'}))
+ allow_contact = forms.BooleanField(required=False, label=u'Contact',
+ help_text=u'May organizers of SciPy.in contact you after the event?')
+ conference = forms.BooleanField(required=False, label=u'Conference',
+ help_text=u"""Do you intend to attend the SciPy conference?
+ Note: Only conference has an registration fee of Rs.200 which you will
+ pay on the spot.""")
+ tutorial = forms.BooleanField(required=False, label=u'Tutorial',
+ help_text=u'Do you intend to attend the tutorials?')
+ sprint = forms.BooleanField(required=False, label=u'Sprint',
+ help_text=u'Do you intend to attend the sprints?')
+# party = forms.BooleanField(required=False, label=u'Pre-con party',
+# help_text=u'Do you intend to attend the pre-conference party on Friday?')
+# discount = forms.BooleanField(required=False, label=u'Student/Unwaged?',
+# help_text=u'You will be required to present your Community Services '\
+# 'Card or Student ID on arrival.')
+# sponsor = forms.CharField(required=False, label=u'Sponsor code',
+# help_text=u'If attending as a sponsor please enter your sponsor code.',
+# max_length=50,
+# widget=forms.TextInput(attrs={'size':'20'}))
+
+ def demographic_fields(self):
+ return (self['organisation'],
+ self['occupation'],
+ self['city'],
+ self['postcode'])
+
+ def personal_fields(self):
+ return (self['tshirt'],
+ self['conference'],
+ self['tutorial'],
+ self['sprint'],
+ self['allow_contact'])
+
+# def other_fields(self):
+# return (self['sponsor'],)
+#
+# def clean_sponsor(self):
+# """Validates that the entered sponsor code is valid and within limits
+# of allowed guests
+# """
+# sponsorcode = self.cleaned_data.get("sponsor")
+# if sponsorcode:
+# try:
+# sponsor = Sponsor.objects.get(slug=sponsorcode)
+# except ObjectDoesNotExist:
+# raise forms.ValidationError(
+# u"The sponsor code you entered is not valid.")
+# if sponsor:
+# guests = sponsor.guests
+# if guests == 0:
+# raise forms.ValidationError(
+# u"The sponsor code you entered is not valid.")
+# count = Registration.objects.filter(
+# sponsor=sponsorcode).count()
+# if count >= guests:
+# raise forms.ValidationError(
+# u"That sponsor has reached limit of guests.")
+#
+#
+# return sponsorcode
+
+
+class RegistrationEditForm(RegistrationSubmitForm):
+ id = forms.CharField(widget=forms.HiddenInput)
+ sponsor = forms.CharField(required=False, widget=forms.HiddenInput)
+
+class WifiForm(forms.ModelForm):
+ """PyCon wifi form
+ """
+
+ def save(self, user):
+ wifi = Wifi(user=user, wifi=self.cleaned_data['wifi'])
+ wifi.save()
+ return wifi
+
+ class Meta:
+ model = Wifi
+ fields = ('wifi',)
+
+PC = (
+ ('all', 'all'),
+ ('paid', 'paid'),
+ ('not paid', 'not paid')
+ )
+HC = (
+ ('all', 'all'),
+ ('party', 'party'),
+ ('no party', 'no party')
+ )
+AC = (
+ ('all', 'all'),
+ ('0', '0'),
+ ('10', '10'),
+ ('20', '20'),
+ ('40', '40'),
+ )
+OC = (
+ ('email', 'email'),
+ ('amount', 'amount'),
+ )
+
+IC = (
+ ('Name', 'name'),
+ ('Email', 'email'),
+ ('Amount', 'amount'),
+ ('Organisation', 'organisation'),
+ ('Conference', 'conference'),
+ ('Tutorial', 'tutorial'),
+ ('Sprint', 'sprint'),
+ ('T-size', 'tshirt'),
+ )
+
+SC = (
+ ('all', 'all'),
+ ('S', 'S'),
+ ('M', 'M'),
+ ('L', 'L'),
+ ('XL', 'XL'),
+ )
+class RegistrationAdminSelectForm(forms.Form):
+ """
+ Used to make selection for csv download
+ """
+ by_payment = forms.ChoiceField(choices=PC, required=False,
+ label=u'By payment')
+ by_amount = forms.MultipleChoiceField(choices=AC, required=False,
+ label=u'By amount')
+ by_party = forms.ChoiceField(choices=HC, required=False,
+ label=u'by party')
+ by_tshirt = forms.ChoiceField(choices=SC, required=False,
+ label=u'by tshirt size')
+ order_by = forms.ChoiceField(choices=OC, required=False,
+ label=u'order results')
+ include = forms.MultipleChoiceField(choices=IC, required=False,
+ label=u'Include fields')
diff --git a/project/kiwipycon/registration/labels.py b/project/kiwipycon/registration/labels.py
new file mode 100644
index 0000000..c465f2c
--- /dev/null
+++ b/project/kiwipycon/registration/labels.py
@@ -0,0 +1,7 @@
+
+WIFI_CHOICES = (
+ ("0", "Yes"),
+ ('1', 'No'),
+ )
+
+WIFI_HELP = """Are you bringing a laptop to the event?"""
diff --git a/project/kiwipycon/registration/migrations/0001_initial.py b/project/kiwipycon/registration/migrations/0001_initial.py
new file mode 100644
index 0000000..4154027
--- /dev/null
+++ b/project/kiwipycon/registration/migrations/0001_initial.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from project.kiwipycon.registration.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'Registration'
+ db.create_table('registration_registration', (
+ ('city', models.CharField(max_length=255, blank=True)),
+ ('slug', models.SlugField()),
+ ('submitted', models.DateTimeField(auto_now_add=True)),
+ ('allow_contact', models.BooleanField(default=False)),
+ ('last_mod', models.DateTimeField(auto_now=True)),
+ ('payment', models.BooleanField(default=False)),
+ ('organisation', models.CharField(max_length=255, blank=True)),
+ ('diet', models.CharField(max_length=255, blank=True)),
+ ('id', models.AutoField(primary_key=True)),
+ ('sponsor', models.CharField(max_length=255, blank=True)),
+ ('discount', models.BooleanField(default=False)),
+ ('amount', models.IntegerField(default=0)),
+ ('tshirt', models.CharField(max_length=2)),
+ ('beverage', models.CharField(max_length=255, blank=True)),
+ ('postcode', models.CharField(max_length=255, blank=True)),
+ ('party', models.BooleanField(default=False)),
+ ('registrant', models.ForeignKey(orm['auth.User'])),
+ ('occupation', models.CharField(max_length=255, blank=True)),
+ ))
+ db.send_create_signal('registration', ['Registration'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Registration'
+ db.delete_table('registration_registration')
+
+
+
+ models = {
+ 'auth.user': {
+ '_stub': True,
+ 'id': ('models.AutoField', [], {'primary_key': 'True'})
+ },
+ 'registration.registration': {
+ 'allow_contact': ('models.BooleanField', [], {'default': 'False'}),
+ 'beverage': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'city': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'diet': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'discount': ('models.BooleanField', [], {'default': 'False'}),
+ 'amount': ('models.IntegerField', [], {'default': 0}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'last_mod': ('models.DateTimeField', [], {'auto_now': 'True'}),
+ 'occupation': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'organisation': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'party': ('models.BooleanField', [], {'default': 'False'}),
+ 'payment': ('models.BooleanField', [], {'default': 'False'}),
+ 'postcode': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'registrant': ('models.ForeignKey', ['User'], {}),
+ 'slug': ('models.SlugField', [], {}),
+ 'sponsor': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'submitted': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
+ 'tshirt': ('models.CharField', [], {'max_length': '2'})
+ }
+ }
+
+ complete_apps = ['registration']
diff --git a/project/kiwipycon/registration/migrations/0002_create_wifi.py b/project/kiwipycon/registration/migrations/0002_create_wifi.py
new file mode 100644
index 0000000..b5f7256
--- /dev/null
+++ b/project/kiwipycon/registration/migrations/0002_create_wifi.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from project.kiwipycon.registration.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'Wifi'
+ db.create_table('registration_wifi', (
+ ('wifi', models.CharField(max_length=50)),
+ ('user', models.ForeignKey(orm['auth.User'])),
+ ('id', models.AutoField(primary_key=True)),
+ ))
+ db.send_create_signal('registration', ['Wifi'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Wifi'
+ db.delete_table('registration_wifi')
+
+
+
+ models = {
+ 'auth.user': {
+ '_stub': True,
+ 'id': ('models.AutoField', [], {'primary_key': 'True'})
+ },
+ 'registration.wifi': {
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('models.ForeignKey', ['User'], {}),
+ 'wifi': ('models.CharField', [], {'max_length': '50'})
+ },
+ 'registration.registration': {
+ 'allow_contact': ('models.BooleanField', [], {'default': 'False'}),
+ 'amount': ('models.IntegerField', [], {'default': '0'}),
+ 'beverage': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'city': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'diet': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'discount': ('models.BooleanField', [], {'default': 'False'}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'last_mod': ('models.DateTimeField', [], {'auto_now': 'True'}),
+ 'occupation': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'organisation': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'party': ('models.BooleanField', [], {'default': 'False'}),
+ 'payment': ('models.BooleanField', [], {'default': 'False'}),
+ 'postcode': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'registrant': ('models.ForeignKey', ['User'], {}),
+ 'slug': ('models.SlugField', [], {}),
+ 'sponsor': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'submitted': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
+ 'tshirt': ('models.CharField', [], {'max_length': '2'})
+ }
+ }
+
+ complete_apps = ['registration']
diff --git a/project/kiwipycon/registration/migrations/__init__.py b/project/kiwipycon/registration/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/registration/migrations/__init__.py
diff --git a/project/kiwipycon/registration/models.py b/project/kiwipycon/registration/models.py
new file mode 100644
index 0000000..17fdcca
--- /dev/null
+++ b/project/kiwipycon/registration/models.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django.db import models
+from django.contrib.auth.models import User
+
+from .utils import send_confirmation_payment_email
+from .utils import send_banking_fix_email
+
+from .labels import WIFI_CHOICES
+from .labels import WIFI_HELP
+
+SIZE_CHOICES = (
+ ('S', 'S'),
+ ('M', 'M'),
+ ('L', 'L'),
+ ('XL', 'XL'),
+ )
+
+class Wifi(models.Model):
+ """Defines wifi options at *PyCon"""
+ user = models.ForeignKey(User)
+ wifi = models.CharField(max_length=50, choices=WIFI_CHOICES,
+ help_text=WIFI_HELP, verbose_name="Laptop")
+
+class Registration(models.Model):
+ """Defines registration at *PyCon"""
+ slug = models.SlugField()
+ registrant = models.ForeignKey(User)
+ organisation = models.CharField(max_length=255, blank=True)
+ occupation = models.CharField(max_length=255, blank=True)
+ city = models.CharField(max_length=255, blank=True)
+ postcode = models.CharField(max_length=255, blank=True)
+# beverage = models.CharField(max_length=255, blank=True)
+# diet = models.CharField(max_length=255, blank=True)
+# sponsor = models.CharField(max_length=255, blank=True)
+ tshirt = models.CharField(max_length=2, choices=SIZE_CHOICES)
+# party = models.BooleanField(default=False)
+# discount = models.BooleanField(default=False)
+
+ # scipy.in specific
+ conference = models.BooleanField(default=False)
+ # scipy.in specific
+ tutorial = models.BooleanField(default=False)
+ # scipy.in specific
+ sprint = models.BooleanField(default=False)
+
+ amount = models.IntegerField(default=0)
+ allow_contact = models.BooleanField(default=False)
+# payment = models.BooleanField(default=False)
+ submitted = models.DateTimeField(auto_now_add=True)
+ last_mod = models.DateTimeField(auto_now=True)
+
+ def __unicode__(self):
+ return 'Registration for user: <%s %s> %s' % (self.registrant.first_name,
+ self.registrant.last_name, self.registrant.email)
+
+# def save(self, *args, **kwargs):
+# if(self.id):
+# old_reg = Registration.objects.get(pk=self.id)
+# if(old_reg.payment == False and self.payment == True \
+# and not self.sponsor):
+# send_confirmation_payment_email(self.registrant)
+# if(old_reg.slug.startswith('NZ') and self.slug.startswith('KPC') \
+# and not self.sponsor):
+# send_banking_fix_email(self.registrant, self.slug)
+# super(Registration, self).save(args, kwargs)
diff --git a/project/kiwipycon/registration/pdf.py b/project/kiwipycon/registration/pdf.py
new file mode 100644
index 0000000..7fec07a
--- /dev/null
+++ b/project/kiwipycon/registration/pdf.py
@@ -0,0 +1,20 @@
+import os
+
+from django.conf import settings
+from django.template.loader import render_to_string
+
+def save_invoice(user, registration, template_name):
+ content = render_to_string(template_name,
+ {'registration' : registration, 'user': user})
+ filename = '%s.html' % registration.slug
+ filepath = os.path.join(settings.USER_MEDIA_PDF, filename)
+ save_to_file(content, filepath)
+
+def save_to_pdf(content, filepath):
+ import pisa
+ pisa.CreatePDF(str(content), file(filepath, 'wb'))
+
+def save_to_file(content, filepath):
+ fout = file(filepath, 'wb')
+ fout.write(content)
+ fout.close()
diff --git a/project/kiwipycon/registration/tests.py b/project/kiwipycon/registration/tests.py
new file mode 100644
index 0000000..0ea28b2
--- /dev/null
+++ b/project/kiwipycon/registration/tests.py
@@ -0,0 +1,19 @@
+
+
+def test_save_to_pdf():
+ """
+ >>> from .pdf import save_invoice
+ >>> from django.db.models.loading import get_model
+ >>> userModel = get_model('auth', 'user')
+ >>> user = userModel(username='joe', email='joe@gmail.com',
+ ... first_name='Joe', last_name='Bloggs')
+ >>> user.save()
+ >>> regModel = get_model('registration', 'registration')
+ >>> registration = regModel(registrant=user, amount=40,
+ ... slug='NZPYCON-0001')
+ >>> registration.save()
+
+ >>> save_invoice(user, registration, 'registration/invoice.html')
+
+ """
+ pass
diff --git a/project/kiwipycon/registration/utils.py b/project/kiwipycon/registration/utils.py
new file mode 100644
index 0000000..58fe5f3
--- /dev/null
+++ b/project/kiwipycon/registration/utils.py
@@ -0,0 +1,215 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+# django
+from django.core.mail import EmailMessage
+
+def send_confirmation(registrant, invoice, password=None, sponsor=None,
+ amount=None):
+
+ message = EmailMessage()
+ message.subject = u'Registration to SciPy.in 2009'
+ message.from_email = u'admin@scipy.in'
+ message.to = [registrant.email]
+ name = '%s %s' % (registrant.first_name, registrant.last_name)
+ if name.strip() == '':
+ name = registrant.username
+
+ username = registrant.username
+ all = {'name': name,
+ 'password': password,
+ 'username': username}
+
+ if password:
+ message.body = confirmation_newuser % all
+ else:
+ message.body = confirmation_currentuser % all
+
+ message.send()
+
+def send_confirmation_payment_email(registrant):
+ message = EmailMessage()
+ message.subject = u'Registration payment to SciPy.in 2009'
+ message.from_email = u'admin@scipy.in'
+ message.to = [registrant.email]
+ name = '%s %s' % (registrant.first_name, registrant.last_name)
+ username = registrant.username
+ if name.strip() == '':
+ name = registrant.username
+ message.body = confirmation_payment % dict(name=name,
+ username=username)
+ message.send()
+
+def send_banking_fix_email(registrant, invoicenum):
+ message = EmailMessage()
+ message.subject = u'Registration invoice update to SciPy.in 2009'
+ message.from_email = u'admin@scipy.in'
+ message.to = [registrant.email]
+ name = '%s %s' % (registrant.first_name, registrant.last_name)
+ username = registrant.username
+ if name.strip() == '':
+ name = registrant.username
+ message.body = banking_fix % dict(name=name,
+ username=username, invoice=invoicenum)
+ message.send()
+
+banking_fix = """
+Dear %(name)s,
+
+Invoice update to Kiwi Pycon 2009.
+
+Ooops. We made the invoice number too long to be entered for internet banking.
+We have therefore changed the prefix and your new invoice number is:
+%(invoice)s
+
+You will find that your online invoice has been updated. Thanks for your
+patience.
+
+http://nz.pycon.org/invoice
+A pdf version here:
+http://nz.pycon.org/pdf_invoice
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+Your username, in case you've forgotten: %(username)s.
+
+If you have lost your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
+
+confirmation_payment = """
+Dear %(name)s,
+
+Welcome to Kiwi Pycon 2009.
+
+Your payment has been received and your attendence confirmed.
+
+Many thanks!
+
+You can view your invoice at:
+http://nz.pycon.org/invoice
+And a pdf version here:
+http://nz.pycon.org/pdf_invoice
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+Your username, in case you've forgotten: %(username)s.
+
+If you have lost your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
+
+confirmation_newuser = """
+Dear %(name)s,
+
+Welcome to Kiwi Pycon 2009. You may log in to
+http://nz.pycon.org/login using the following credentials:
+
+Username: %(username)s
+Password: %(password)s
+
+Amount: %(amount)s
+
+Your invoice number is: %(invoice)s
+
+Please use this number and your username as reference when
+making payment to the following:
+
+New Zealand Python User Group,
+06-0158-0360348-00
+The National Bank,
+Auckland University Branch
+PO Box 2132
+
+Thanks for your registration!
+
+You can view your invoice at:
+http://nz.pycon.org/invoice
+And a pdf version here:
+http://nz.pycon.org/pdf_invoice
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+If you lose your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
+
+confirmation_sponsoreduser = """
+Dear %(name)s,
+
+Welcome to Kiwi Pycon 2009.
+
+Your username is: %(username)s
+
+Your registration has been accepted as a guest of %(stype)s
+sponsor %(sname)s.
+
+Thanks!
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+If you have lost your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
+
+confirmation_sponsorednewuser = """
+Dear %(name)s,
+
+Welcome to Kiwi Pycon 2009.
+
+Your username is: %(username)s
+Your password is: %(password)s
+
+Your registration has been accepted as a guest of %(stype)s sponsor %(sname)s.
+
+Thanks!
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+If you lose your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
+
+confirmation_currentuser = """
+Dear %(name)s,
+
+Welcome to Kiwi Pycon 2009.
+
+Your invoice number is: %(invoice)s
+Your username is: %(username)s
+
+Amount: %(amount)s
+
+Please use this number and your username as reference when making payment
+to the following:
+
+New Zealand Python User Group,
+06-0158-0360348-00
+The National Bank,
+Auckland University Branch
+PO Box 2132
+
+Thanks for your registration!
+
+You can view your invoice at:
+http://nz.pycon.org/invoice
+And a pdf version here:
+http://nz.pycon.org/pdf_invoice
+
+Regards,
+The Kiwi Pycon 2009 Team
+
+If you have lost your password to the website please visit:
+http://nz.pycon.org/password-reset
+
+ """
diff --git a/project/kiwipycon/registration/views.py b/project/kiwipycon/registration/views.py
new file mode 100644
index 0000000..754dc15
--- /dev/null
+++ b/project/kiwipycon/registration/views.py
@@ -0,0 +1,336 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+import cStringIO as StringIO
+import csv
+
+# django
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template.loader import render_to_string
+from django.shortcuts import get_object_or_404
+from django.template import RequestContext
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse
+
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.models import User
+from django.core.exceptions import ObjectDoesNotExist
+
+#kiwipycon
+from project.kiwipycon.utils import set_message_cookie
+from project.kiwipycon.utils import slugify
+from project.kiwipycon.user.models import UserProfile
+from project.kiwipycon.user.utils import kiwipycon_createregistrant
+from project.kiwipycon.user.forms import RegistrantForm
+from project.kiwipycon.sponsor.models import Sponsor
+from project.kiwipycon.talk.models import Talk
+
+from .models import Registration
+from .models import Wifi
+from .forms import RegistrationSubmitForm
+from .forms import RegistrationEditForm
+from .forms import RegistrationAdminSelectForm
+from .forms import WifiForm
+from .utils import send_confirmation
+
+from .forms import IC
+
+REG_TOTAL = 1000
+
+@login_required
+def download_csv(request,
+ template_name = 'registration/download-csv.html'):
+ """
+ """
+ if not request.user.is_staff:
+ redirect_to = reverse('kiwipycon_login')
+ if request.method == "POST":
+ form = RegistrationAdminSelectForm(request.POST)
+ if form.is_valid():
+ conference = form.cleaned_data['by_conference']
+ tutorial = form.cleaned_data['by_tutorial']
+ sprint = form.cleaned_data['by_sprint']
+ amount = form.cleaned_data['by_amount']
+ tshirt = form.cleaned_data['by_tshirt']
+ order_by = form.cleaned_data['order_by']
+ include = form.cleaned_data['include']
+ q = Registration.objects.all()
+ if conference == 'conference':
+ q = q.filter(conference=True)
+ elif conference == 'no conference':
+ q = q.filter(conference=False)
+ elif tutorial == 'tutorial':
+ q = q.filter(tutorial=True)
+ elif tutorial == 'no tutorial':
+ q = q.filter(tutorial=False)
+ if sprint == 'sprint':
+ q = q.filter(sprint=True)
+ if sprint == 'no sprint':
+ q = q.filter(sprint=False)
+ elif tshirt != 'all':
+ q = q.filter(tshirt=tshirt)
+ q = q.order_by('registrant__email')
+ query = q.query
+ results = list(q)
+ if include == []:
+ # default to include all fields
+ include = [i[0] for i in IC]
+ if results:
+ response = HttpResponse(mimetype='text/csv')
+ response['Content-Disposition'] = 'attachment; filename=registrations.csv'
+ output = csv.writer(response)
+ output.writerow([h for h in include])
+ for row in results:
+ conference = row.conference == True and 'yes' or 'no'
+ tutorial = row.tutorial == True and 'yes' or 'no'
+ sprint = row.sprint == True and 'yes' or 'no'
+ wrow = []
+ if 'Name' in include:
+ wrow.append(
+ row.registrant.get_full_name().encode('utf-8'))
+ if 'Email' in include:
+ wrow.append(row.registrant.email.encode('utf-8'))
+ if 'Organisation' in include:
+ wrow.append(row.organisation.encode('utf-8'))
+ if 'Conference' in include:
+ wrow.append(conference)
+ if 'Tutorial' in include:
+ wrow.append(tutorial)
+ if 'Sprint' in include:
+ wrow.append(sprint)
+ if 'T-size' in include:
+ wrow.append(row.tshirt)
+ output.writerow(wrow)
+ return response
+ else:
+ no_results = u'No results found for the query'
+
+ else:
+ form = RegistrationAdminSelectForm()
+ return render_to_response(template_name, RequestContext(request,
+ locals()))
+
+# NOT REQUIRED FOR SciPy.in
+@login_required
+def invoice(request, template_name='registration/invoice.html'):
+ user = request.user
+ registration = get_object_or_404(Registration, registrant=user)
+ if registration.sponsor:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'You are a sponsored guest, no payment required.')
+ return render_to_response(template_name, RequestContext(request,
+ {'registration' : registration, 'user': user}))
+
+@login_required
+def pdf_invoice(request, template_name='registration/invoice.html'):
+ user = request.user
+ registration = get_object_or_404(Registration, registrant=user)
+ if registration.sponsor:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'You are a sponsored guest, no payment required.')
+ content = render_to_string(template_name,
+ {'registration' : registration, 'user': user})
+ result = StringIO.StringIO()
+ import ho.pisa
+ pdf = ho.pisa.pisaDocument(StringIO.StringIO(content.encode("UTF-8")),result)
+ if not pdf.err:
+ return HttpResponse(result.getvalue(), mimetype='application/pdf')
+ return HttpResponse("Gremlins ate your invoice, please try html" \
+ " version")
+
+
+def registrations(request,
+ template_name='registration/registrations.html'):
+ """Simple page to count registrations"""
+ #registrations = Registration.objects.filter(payment=True).count()
+ registrations = Registration.objects.all().count()
+ return render_to_response(template_name, RequestContext(request,
+ {
+ 'over_reg' : registrations >= REG_TOTAL and True or False,
+ 'registrations' : registrations}))
+
+@login_required
+def edit_registration(request, id,
+ template_name='registration/edit-registration.html'):
+ '''Allows users that submitted a registration to edit it.
+ '''
+ reg = Registration.objects.get(pk=id)
+
+ if reg.registrant != request.user:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Redirected because the registration you selected' \
+ + ' is not your own.')
+
+ if request.method == 'POST':
+ form = RegistrationEditForm(data=request.POST)
+ if form.is_valid():
+ reg.organisation = form.data.get('organisation')
+ reg.occupation = form.data.get('occupation')
+ reg.city = form.data.get('city')
+ reg.tshirt = form.data.get('tshirt')
+ reg.allow_contact = form.data.get('allow_contact') and True or False
+ reg.conference = form.data.get('conference') and True or False
+ reg.tutorial = form.data.get('tutorial') and True or False
+ reg.sprint = form.data.get('sprint') and True or False
+ reg.save()
+ # Saved.. redirect
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Your changes have been saved.')
+ else:
+ form = RegistrationEditForm(initial={
+ 'id' : id,
+ 'organisation' : reg.organisation,
+ 'occupation' : reg.occupation,
+ 'city' : reg.city,
+ 'tshirt' : reg.tshirt,
+ 'conference': reg.conference,
+ 'tutorial': reg.tutorial,
+ 'postcode' : reg.postcode,
+ 'sprint' : reg.sprint,
+ 'allow_contact' : reg.allow_contact,
+ })
+
+ return render_to_response(template_name, RequestContext(request, locals()))
+
+def submit_registration(request,
+ template_name='registration/submit-registration.html'):
+ '''Allows user to edit registration
+ '''
+ user = request.user
+ reg_count = Registration.objects.all().count()
+ if user.is_authenticated():
+ try:
+ profile = user.get_profile()
+ except:
+ profile, new = UserProfile.objects.get_or_create(user=user)
+ if new:
+ profile.save()
+ try:
+ registration = Registration.objects.get(registrant=user)
+ if registration:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'You have already been registered.')
+
+ except ObjectDoesNotExist:
+ pass
+
+ message = None
+
+ if request.method == 'POST':
+ registration_form = RegistrationSubmitForm(data=request.POST)
+ registrant_form = RegistrantForm(data=request.POST)
+ wifi_form = WifiForm(data=request.POST)
+
+ if request.POST.get('action', None) == 'login':
+ login_form = AuthenticationForm(data=request.POST)
+ if login_form.is_valid():
+
+ from django.contrib.auth import login
+ login(request, login_form.get_user())
+
+ redirect_to = reverse('kiwipycon_submit_registration')
+ return set_message_cookie(redirect_to,
+ msg = u'You have been logged in please continue' + \
+ 'with registration.')
+
+ newuser = None
+ passwd = None
+ if not user.is_authenticated():
+ if registrant_form.is_valid():
+ newuser = kiwipycon_createregistrant(request, registrant_form.data)
+ # Log in user
+ passwd = User.objects.make_random_password()
+ newuser.set_password(passwd)
+ newuser.save()
+ from django.contrib.auth import authenticate
+ user = authenticate(username=newuser.username, password=passwd)
+
+ from django.contrib.auth import login
+ login(request, user)
+
+ newuser = user
+
+ else:
+ newuser = user
+
+ if registration_form.is_valid() and newuser:
+ allow_contact = registration_form.data.get('allow_contact') and \
+ True or False
+ conference = registration_form.data.get('conference') and \
+ True or False
+ tutorial = registration_form.data.get('tutorial') and \
+ True or False
+ sprint = registration_form.data.get('sprint') and \
+ True or False
+
+ registrant = User.objects.get(pk=newuser.id)
+
+ presenter = None
+ talks = Talk.objects.filter(
+ speaker=registrant).filter(approved=True)
+ if talks:
+ for talk in talks:
+ if talk.duration == '30':
+ presenter = True
+ elif talk.duration == '60':
+ presenter = True
+
+ reg = Registration(
+ # slug = newuser.username,
+ registrant = registrant,
+ organisation = registration_form.data.get('organisation'),
+ occupation = registration_form.data.get('occupation'),
+ city = registration_form.data.get('city'),
+ tshirt = registration_form.data.get('tshirt'),
+ postcode = registration_form.cleaned_data.get('postcode'),
+ allow_contact = allow_contact,
+ conference = conference,
+ tutorial = tutorial,
+ sprint = sprint)
+ reg.save()
+
+ # get id and use as slug and invoice number
+ id = reg.id
+ slug = 'KPC09%03d' % id
+ reg.slug = slug
+ reg.save()
+
+ # additional tasks:
+ if wifi_form.is_valid():
+ wifi = wifi_form.save(registrant)
+
+ # 1. include random password if we are a new user
+ if passwd:
+ send_confirmation(registrant, slug, password=passwd)
+ else:
+ # 2. send user email with registration id
+ send_confirmation(registrant, slug)
+
+ redirect_to = reverse('kiwipycon_registrations')
+ return set_message_cookie(redirect_to,
+ msg = u'Thank you, your registration has been submitted '\
+ 'and an email has been sent with payment details.')
+
+ else:
+ registration_form = RegistrationSubmitForm()
+ registrant_form = RegistrantForm()
+ wifi_form = WifiForm()
+
+ login_form = AuthenticationForm()
+
+
+ return render_to_response(template_name, RequestContext(request, {
+ 'registration_form': registration_form,
+ 'registrant_form' : registrant_form,
+ 'over_reg' : reg_count >= REG_TOTAL and True or False,
+ 'wifi_form' : wifi_form,
+ 'message' : message,
+ 'login_form' : login_form
+ }))
diff --git a/project/kiwipycon/sponsor/__init__.py b/project/kiwipycon/sponsor/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/sponsor/__init__.py
diff --git a/project/kiwipycon/sponsor/admin.py b/project/kiwipycon/sponsor/admin.py
new file mode 100644
index 0000000..95735d9
--- /dev/null
+++ b/project/kiwipycon/sponsor/admin.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django.contrib import admin
+
+#kiwipycon
+from .models import Sponsor
+
+class SponsorAdmin(admin.ModelAdmin):
+ list_display = ('title', 'type', 'contact_name', 'contact_email', 'contact_phone',
+ 'guests', 'url', 'logo')
+
+admin.site.register(Sponsor, SponsorAdmin)
+
diff --git a/project/kiwipycon/sponsor/migrations/0001_initial.py b/project/kiwipycon/sponsor/migrations/0001_initial.py
new file mode 100644
index 0000000..2512f1a
--- /dev/null
+++ b/project/kiwipycon/sponsor/migrations/0001_initial.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from project.kiwipycon.sponsor.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'Sponsor'
+ db.create_table('sponsor_sponsor', (
+ ('id', models.AutoField(primary_key=True)),
+ ('slug', models.SlugField()),
+ ('title', models.CharField(max_length=255)),
+ ('type', models.CharField(max_length=10)),
+ ('url', models.URLField(verify_exists=False, blank=True)),
+ ('contact_name', models.CharField(max_length=255)),
+ ('contact_phone', models.CharField(max_length=255)),
+ ('contact_email', models.CharField(max_length=255)),
+ ('logo', models.CharField(max_length=64, blank=True)),
+ ('guests', models.IntegerField()),
+ ))
+ db.send_create_signal('sponsor', ['Sponsor'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Sponsor'
+ db.delete_table('sponsor_sponsor')
+
+
+
+ models = {
+ 'sponsor.sponsor': {
+ 'contact_email': ('models.CharField', [], {'max_length': '255'}),
+ 'contact_name': ('models.CharField', [], {'max_length': '255'}),
+ 'contact_phone': ('models.CharField', [], {'max_length': '255'}),
+ 'guests': ('models.IntegerField', [], {}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'logo': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'slug': ('models.SlugField', [], {}),
+ 'title': ('models.CharField', [], {'max_length': '255'}),
+ 'type': ('models.CharField', [], {'max_length': '10'}),
+ 'url': ('models.URLField', [], {'verify_exists': 'False', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['sponsor']
diff --git a/project/kiwipycon/sponsor/migrations/__init__.py b/project/kiwipycon/sponsor/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/sponsor/migrations/__init__.py
diff --git a/project/kiwipycon/sponsor/models.py b/project/kiwipycon/sponsor/models.py
new file mode 100644
index 0000000..68d8b5b
--- /dev/null
+++ b/project/kiwipycon/sponsor/models.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django.db import models
+from django.conf import settings
+
+TYPE_CHOICES = (
+ ('gold', 'Gold'),
+ ('silver', 'Silver'),
+ ('schwag', 'Schwag'),
+ )
+
+class Sponsor(models.Model):
+ """Defines sponsors for *PyCon"""
+ slug = models.SlugField()
+ title = models.CharField(max_length=255)
+ type = models.CharField(max_length=10, choices=TYPE_CHOICES)
+ contact_name = models.CharField(max_length=255)
+ contact_email = models.CharField(max_length=255)
+ contact_phone = models.CharField(max_length=255)
+ url = models.URLField(blank=True, verify_exists=False)
+ logo = models.CharField(max_length=64, blank=True)
+ guests = models.IntegerField()
+
+ def __unicode__(self):
+ return self.title
+
diff --git a/project/kiwipycon/sponsor/views.py b/project/kiwipycon/sponsor/views.py
new file mode 100644
index 0000000..a6f5ad2
--- /dev/null
+++ b/project/kiwipycon/sponsor/views.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+# django
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+def schwag_sponsors(request,
+ template_name = 'sponsor/schwag.html'):
+ """Simple page to display schwag sponsors
+
+ The list is generated in kiwipycon.context_processors
+ """
+ return render_to_response(template_name, RequestContext(request,
+ {}))
+
diff --git a/project/kiwipycon/talk/__init__.py b/project/kiwipycon/talk/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/talk/__init__.py
diff --git a/project/kiwipycon/talk/admin.py b/project/kiwipycon/talk/admin.py
new file mode 100644
index 0000000..73c8d6a
--- /dev/null
+++ b/project/kiwipycon/talk/admin.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django.contrib
+from django.contrib import admin
+
+#kiwipycon
+from .models import Talk
+
+class TalkAdmin(admin.ModelAdmin):
+ list_display = ('title', 'speaker', 'topic', 'duration', 'audience', 'approved')
+ list_filter = ('approved', 'audience', 'topic', 'speaker')
+ search_fields = ('slug', 'title', 'abstract')
+ prepopulate_from = {'slug': ('title',)}
+ fieldsets = (
+ ('Details', {
+ 'fields': ('slug', 'title', 'abstract', 'speaker')
+ }),
+ ('Information', {
+ 'fields': ('topic', 'duration', 'audience', 'approved')
+ }),
+ )
+admin.site.register(Talk, TalkAdmin)
diff --git a/project/kiwipycon/talk/forms.py b/project/kiwipycon/talk/forms.py
new file mode 100644
index 0000000..5059285
--- /dev/null
+++ b/project/kiwipycon/talk/forms.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django import forms
+
+#django.contrib
+from django.contrib.auth.models import User
+
+#tagging
+from tagging.forms import TagField
+
+#kiwipycon
+#from .models import TOPIC_CHOICES
+from .models import DURATION_CHOICES
+from .models import AUDIENCE_CHOICES
+
+
+class TalkSubmitForm(forms.Form):
+ """Submit talk form
+ """
+ authors_bio = forms.CharField(widget=forms.Textarea, required=True,
+ label=u'Author(s) and short bio',
+ help_text=u'(include a bit about your qualifications regarding your presentation topic)')
+ contact = forms.EmailField(required=True, label=u'E-Mail ID',
+ help_text=u'Provide your email ID',
+ max_length=1024,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ title = forms.CharField(required=True, label=u'Talk title',
+ help_text=u'Title of proposed presentation',
+ max_length=1024,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ abstract = forms.CharField(widget=forms.Textarea, required=True,
+ help_text=u'Summary of proposed presentation (around 30 words)')
+# outline = forms.CharField(widget=forms.Textarea, required=True,
+# help_text=u'Outline of proposed presentation (around 200 words)')
+# topic = forms.ChoiceField(choices=TOPIC_CHOICES,
+# label=u'Topic', help_text=u'Select one of the available options or enter other topic')
+# topic_other = forms.CharField(label=u'Other topic',
+# help_text=u'Description of your topic',
+# max_length=255,
+# required=False,
+# widget=forms.TextInput(attrs={'size':'50'}))
+ topic = forms.CharField(label=u'Topic',
+ help_text=u'Description of your topic or comma separated tags',
+ max_length=255,
+ required=False,
+ widget=forms.TextInput(attrs={'size':'50'}))
+ duration = forms.ChoiceField(choices=DURATION_CHOICES, required=True,
+ label=u'Preferred timeslot', help_text=u'Select preferred time slot')
+ audience = forms.ChoiceField(choices=AUDIENCE_CHOICES, label=u'Itended audience',
+ help_text=u'Select one of the available options or enter other type of intended audience')
+# audience_other = forms.CharField(label=u'Other intended audience',
+# help_text=u'Description of intended audience (ie. Discordians)',
+# max_length=128,
+# required=False,
+# widget=forms.TextInput(attrs={'size':'50'}))
+# tags = TagField(max_length=255,
+# widget=forms.TextInput(attrs={'size':'50'}))
+
+class TalkEditForm(TalkSubmitForm):
+ id = forms.CharField(widget=forms.HiddenInput)
diff --git a/project/kiwipycon/talk/migrations/0001_initial.py b/project/kiwipycon/talk/migrations/0001_initial.py
new file mode 100644
index 0000000..961abcf
--- /dev/null
+++ b/project/kiwipycon/talk/migrations/0001_initial.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from project.kiwipycon.talk.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'Talk'
+ db.create_table('talk_talk', (
+ ('id', models.AutoField(primary_key=True)),
+ ('slug', models.SlugField()),
+ ('speaker', models.ForeignKey(orm['auth.User'])),
+ ('authors_bio', models.TextField()),
+ ('contact', models.CharField(max_length=1024)),
+ ('title', models.CharField(max_length=1024)),
+ ('abstract', models.TextField()),
+ ('outline', models.TextField()),
+ ('topic', models.CharField(blank=True, max_length=255)),
+ ('topic_other', models.CharField(max_length=255, blank=True)),
+ ('duration', models.CharField(max_length=3)),
+ ('audience', models.CharField(blank=True, max_length=32)),
+ ('audience_other', models.CharField(max_length=128, blank=True)),
+ ('approved', models.BooleanField(default=False)),
+ ('submitted', models.DateTimeField(auto_now_add=True)),
+ ('last_mod', models.DateTimeField(auto_now=True)),
+ ('tags', TagField(blank=True)),
+ ))
+ db.send_create_signal('talk', ['Talk'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Talk'
+ db.delete_table('talk_talk')
+
+
+
+ models = {
+ 'auth.user': {
+ '_stub': True,
+ 'id': ('models.AutoField', [], {'primary_key': 'True'})
+ },
+ 'talk.talk': {
+ 'abstract': ('models.TextField', [], {}),
+ 'approved': ('models.BooleanField', [], {'default': 'False'}),
+ 'audience': ('models.CharField', [], {'blank': 'True', 'max_length': '32'}),
+ 'audience_other': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'authors_bio': ('models.TextField', [], {}),
+ 'contact': ('models.CharField', [], {'max_length': '1024'}),
+ 'duration': ('models.CharField', [], {'max_length': '3'}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'last_mod': ('models.DateTimeField', [], {'auto_now': 'True'}),
+ 'outline': ('models.TextField', [], {}),
+ 'slug': ('models.SlugField', [], {}),
+ 'speaker': ('models.ForeignKey', ['User'], {}),
+ 'submitted': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
+ 'tags': ('TagField', [], {'blank': 'True'}),
+ 'title': ('models.CharField', [], {'max_length': '1024'}),
+ 'topic': ('models.CharField', [], {'blank': 'True', 'max_length': '255'}),
+ 'topic_other': ('models.CharField', [], {'max_length': '255', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['talk']
diff --git a/project/kiwipycon/talk/migrations/__init__.py b/project/kiwipycon/talk/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/talk/migrations/__init__.py
diff --git a/project/kiwipycon/talk/models.py b/project/kiwipycon/talk/models.py
new file mode 100644
index 0000000..62ae89b
--- /dev/null
+++ b/project/kiwipycon/talk/models.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django.db import models
+from django.contrib.auth.models import User
+
+#tagging
+from tagging import register
+from tagging.fields import TagField
+from tagging.utils import parse_tag_input
+
+DURATION_CHOICES = (
+ ('10', 'Lightning Talk (10 mins)'),
+ ('20', 'Short Talk (20 mins)'),
+ ('30', 'Standard Talk (30 mins)'),
+ )
+
+AUDIENCE_CHOICES = (
+ ('nonprogrammers', 'non-programmer'),
+ ('beginers', 'beginning programmer'),
+ ('intermediate', 'intermediate programmer'),
+ ('advanced', 'advanced programmer'),
+ )
+
+#TOPIC_CHOICES = (
+# ('Core Python', 'Core Python'),
+# ('Other implementations: Jython, IronPython, PyPy, and Stackless', 'Other implementations: Jython, IronPython, PyPy, and Stackless'),
+# ('Python libraries and extensions', 'Python libraries and extensions'),
+# ('Python 3k', 'Python 3k'),
+# ('Databases', 'Databases'),
+# ('Documentation', 'Documentation'),
+# ('GUI Programming', 'GUI Programming'),
+# ('Game Programming', 'Game Programming'),
+# ('Network Programming', 'Network Programming'),
+# ('Open Source Python projects', 'Open Source Python projects'),
+# ('Packaging Issues', 'Packaging Issues'),
+# ('Programming Tools', 'Programming Tools'),
+# ('Project Best Practices', 'Project Best Practices'),
+# ('Embedding and Extending', 'Embedding and Extending'),
+# ('Science and Maths', 'Science and Maths'),
+# ('Web-based Systems', 'Web-based Systems'),
+#)
+
+class Talk(models.Model):
+ """Defines talks at *PyCon"""
+ slug = models.SlugField()
+ speaker = models.ForeignKey(User)
+ authors_bio = models.TextField()
+ contact = models.EmailField()
+ title = models.CharField(max_length=1024)
+ abstract = models.TextField()
+# outline = models.TextField()
+ topic = models.CharField(max_length=255,
+ #choices=TOPIC_CHOICES,
+ blank=True)
+ #topic_other = models.CharField(max_length=255, blank=True)
+ duration = models.CharField(max_length=3, choices=DURATION_CHOICES)
+ audience = models.CharField(max_length=32, choices=AUDIENCE_CHOICES, blank=True)
+# audience_other = models.CharField(max_length=128, blank=True)
+ approved = models.BooleanField(default=False)
+ submitted = models.DateTimeField(auto_now_add=True)
+ last_mod = models.DateTimeField(auto_now=True)
+# tags = TagField(blank=True)
+
+ def __unicode__(self):
+ return self.title
+
+ def get_tag_list(self):
+ return parse_tag_input(self.tags)
+
+# register(Talk) # saving talk failed - see:
+# http://code.google.com/p/django-tagging/issues/detail?id=152
diff --git a/project/kiwipycon/talk/templatetags/__init__.py b/project/kiwipycon/talk/templatetags/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/project/kiwipycon/talk/templatetags/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/project/kiwipycon/talk/templatetags/talk_extras.py b/project/kiwipycon/talk/templatetags/talk_extras.py
new file mode 100644
index 0000000..e28f2bf
--- /dev/null
+++ b/project/kiwipycon/talk/templatetags/talk_extras.py
@@ -0,0 +1,8 @@
+from django import template
+
+register = template.Library()
+
+def choice(choices, value):
+ return choices[value]
+
+register.filter('choice', choice)
diff --git a/project/kiwipycon/talk/views.py b/project/kiwipycon/talk/views.py
new file mode 100644
index 0000000..a11be54
--- /dev/null
+++ b/project/kiwipycon/talk/views.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+# python imports
+from urlparse import urlparse
+
+# django
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.core.urlresolvers import reverse
+from django.views.generic.list_detail import object_list
+from django.views.generic.list_detail import object_detail
+
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.models import User
+
+# PIL
+from PIL import Image
+
+# tagging
+from tagging.models import Tag
+
+#kiwipycon
+from project.kiwipycon.utils import set_message_cookie
+from project.kiwipycon.utils import slugify
+from project.kiwipycon.user.models import UserProfile
+from project.kiwipycon.user.forms import RegisterForm
+from project.kiwipycon.user.utils import kiwipycon_createuser
+
+from .models import Talk
+from .forms import TalkSubmitForm
+from .forms import TalkEditForm
+from .models import DURATION_CHOICES
+from .models import AUDIENCE_CHOICES
+
+def list_talks(request):
+ objects = Talk.objects.filter(approved=True)
+ extra_context = dict(count=objects.count())
+ return object_list(request, objects, extra_context=extra_context)
+
+def talk(request, id):
+ objects = Talk.objects.filter(approved=True)
+ audience = {}
+ for choice in AUDIENCE_CHOICES:
+ audience[choice[0]] = choice[1]
+ extra_context = dict(choices=audience)
+ return object_detail(request, objects, id, extra_context=extra_context)
+
+@login_required
+def edit_talk(request, id, template_name='talk/edit-talk.html'):
+ '''Allows users that submitted a talk to edit it until the talk is approved.
+ '''
+ talk = Talk.objects.get(pk=id)
+
+ if talk.approved == True:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Sorry but you cannot edit the talk once'\
+ + ' it has been accepted.')
+ if talk.speaker != request.user:
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Redirected to account because the talk you selected' \
+ + ' is not your own.')
+
+ if request.method == 'POST':
+ form = TalkEditForm(data=request.POST)
+ if form.is_valid():
+ talk.slug = slugify(form.data.get('title'))
+ talk.authors_bio = form.data.get('authors_bio')
+ talk.contact = form.data.get('contact')
+ talk.title = form.data.get('title')
+ talk.abstract = form.data.get('abstract')
+ talk.outline = form.data.get('outline')
+ talk.topic = form.data.get('topic')
+ talk.topic_other = form.data.get('topic_other')
+ talk.duration = form.data.get('duration')
+ talk.audience = form.data.get('audience')
+ talk.audience_other = form.data.get('audience_other')
+ talk.tags = form.data.get('tags')
+ talk.save()
+ # Saved.. redirect
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Your changes have been saved.')
+ else:
+ form = TalkEditForm(initial={
+ 'id' : id,
+ 'authors_bio' : talk.authors_bio,
+ 'contact' : talk.contact,
+ 'title' : talk.title,
+ 'abstract' : talk.abstract,
+ 'outline' : talk.outline,
+ 'topic' : talk.topic,
+ 'topic_other' : talk.topic_other,
+ 'duration' : talk.duration,
+ 'audience' : talk.audience,
+ 'audience_other' : talk.audience_other,
+ 'tags' : talk.tags,
+ })
+
+ return render_to_response(template_name, RequestContext(request, locals()))
+
+@login_required()
+def submit_talk(request, template_name='talk/submit-talk.html'):
+ '''Allows user to edit profile
+ '''
+ user = request.user
+ if user.is_authenticated():
+ try:
+ profile = user.get_profile()
+ except:
+ profile, new = UserProfile.objects.get_or_create(user=user)
+ if new:
+ profile.save()
+ message = None
+
+ if request.method == 'POST':
+ talk_form = TalkSubmitForm(data=request.POST)
+
+ register_form = RegisterForm(data=request.POST,
+ files=request.FILES)
+
+ if request.POST.get('action', None) == 'login':
+ login_form = AuthenticationForm(data=request.POST)
+ if login_form.is_valid():
+
+ from django.contrib.auth import login
+ login(request, login_form.get_user())
+
+ redirect_to = reverse('kiwipycon_submit_talk')
+ return set_message_cookie(redirect_to,
+ msg = u'You have been logged in.')
+
+ if request.POST.get('action', None) == 'register':
+ # add the new user
+ if register_form.is_valid():
+
+ user = kiwipycon_createuser(request, register_form.data)
+
+ if talk_form.is_valid():
+ if user.is_authenticated():
+ title = talk_form.data.get('title')
+ talk = Talk.objects.create(
+ slug = slugify(title),
+ speaker = User.objects.get(pk=user.id),
+ authors_bio = talk_form.data.get('authors_bio'),
+ contact = talk_form.data.get('contact'),
+ title = talk_form.data.get('title'),
+ abstract = talk_form.data.get('abstract'),
+ outline = talk_form.data.get('outline'),
+ topic = talk_form.data.get('topic'),
+ topic_other = talk_form.data.get('topic_other'),
+ duration = talk_form.data.get('duration'),
+ audience = talk_form.data.get('audience'),
+ audience_other = talk_form.data.get('audience_other'),
+ approved = False,
+ tags = talk_form.data.get('tags'))
+ talk.save()
+ # Saved, ... redirect back to account
+ redirect_to = reverse('kiwipycon_account')
+ return set_message_cookie(redirect_to,
+ msg = u'Thanks, your talk has been submitted.')
+ else:
+ redirect_to = reverse('kiwipycon_submit_talk')
+ return set_message_cookie(redirect_to,
+ msg = u'Something is wrong here.')
+
+ else:
+ talk_form = TalkSubmitForm()
+ register_form = RegisterForm()
+ login_form = AuthenticationForm()
+
+
+ return render_to_response(template_name, RequestContext(request, {
+ 'talk_form': talk_form,
+ 'register_form' : register_form,
+ 'message' : message,
+ 'login_form' : login_form
+ }))
+
diff --git a/project/kiwipycon/user/__init__.py b/project/kiwipycon/user/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/user/__init__.py
diff --git a/project/kiwipycon/user/admin.py b/project/kiwipycon/user/admin.py
new file mode 100644
index 0000000..c72a5b5
--- /dev/null
+++ b/project/kiwipycon/user/admin.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+from django.contrib import admin
+
+#kiwipycon
+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/kiwipycon/user/forms.py b/project/kiwipycon/user/forms.py
new file mode 100644
index 0000000..46ad2f6
--- /dev/null
+++ b/project/kiwipycon/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/kiwipycon/user/migrations/0001_initial.py b/project/kiwipycon/user/migrations/0001_initial.py
new file mode 100644
index 0000000..8cb8788
--- /dev/null
+++ b/project/kiwipycon/user/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+from south.db import db
+from django.db import models
+from project.kiwipycon.user.models import *
+
+class Migration:
+
+ def forwards(self, orm):
+
+ # Adding model 'UserProfile'
+ db.create_table('user_userprofile', (
+ ('id', models.AutoField(primary_key=True)),
+ ('user', models.ForeignKey(orm['auth.User'], unique=True)),
+ ('url', models.URLField(verify_exists=False, blank=True)),
+ ('photo', models.CharField(max_length=64, blank=True)),
+ ('about', models.TextField(blank=True)),
+ ))
+ db.send_create_signal('user', ['UserProfile'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'UserProfile'
+ db.delete_table('user_userprofile')
+
+
+
+ models = {
+ 'auth.user': {
+ '_stub': True,
+ 'id': ('models.AutoField', [], {'primary_key': 'True'})
+ },
+ 'user.userprofile': {
+ 'about': ('models.TextField', [], {'blank': 'True'}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'photo': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'url': ('models.URLField', [], {'verify_exists': 'False', 'blank': 'True'}),
+ 'user': ('models.ForeignKey', ['User'], {'unique': 'True'})
+ }
+ }
+
+ complete_apps = ['user']
diff --git a/project/kiwipycon/user/migrations/__init__.py b/project/kiwipycon/user/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project/kiwipycon/user/migrations/__init__.py
diff --git a/project/kiwipycon/user/models.py b/project/kiwipycon/user/models.py
new file mode 100644
index 0000000..85cf762
--- /dev/null
+++ b/project/kiwipycon/user/models.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#django
+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
+
+class UserProfile(models.Model):
+ """
+ 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)
+
+def add_profile(sender, instance, signal, *args, **kwargs):
+ """Create user profile on create of new user"""
+ if not instance.is_superuser:
+ try:
+ profile, new = UserProfile.objects.get_or_create(user=instance)
+ if new:
+ profile.save()
+ except:
+ pass
+
+post_save.connect(add_profile, sender=User, weak=False)
diff --git a/project/kiwipycon/user/utils.py b/project/kiwipycon/user/utils.py
new file mode 100644
index 0000000..b912a7b
--- /dev/null
+++ b/project/kiwipycon/user/utils.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+#python imports
+import os
+
+#django
+from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist
+
+#django.contrib
+from django.contrib.auth.models import User
+
+#PIL
+from PIL import Image
+
+
+def kiwipycon_createregistrant(request, data):
+ """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()
+
+ return user
+
+def kiwipycon_createuser(request, data):
+ """Create user"""
+ 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
+ from django.contrib.auth import authenticate
+ user = authenticate(username=username, password=password)
+
+ from django.contrib.auth import login
+ login(request, user)
+
+ profile = user.get_profile()
+ photo = request.FILES.get('photo', None)
+ filename= None
+ if photo:
+ filename = handle_uploaded_photo(user, request.FILES['photo'])
+ if filename:
+ profile.photo = filename
+ print photo, filename
+
+ profile.url = data.get("url")
+ profile.about = data.get("about")
+ profile.save()
+
+ return user
+
+def handle_uploaded_photo(user, ufile):
+ usermedia = settings.USER_MEDIA_ROOT
+ filename = ufile.name
+ ext = filename.split('.')[-1]
+ filesize = ufile.size
+ 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))
+ print((0, t, nw, t + nh))
+ 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/kiwipycon/user/views.py b/project/kiwipycon/user/views.py
new file mode 100644
index 0000000..e9a0454
--- /dev/null
+++ b/project/kiwipycon/user/views.py
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+#python
+from urlparse import urlparse
+import urllib
+import os
+
+#django
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.core.urlresolvers import reverse
+from django.db.models.signals import post_save
+
+#django.contrib
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.forms import PasswordChangeForm
+from django.core.exceptions import ObjectDoesNotExist
+
+#PIL
+from PIL import Image
+
+#kiwipycon
+from project.kiwipycon.utils import set_message_cookie
+from project.kiwipycon.talk.models import Talk
+from project.kiwipycon.registration.models import Registration
+from project.kiwipycon.registration.models import Wifi
+from project.kiwipycon.registration.forms import WifiForm
+from project.kiwipycon.sponsor.models import Sponsor
+
+from .utils import kiwipycon_createuser
+from .utils import handle_uploaded_photo
+from .forms import RegisterForm
+from .forms import EditProfileForm
+from .forms import UsernameForm
+
+@login_required
+def account(request, 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
+
+ if profile.photo:
+ photo = os.path.join(settings.USER_MEDIA_URL, profile.photo)
+ else:
+ photo = '/img/user-default.png'
+
+ qstring = ""
+
+ wifi_comment = None
+ if wifiobj:
+ wifi_form = False
+ else:
+ if request.method == "POST":
+ wifi_form = WifiForm(request.POST)
+ if wifi_form.is_valid():
+ wifi_form.save(user)
+ wifi_comment = 'Thanks, your wifi preference has been saved'
+ wifi_form = None
+ else:
+ wifi_form = WifiForm()
+
+ return render_to_response(template_name, RequestContext(request, {
+ "form" : wifi_form, "comment": wifi_comment,
+ "user" : user, "profile" : profile, "photo" : photo,
+ "talks" : talks, "registration" : registration,
+ }))
+
+@login_required
+def edit_profile(request, 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("kiwipycon_account")
+ 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, {
+ "form": form
+ }))
+
+def login(request, 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("kiwipycon_account")
+ 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("kiwipycon_account")
+
+ 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 = kiwipycon_createuser(request, register_form.data)
+
+ redirect_to = request.POST.get("next")
+ if not redirect_to or '//' in redirect_to or ' ' in redirect_to:
+ redirect_to = reverse("kiwipycon_account")
+
+ 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("kiwipycon_account")
+ # 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, {
+ "login_form" : login_form,
+ "login_form_errors" : login_form_errors,
+ "register_form" : register_form,
+ "next_url" : next_url,
+ }))
+
+def logout(request):
+ """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 = '/'
+ return set_message_cookie(redirect_to, msg = u"You have been logged out.")
+
+@login_required
+def password(request, 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("kiwipycon_account")
+ 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, {
+ "form" : form
+ }))
+
+@login_required
+def username(request, 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("kiwipycon_account")
+ 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, {
+ "form": username_form
+ }))
+
diff --git a/project/kiwipycon/utils.py b/project/kiwipycon/utils.py
new file mode 100644
index 0000000..611dc62
--- /dev/null
+++ b/project/kiwipycon/utils.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+#python
+import urllib
+import datetime
+import re
+from random import randint
+
+#django
+from django.http import HttpResponseRedirect
+
+def kiwipycon_quote(string, encoding="utf-8"):
+ """Encodes string to encoding before quoting.
+ """
+ return urllib.quote(string.encode(encoding))
+
+# from LFS
+def set_message_cookie(url, msg):
+ """Creates response object with given url and adds message cookie with passed
+ message.
+ """
+
+ # We just keep the message two seconds.
+ max_age = 2
+ expires = datetime.datetime.strftime(
+ datetime.datetime.utcnow() +
+ datetime.timedelta(seconds=max_age), "%a, %d-%b-%Y %H:%M:%S GMT")
+
+ response = HttpResponseRedirect(url)
+ response.set_cookie("message", kiwipycon_quote(msg), max_age=max_age, expires=expires)
+
+ return response
+
+# from django-snippets
+def slugify(inStr):
+ removelist = ["a", "an", "as", "at", "before", "but", "by", "for","from","is", "in", "into", "like", "of", "off", "on", "onto","per","since", "than", "the", "this", "that", "to", "up", "via","with"];
+ for a in removelist:
+ aslug = re.sub(r'\b'+a+r'\b','',inStr)
+ aslug = re.sub('[^\w\s-]', '', aslug).strip().lower()
+ aslug = re.sub('\s+', '-', aslug)
+ return len(aslug) > 50 and '%s-%d' % (aslug[:43], randint(100000,999999)) or aslug