add speakers app from pycon
This commit is contained in:
parent
76c4a7b79c
commit
2b7f5546a0
10 changed files with 307 additions and 0 deletions
0
symposion/speakers/__init__.py
Normal file
0
symposion/speakers/__init__.py
Normal file
9
symposion/speakers/admin.py
Normal file
9
symposion/speakers/admin.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from symposion.speakers.models import Speaker
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Speaker,
|
||||||
|
list_display = ["name", "email", "twitter_username", "sessions_preference", "created"],
|
||||||
|
search_fields = ["name"],
|
||||||
|
)
|
31
symposion/speakers/fixture_gen.py
Normal file
31
symposion/speakers/fixture_gen.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from fixture_generator import fixture_generator
|
||||||
|
|
||||||
|
from symposion.speakers.models import Speaker
|
||||||
|
|
||||||
|
|
||||||
|
@fixture_generator(Speaker, User)
|
||||||
|
def speakers():
|
||||||
|
guido = User.objects.create_user("guido", "guido@python.org", "pythonisawesome")
|
||||||
|
matz = User.objects.create_user("matz", "matz@ruby.org", "pythonsucks")
|
||||||
|
larry = User.objects.create_user("larryw", "larry@perl.org", "linenoisehere")
|
||||||
|
|
||||||
|
Speaker.objects.create(
|
||||||
|
user=guido,
|
||||||
|
name="Guido van Rossum",
|
||||||
|
biography="I wrote Python, and named it after Monty Python",
|
||||||
|
twitter_username="gvanrossum",
|
||||||
|
)
|
||||||
|
Speaker.objects.create(
|
||||||
|
user=matz,
|
||||||
|
name="Yukihiro Matsumoto",
|
||||||
|
biography="I wrote Ruby, and named it after the rare gem Ruby, a pun "
|
||||||
|
"on Perl/pearl.",
|
||||||
|
twitter_username="yukihiro_matz"
|
||||||
|
)
|
||||||
|
Speaker.objects.create(
|
||||||
|
user=larry,
|
||||||
|
name="Larry Wall",
|
||||||
|
biography="I wrote Perl, and named it after the Parable of the Pearl",
|
||||||
|
)
|
63
symposion/speakers/forms.py
Normal file
63
symposion/speakers/forms.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
|
from markitup.widgets import MarkItUpWidget
|
||||||
|
|
||||||
|
from symposion.speakers.models import Speaker
|
||||||
|
|
||||||
|
|
||||||
|
class SpeakerForm(forms.ModelForm):
|
||||||
|
|
||||||
|
sessions_preference = forms.ChoiceField(
|
||||||
|
widget=forms.RadioSelect(),
|
||||||
|
choices=Speaker.SESSION_COUNT_CHOICES,
|
||||||
|
required=False,
|
||||||
|
help_text="If you've submitted multiple proposals, please let us know if you only want to give one or if you'd like to give two talks."
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Speaker
|
||||||
|
fields = [
|
||||||
|
"name",
|
||||||
|
"biography",
|
||||||
|
"photo",
|
||||||
|
"twitter_username",
|
||||||
|
"sessions_preference"
|
||||||
|
]
|
||||||
|
widgets = {
|
||||||
|
"biography": MarkItUpWidget(),
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean_twitter_username(self):
|
||||||
|
value = self.cleaned_data["twitter_username"]
|
||||||
|
if value.startswith("@"):
|
||||||
|
value = value[1:]
|
||||||
|
return value
|
||||||
|
|
||||||
|
def clean_sessions_preference(self):
|
||||||
|
value = self.cleaned_data["sessions_preference"]
|
||||||
|
if not value:
|
||||||
|
return None
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
|
||||||
|
# class SignupForm(PinaxSignupForm):
|
||||||
|
|
||||||
|
# def save(self, speaker, request=None):
|
||||||
|
# # don't assume a username is available. it is a common removal if
|
||||||
|
# # site developer wants to use email authentication.
|
||||||
|
# username = self.cleaned_data.get("username")
|
||||||
|
# email = self.cleaned_data["email"]
|
||||||
|
# new_user = self.create_user(username)
|
||||||
|
# if speaker.invite_email == new_user.email:
|
||||||
|
# # already verified so can just create
|
||||||
|
# EmailAddress(user=new_user, email=email, verified=True, primary=True).save()
|
||||||
|
# else:
|
||||||
|
# if request:
|
||||||
|
# messages.info(request, u"Confirmation email sent to %(email)s" % {"email": email})
|
||||||
|
# EmailAddress.objects.add_email(new_user, email)
|
||||||
|
# new_user.is_active = False
|
||||||
|
# new_user.save()
|
||||||
|
# self.after_signup(new_user)
|
||||||
|
# return new_user
|
0
symposion/speakers/management/__init__.py
Normal file
0
symposion/speakers/management/__init__.py
Normal file
0
symposion/speakers/management/commands/__init__.py
Normal file
0
symposion/speakers/management/commands/__init__.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
|
from symposion.speakers.models import Speaker
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
csv_file = csv.writer(open(os.path.join(os.getcwd(), "speakers.csv"), "wb"))
|
||||||
|
csv_file.writerow(["Name", "Bio"])
|
||||||
|
|
||||||
|
for speaker in Speaker.objects.all():
|
||||||
|
csv_file.writerow([
|
||||||
|
speaker.name.encode("utf-8"),
|
||||||
|
speaker.biography.encode("utf-8"),
|
||||||
|
])
|
55
symposion/speakers/models.py
Normal file
55
symposion/speakers/models.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from markitup.fields import MarkupField
|
||||||
|
|
||||||
|
|
||||||
|
class Speaker(models.Model):
|
||||||
|
|
||||||
|
SESSION_COUNT_CHOICES = [
|
||||||
|
(1, "One"),
|
||||||
|
(2, "Two")
|
||||||
|
]
|
||||||
|
|
||||||
|
user = models.OneToOneField(User, null=True, related_name="speaker_profile")
|
||||||
|
name = models.CharField(max_length=100, help_text="As you would like it to appear in the conference program.")
|
||||||
|
biography = MarkupField(help_text="A little bit about you. Edit using <a href='http://warpedvisions.org/projects/markdown-cheat-sheet/' target='_blank'>Markdown</a>.")
|
||||||
|
photo = models.ImageField(upload_to="speaker_photos", blank=True)
|
||||||
|
twitter_username = models.CharField(
|
||||||
|
max_length = 15,
|
||||||
|
blank = True,
|
||||||
|
help_text = "Your Twitter account"
|
||||||
|
)
|
||||||
|
annotation = models.TextField() # staff only
|
||||||
|
invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True)
|
||||||
|
invite_token = models.CharField(max_length=40, db_index=True)
|
||||||
|
created = models.DateTimeField(
|
||||||
|
default = datetime.datetime.now,
|
||||||
|
editable = False
|
||||||
|
)
|
||||||
|
sessions_preference = models.IntegerField(
|
||||||
|
choices=SESSION_COUNT_CHOICES,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="If you've submitted multiple proposals, please let us know if you only want to give one or if you'd like to give two talks. You may submit more than two proposals."
|
||||||
|
)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
if self.user:
|
||||||
|
return self.name
|
||||||
|
else:
|
||||||
|
return "?"
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("speaker_edit")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def email(self):
|
||||||
|
if self.user is not None:
|
||||||
|
return self.user.email
|
||||||
|
else:
|
||||||
|
return self.invite_email
|
9
symposion/speakers/urls.py
Normal file
9
symposion/speakers/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns("symposion.speakers.views",
|
||||||
|
url(r"^create/$", "speaker_create", name="speaker_create"),
|
||||||
|
url(r"^create/(\w+)/$", "speaker_create_token", name="speaker_create_token"),
|
||||||
|
url(r"^edit/(?:(?P<pk>\d+)/)?$", "speaker_edit", name="speaker_edit"),
|
||||||
|
url(r"^profile/(?P<pk>\d+)/$", "speaker_profile", name="speaker_profile"),
|
||||||
|
)
|
121
symposion/speakers/views.py
Normal file
121
symposion/speakers/views.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.http import Http404, HttpResponse
|
||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.template import RequestContext
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
|
from symposion.proposals.models import ProposalBase
|
||||||
|
from symposion.speakers.forms import SpeakerForm #, SignupForm
|
||||||
|
from symposion.speakers.models import Speaker
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def speaker_create(request):
|
||||||
|
try:
|
||||||
|
return redirect(request.user.speaker_profile)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
try:
|
||||||
|
speaker = Speaker.objects.get(invite_email=request.user.email)
|
||||||
|
found = True
|
||||||
|
except Speaker.DoesNotExist:
|
||||||
|
speaker = None
|
||||||
|
found = False
|
||||||
|
form = SpeakerForm(request.POST, request.FILES, instance=speaker)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
speaker = form.save(commit=False)
|
||||||
|
speaker.user = request.user
|
||||||
|
if not found:
|
||||||
|
speaker.invite_email = None
|
||||||
|
speaker.save()
|
||||||
|
messages.success(request, "Speaker profile created.")
|
||||||
|
return redirect("dashboard")
|
||||||
|
else:
|
||||||
|
form = SpeakerForm(initial = {"name": request.user.get_full_name()})
|
||||||
|
|
||||||
|
return render(request, "speakers/speaker_create.html", {
|
||||||
|
"form": form,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def speaker_create_token(request, token):
|
||||||
|
speaker = get_object_or_404(Speaker, invite_token=token)
|
||||||
|
request.session["pending-token"] = token
|
||||||
|
if request.user.is_authenticated():
|
||||||
|
# check for speaker profile
|
||||||
|
try:
|
||||||
|
existing_speaker = request.user.speaker_profile
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
del request.session["pending-token"]
|
||||||
|
additional_speakers = ProposalBase.additional_speakers.through
|
||||||
|
additional_speakers._default_manager.filter(
|
||||||
|
speaker = speaker
|
||||||
|
).update(
|
||||||
|
speaker = existing_speaker
|
||||||
|
)
|
||||||
|
messages.info(request, "You have been associated with all pending "
|
||||||
|
"talk proposals")
|
||||||
|
return redirect("dashboard")
|
||||||
|
else:
|
||||||
|
if not request.user.is_authenticated():
|
||||||
|
return redirect("account_login")
|
||||||
|
return redirect("speaker_create")
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def speaker_edit(request, pk=None):
|
||||||
|
if pk is None:
|
||||||
|
try:
|
||||||
|
speaker = request.user.speaker_profile
|
||||||
|
except Speaker.DoesNotExist:
|
||||||
|
return redirect("speaker_create")
|
||||||
|
else:
|
||||||
|
if request.user.groups.filter(name="organizer").exists(): # @@@
|
||||||
|
speaker = get_object_or_404(Speaker, pk=pk)
|
||||||
|
else:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SpeakerForm(request.POST, request.FILES, instance=speaker)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, "Speaker profile updated.")
|
||||||
|
return redirect("dashboard")
|
||||||
|
else:
|
||||||
|
form = SpeakerForm(instance=speaker)
|
||||||
|
|
||||||
|
return render(request, "speakers/speaker_edit.html", {
|
||||||
|
"form": form,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def speaker_profile(request, pk, template_name="speakers/speaker_profile.html", extra_context=None):
|
||||||
|
|
||||||
|
if extra_context is None:
|
||||||
|
extra_context = {}
|
||||||
|
|
||||||
|
speaker = get_object_or_404(Speaker, pk=pk)
|
||||||
|
|
||||||
|
# schedule may not be installed so we need to check for sessions
|
||||||
|
if hasattr(speaker, "sessions"):
|
||||||
|
sessions = speaker.sessions.exclude(slot=None).order_by("slot__start")
|
||||||
|
else:
|
||||||
|
sessions = []
|
||||||
|
|
||||||
|
if not sessions:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
return render_to_response(template_name, dict({
|
||||||
|
"speaker": speaker,
|
||||||
|
"sessions": sessions,
|
||||||
|
"timezone": settings.SCHEDULE_TIMEZONE,
|
||||||
|
}, **extra_context), context_instance=RequestContext(request))
|
Loading…
Reference in a new issue