Changeset - cb4b0fac3871
[Not reviewed]
Merge
! ! !
Patrick Altman - 10 years ago 2014-12-15 21:15:46
paltman@gmail.com
Merge branch 'django1.6-compatibility' of https://github.com/mbrochh/symposion into mbrochh-django1.6-compatibility

Conflicts:
symposion/boxes/urls.py
symposion/cms/urls.py
symposion/conference/urls.py
symposion/proposals/models.py
symposion/proposals/urls.py
symposion/reviews/urls.py
symposion/schedule/models.py
symposion/schedule/urls.py
symposion/speakers/urls.py
symposion/sponsorship/urls.py
symposion/teams/urls.py
12 files changed with 30 insertions and 32 deletions:
0 comments (0 inline, 0 general)
symposion/boxes/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import url, patterns
 
from django.conf.urls import url, patterns
 

	
 

	
 
urlpatterns = patterns("symposion.boxes.views",
 
    url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"),
 
)
symposion/cms/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import url, patterns
 
from django.conf.urls import url, patterns
 

	
 

	
 
PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/"
 

	
 
urlpatterns = patterns("symposion.cms.views",
 
    url(r"^files/$", "file_index", name="file_index"),
 
    url(r"^files/create/$", "file_create", name="file_create"),
 
    url(r"^files/(\d+)/([^/]+)$", "file_download", name="file_download"),
 
    url(r"^files/(\d+)/delete/$", "file_delete", name="file_delete"),
 
    url(r"^(?P<path>%s)_edit/$" % PAGE_RE, "page_edit", name="cms_page_edit"),
 
    url(r"^(?P<path>%s)$" % PAGE_RE, "page", name="cms_page"),
 
)
symposion/conference/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import patterns, url
 
from django.conf.urls import patterns, url
 

	
 

	
 
urlpatterns = patterns("symposion.conference.views",
 
    url(r"^users/$", "user_list", name="user_list"),
 
)
symposion/proposals/models.py
Show inline comments
 
import datetime
 
import os
 
import uuid
 

	
 
from django.core.urlresolvers import reverse
 
from django.db import models
 
from django.db.models import Q
 
from django.utils.translation import ugettext_lazy as _
 
from django.utils.timezone import now
 

	
 
from django.contrib.auth.models import User
 

	
 
import reversion
 

	
 
from markitup.fields import MarkupField
 

	
 
from model_utils.managers import InheritanceManager
 

	
 
from symposion.conference.models import Section
 

	
 

	
 
class ProposalSection(models.Model):
 
    """
 
    configuration of proposal submissions for a specific Section.
 

	
 
    a section is available for proposals iff:
 
      * it is after start (if there is one) and
 
      * it is before end (if there is one) and
 
      * closed is NULL or False
 
    """
 

	
 
    section = models.OneToOneField(Section)
 

	
 
    start = models.DateTimeField(null=True, blank=True)
 
    end = models.DateTimeField(null=True, blank=True)
 
    closed = models.NullBooleanField()
 
    published = models.NullBooleanField()
 

	
 
    @classmethod
 
    def available(cls):
 
        now = datetime.datetime.now()
 
        return cls._default_manager.filter(
 
            Q(start__lt=now) | Q(start=None),
 
            Q(end__gt=now) | Q(end=None),
 
            Q(start__lt=now()) | Q(start=None),
 
            Q(end__gt=now()) | Q(end=None),
 
            Q(closed=False) | Q(closed=None),
 
        )
 

	
 
    def is_available(self):
 
        if self.closed:
 
            return False
 
        now = datetime.datetime.now()
 
        if self.start and self.start > now:
 
        if self.start and self.start > now():
 
            return False
 
        if self.end and self.end < now:
 
        if self.end and self.end < now():
 
            return False
 
        return True
 

	
 
    def __unicode__(self):
 
        return self.section.name
 

	
 

	
 
class ProposalKind(models.Model):
 
    """
 
    e.g. talk vs panel vs tutorial vs poster
 

	
 
    Note that if you have different deadlines, reviewers, etc. you'll want
 
    to distinguish the section as well as the kind.
 
    """
 

	
 
    section = models.ForeignKey(Section, related_name="proposal_kinds")
 

	
 
    name = models.CharField(_("Name"), max_length=100)
 
    slug = models.SlugField()
 

	
 
    def __unicode__(self):
 
        return self.name
 

	
 

	
 
class ProposalBase(models.Model):
 

	
 
    objects = InheritanceManager()
 

	
 
    kind = models.ForeignKey(ProposalKind)
 

	
 
    title = models.CharField(max_length=100)
 
    description = models.TextField(
 
        _("Brief Description"),
 
        max_length=400,  # @@@ need to enforce 400 in UI
 
        help_text=_("If your proposal is accepted this will be made public and printed in the "
 
                    "program. Should be one paragraph, maximum 400 characters.")
 
    )
 
    abstract = MarkupField(
 
        _("Detailed Abstract"),
 
        help_text=_("Detailed outline. Will be made public if your proposal is accepted. Edit "
 
                    "using <a href='http://daringfireball.net/projects/markdown/basics' "
 
                    "target='_blank'>Markdown</a>.")
 
    )
 
    additional_notes = MarkupField(
 
        blank=True,
 
        help_text=_("Anything else you'd like the program committee to know when making their "
 
                    "selection: your past experience, etc. This is not made public. Edit using "
 
                    "<a href='http://daringfireball.net/projects/markdown/basics' "
 
                    "target='_blank'>Markdown</a>.")
 
    )
 
    submitted = models.DateTimeField(
 
        default=datetime.datetime.now,
 
        default=now,
 
        editable=False,
 
    )
 
    speaker = models.ForeignKey("speakers.Speaker", related_name="proposals")
 
    additional_speakers = models.ManyToManyField("speakers.Speaker", through="AdditionalSpeaker",
 
                                                 blank=True)
 
    cancelled = models.BooleanField(default=False)
 

	
 
    def can_edit(self):
 
        return True
 

	
 
    @property
 
    def section(self):
 
        return self.kind.section
 

	
 
    @property
 
    def speaker_email(self):
 
        return self.speaker.email
 

	
 
    @property
 
    def number(self):
 
        return str(self.pk).zfill(3)
 

	
 
    def speakers(self):
 
        yield self.speaker
 
        speakers = self.additional_speakers.exclude(
 
            additionalspeaker__status=AdditionalSpeaker.SPEAKING_STATUS_DECLINED)
 
        for speaker in speakers:
 
            yield speaker
 

	
 
    def notification_email_context(self):
 
        return {
 
            "title": self.title,
 
            "speaker": self.speaker.name,
 
            "kind": self.kind.name,
 
        }
 

	
 

	
 
reversion.register(ProposalBase)
 

	
 

	
 
class AdditionalSpeaker(models.Model):
 

	
 
    SPEAKING_STATUS_PENDING = 1
 
    SPEAKING_STATUS_ACCEPTED = 2
 
    SPEAKING_STATUS_DECLINED = 3
 

	
 
    SPEAKING_STATUS = [
 
        (SPEAKING_STATUS_PENDING, _("Pending")),
 
        (SPEAKING_STATUS_ACCEPTED, _("Accepted")),
 
        (SPEAKING_STATUS_DECLINED, _("Declined")),
 
    ]
 

	
 
    speaker = models.ForeignKey("speakers.Speaker")
 
    proposalbase = models.ForeignKey(ProposalBase)
 
    status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING)
 

	
 
    class Meta:
 
        db_table = "proposals_proposalbase_additional_speakers"
 
        unique_together = ("speaker", "proposalbase")
 

	
 

	
 
def uuid_filename(instance, filename):
 
    ext = filename.split(".")[-1]
 
    filename = "%s.%s" % (uuid.uuid4(), ext)
 
    return os.path.join("document", filename)
 

	
 

	
 
class SupportingDocument(models.Model):
 

	
 
    proposal = models.ForeignKey(ProposalBase, related_name="supporting_documents")
 

	
 
    uploaded_by = models.ForeignKey(User)
 
    created_at = models.DateTimeField(default=datetime.datetime.now)
 

	
 
    created_at = models.DateTimeField(default=now)
 

	
 
    file = models.FileField(upload_to=uuid_filename)
 
    description = models.CharField(max_length=140)
 

	
 
    def download_url(self):
 
        return reverse("proposal_document_download",
 
                       args=[self.pk, os.path.basename(self.file.name).lower()])
symposion/proposals/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import *
 
from django.conf.urls import patterns, url
 

	
 

	
 
urlpatterns = patterns("symposion.proposals.views",
 
    url(r"^submit/$", "proposal_submit", name="proposal_submit"),
 
    url(r"^submit/([\w\-]+)/$", "proposal_submit_kind", name="proposal_submit_kind"),
 
    url(r"^(\d+)/$", "proposal_detail", name="proposal_detail"),
 
    url(r"^(\d+)/edit/$", "proposal_edit", name="proposal_edit"),
 
    url(r"^(\d+)/speakers/$", "proposal_speaker_manage", name="proposal_speaker_manage"),
 
    url(r"^(\d+)/cancel/$", "proposal_cancel", name="proposal_cancel"),
 
    url(r"^(\d+)/leave/$", "proposal_leave", name="proposal_leave"),
 
    url(r"^(\d+)/join/$", "proposal_pending_join", name="proposal_pending_join"),
 
    url(r"^(\d+)/decline/$", "proposal_pending_decline", name="proposal_pending_decline"),
 

	
 
    url(r"^(\d+)/document/create/$", "document_create", name="proposal_document_create"),
 
    url(r"^document/(\d+)/delete/$", "document_delete", name="proposal_document_delete"),
 
    url(r"^document/(\d+)/([^/]+)$", "document_download", name="proposal_document_download"),
 
)
symposion/proposals/views.py
Show inline comments
 
import random
 
import sys
 

	
 
from django.conf import settings
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.urlresolvers import reverse
 
from django.db.models import Q
 
from django.http import Http404, HttpResponse, HttpResponseForbidden
 
from django.shortcuts import render, redirect, get_object_or_404
 
from django.utils.hashcompat import sha_constructor
 

	
 
try:
 
    from hashlib import sha1 as sha_constructor
 
except ImportError:
 
    from django.utils.hashcompat import sha_constructor
 

	
 
from django.views import static
 

	
 
from django.contrib import messages
 
from django.contrib.auth.models import User
 
from django.contrib.auth.decorators import login_required
 

	
 
from account.models import EmailAddress
 
from symposion.proposals.models import ProposalBase, ProposalSection, ProposalKind
 
from symposion.proposals.models import SupportingDocument, AdditionalSpeaker
 
from symposion.speakers.models import Speaker
 
from symposion.utils.mail import send_email
 

	
 
from symposion.proposals.forms import AddSpeakerForm, SupportingDocumentCreateForm
 

	
 

	
 
def get_form(name):
 
    dot = name.rindex(".")
 
    mod_name, form_name = name[:dot], name[dot + 1:]
 
    __import__(mod_name)
 
    return getattr(sys.modules[mod_name], form_name)
 

	
 

	
 
def proposal_submit(request):
 
    if not request.user.is_authenticated():
 
        messages.info(request, "To submit a proposal, please "
 
                      "<a href='{0}'>log in</a> and create a speaker profile "
 
                      "via the dashboard.".format(settings.LOGIN_URL))
 
        return redirect("home")  # @@@ unauth'd speaker info page?
 
    else:
 
        try:
 
            request.user.speaker_profile
 
        except ObjectDoesNotExist:
 
            url = reverse("speaker_create")
 
            messages.info(request, "To submit a proposal, first "
 
                          "<a href='{0}'>create a speaker "
 
                          "profile</a>.".format(url))
 
            return redirect("dashboard")
 

	
 
    kinds = []
 
    for proposal_section in ProposalSection.available():
 
        for kind in proposal_section.section.proposal_kinds.all():
 
            kinds.append(kind)
 

	
 
    return render(request, "proposals/proposal_submit.html", {
 
        "kinds": kinds,
 
    })
 

	
 

	
 
def proposal_submit_kind(request, kind_slug):
 

	
 
    kind = get_object_or_404(ProposalKind, slug=kind_slug)
 

	
 
    if not request.user.is_authenticated():
 
        return redirect("home")  # @@@ unauth'd speaker info page?
 
    else:
 
        try:
 
            speaker_profile = request.user.speaker_profile
 
        except ObjectDoesNotExist:
 
            return redirect("dashboard")
 

	
 
    if not kind.section.proposalsection.is_available():
 
        return redirect("proposal_submit")
 

	
 
    form_class = get_form(settings.PROPOSAL_FORMS[kind_slug])
 

	
 
    if request.method == "POST":
 
        form = form_class(request.POST)
 
        if form.is_valid():
 
            proposal = form.save(commit=False)
 
            proposal.kind = kind
 
            proposal.speaker = speaker_profile
 
            proposal.save()
 
            form.save_m2m()
 
            messages.success(request, "Proposal submitted.")
 
            if "add-speakers" in request.POST:
 
                return redirect("proposal_speaker_manage", proposal.pk)
 
            return redirect("dashboard")
 
    else:
 
        form = form_class()
 

	
 
    return render(request, "proposals/proposal_submit_kind.html", {
 
        "kind": kind,
 
        "form": form,
 
    })
 

	
 

	
 
@login_required
 
def proposal_speaker_manage(request, pk):
 
    queryset = ProposalBase.objects.select_related("speaker")
 
    proposal = get_object_or_404(queryset, pk=pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    if proposal.speaker != request.user.speaker_profile:
 
        raise Http404()
 

	
 
    if request.method == "POST":
 
        add_speaker_form = AddSpeakerForm(request.POST, proposal=proposal)
 
        if add_speaker_form.is_valid():
 
            message_ctx = {
 
                "proposal": proposal,
 
            }
 

	
 
            def create_speaker_token(email_address):
 
                # create token and look for an existing speaker to prevent
 
                # duplicate tokens and confusing the pending speaker
 
                try:
 
                    pending = Speaker.objects.get(
 
                        Q(user=None, invite_email=email_address)
 
                    )
 
                except Speaker.DoesNotExist:
 
                    salt = sha_constructor(str(random.random())).hexdigest()[:5]
 
                    token = sha_constructor(salt + email_address).hexdigest()
 
                    pending = Speaker.objects.create(
 
                        invite_email=email_address,
 
                        invite_token=token,
 
                    )
 
                else:
 
                    token = pending.invite_token
 
                return pending, token
 
            email_address = add_speaker_form.cleaned_data["email"]
 
            # check if email is on the site now
 
            users = EmailAddress.objects.get_users_for(email_address)
 
            if users:
 
                # should only be one since we enforce unique email
 
                user = users[0]
 
                message_ctx["user"] = user
 
                # look for speaker profile
 
                try:
 
                    speaker = user.speaker_profile
 
                except ObjectDoesNotExist:
 
                    speaker, token = create_speaker_token(email_address)
 
                    message_ctx["token"] = token
 
                    # fire off email to user to create profile
 
                    send_email(
 
                        [email_address], "speaker_no_profile",
 
                        context=message_ctx
 
                    )
 
                else:
 
                    # fire off email to user letting them they are loved.
 
                    send_email(
 
                        [email_address], "speaker_addition",
 
                        context=message_ctx
 
                    )
 
            else:
 
                speaker, token = create_speaker_token(email_address)
 
                message_ctx["token"] = token
 
                # fire off email letting user know about site and to create
 
                # account and speaker profile
 
                send_email(
 
                    [email_address], "speaker_invite",
 
                    context=message_ctx
 
                )
 
            invitation, created = AdditionalSpeaker.objects.get_or_create(
 
                proposalbase=proposal.proposalbase_ptr, speaker=speaker)
 
            messages.success(request, "Speaker invited to proposal.")
 
            return redirect("proposal_speaker_manage", proposal.pk)
 
    else:
 
        add_speaker_form = AddSpeakerForm(proposal=proposal)
 
    ctx = {
 
        "proposal": proposal,
 
        "speakers": proposal.speakers(),
 
        "add_speaker_form": add_speaker_form,
 
    }
 
    return render(request, "proposals/proposal_speaker_manage.html", ctx)
 

	
 

	
 
@login_required
 
def proposal_edit(request, pk):
 
    queryset = ProposalBase.objects.select_related("speaker")
 
    proposal = get_object_or_404(queryset, pk=pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    if request.user != proposal.speaker.user:
 
        raise Http404()
 

	
 
    if not proposal.can_edit():
 
        ctx = {
 
            "title": "Proposal editing closed",
 
            "body": "Proposal editing is closed for this session type."
 
        }
 
        return render(request, "proposals/proposal_error.html", ctx)
 

	
 
    form_class = get_form(settings.PROPOSAL_FORMS[proposal.kind.slug])
 

	
 
    if request.method == "POST":
 
        form = form_class(request.POST, instance=proposal)
 
        if form.is_valid():
 
            form.save()
 
            if hasattr(proposal, "reviews"):
 
                users = User.objects.filter(
 
                    Q(review__proposal=proposal) |
 
                    Q(proposalmessage__proposal=proposal)
 
                )
 
                users = users.exclude(id=request.user.id).distinct()
 
                for user in users:
 
                    ctx = {
 
                        "user": request.user,
 
                        "proposal": proposal,
 
                    }
 
                    send_email(
 
                        [user.email], "proposal_updated",
 
                        context=ctx
 
                    )
 
            messages.success(request, "Proposal updated.")
 
            return redirect("proposal_detail", proposal.pk)
 
    else:
 
        form = form_class(instance=proposal)
 

	
 
    return render(request, "proposals/proposal_edit.html", {
 
        "proposal": proposal,
 
        "form": form,
 
    })
 

	
 

	
 
@login_required
 
def proposal_detail(request, pk):
 
    queryset = ProposalBase.objects.select_related("speaker", "speaker__user")
 
    proposal = get_object_or_404(queryset, pk=pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    if request.user not in [p.user for p in proposal.speakers()]:
 
        raise Http404()
 

	
 
    if "symposion.reviews" in settings.INSTALLED_APPS:
 
        from symposion.reviews.forms import SpeakerCommentForm
 
        message_form = SpeakerCommentForm()
 
        if request.method == "POST":
 
            message_form = SpeakerCommentForm(request.POST)
 
            if message_form.is_valid():
 

	
 
                message = message_form.save(commit=False)
 
                message.user = request.user
 
                message.proposal = proposal
 
                message.save()
 

	
 
                ProposalMessage = SpeakerCommentForm.Meta.model
 
                reviewers = User.objects.filter(
 
                    id__in=ProposalMessage.objects.filter(
 
                        proposal=proposal
 
                    ).exclude(
 
                        user=request.user
 
                    ).distinct().values_list("user", flat=True)
 
                )
 

	
 
                for reviewer in reviewers:
 
                    ctx = {
 
                        "proposal": proposal,
 
                        "message": message,
 
                        "reviewer": True,
 
                    }
 
                    send_email(
 
                        [reviewer.email], "proposal_new_message",
 
                        context=ctx
 
                    )
 

	
 
                return redirect(request.path)
 
        else:
 
            message_form = SpeakerCommentForm()
 
    else:
 
        message_form = None
 

	
 
    return render(request, "proposals/proposal_detail.html", {
 
        "proposal": proposal,
 
        "message_form": message_form
 
    })
 

	
 

	
 
@login_required
 
def proposal_cancel(request, pk):
 
    queryset = ProposalBase.objects.select_related("speaker")
 
    proposal = get_object_or_404(queryset, pk=pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    if proposal.speaker.user != request.user:
 
        return HttpResponseForbidden()
 

	
 
    if request.method == "POST":
 
        proposal.cancelled = True
 
        proposal.save()
 
        # @@@ fire off email to submitter and other speakers
 
        messages.success(request, "%s has been cancelled" % proposal.title)
 
        return redirect("dashboard")
 

	
 
    return render(request, "proposals/proposal_cancel.html", {
 
        "proposal": proposal,
 
    })
 

	
 

	
 
@login_required
 
def proposal_leave(request, pk):
 
    queryset = ProposalBase.objects.select_related("speaker")
 
    proposal = get_object_or_404(queryset, pk=pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    try:
 
        speaker = proposal.additional_speakers.get(user=request.user)
 
    except ObjectDoesNotExist:
 
        return HttpResponseForbidden()
 
    if request.method == "POST":
 
        proposal.additional_speakers.remove(speaker)
 
        # @@@ fire off email to submitter and other speakers
 
        messages.success(request, "You are no longer speaking on %s" % proposal.title)
 
        return redirect("dashboard")
 
    ctx = {
 
        "proposal": proposal,
 
    }
 
    return render(request, "proposals/proposal_leave.html", ctx)
 

	
 

	
 
@login_required
 
def proposal_pending_join(request, pk):
 
    proposal = get_object_or_404(ProposalBase, pk=pk)
 
    speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile,
 
                                 proposalbase=proposal)
 
    if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
 
        speaking.status = AdditionalSpeaker.SPEAKING_STATUS_ACCEPTED
 
        speaking.save()
 
        messages.success(request, "You have accepted the invitation to join %s" % proposal.title)
 
        return redirect("dashboard")
 
    else:
 
        return redirect("dashboard")
 

	
 

	
 
@login_required
 
def proposal_pending_decline(request, pk):
 
    proposal = get_object_or_404(ProposalBase, pk=pk)
 
    speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile,
 
                                 proposalbase=proposal)
 
    if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
 
        speaking.status = AdditionalSpeaker.SPEAKING_STATUS_DECLINED
 
        speaking.save()
 
        messages.success(request, "You have declined to speak on %s" % proposal.title)
 
        return redirect("dashboard")
 
    else:
 
        return redirect("dashboard")
 

	
 

	
 
@login_required
 
def document_create(request, proposal_pk):
 
    queryset = ProposalBase.objects.select_related("speaker")
 
    proposal = get_object_or_404(queryset, pk=proposal_pk)
 
    proposal = ProposalBase.objects.get_subclass(pk=proposal.pk)
 

	
 
    if proposal.cancelled:
 
        return HttpResponseForbidden()
 

	
 
    if request.method == "POST":
 
        form = SupportingDocumentCreateForm(request.POST, request.FILES)
 
        if form.is_valid():
 
            document = form.save(commit=False)
 
            document.proposal = proposal
 
            document.uploaded_by = request.user
 
            document.save()
 
            return redirect("proposal_detail", proposal.pk)
 
    else:
 
        form = SupportingDocumentCreateForm()
 

	
 
    return render(request, "proposals/document_create.html", {
 
        "proposal": proposal,
 
        "form": form,
 
    })
 

	
 

	
 
@login_required
 
def document_download(request, pk, *args):
 
    document = get_object_or_404(SupportingDocument, pk=pk)
 
    if getattr(settings, "USE_X_ACCEL_REDIRECT", False):
 
        response = HttpResponse()
 
        response["X-Accel-Redirect"] = document.file.url
 
        # delete content-type to allow Gondor to determine the filetype and
 
        # we definitely don't want Django's crappy default :-)
 
        del response["content-type"]
 
    else:
 
        response = static.serve(request, document.file.name, document_root=settings.MEDIA_ROOT)
 
    return response
 

	
 

	
 
@login_required
 
def document_delete(request, pk):
 
    document = get_object_or_404(SupportingDocument, pk=pk, uploaded_by=request.user)
 
    proposal_pk = document.proposal.pk
 

	
 
    if request.method == "POST":
 
        document.delete()
symposion/reviews/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import patterns, url
 
from django.conf.urls import patterns, url
 

	
 

	
 
urlpatterns = patterns("symposion.reviews.views",
 
    url(r"^section/(?P<section_slug>[\w\-]+)/all/$", "review_section", {"reviewed": "all"}, name="review_section"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/reviewed/$", "review_section", {"reviewed": "reviewed"}, name="user_reviewed"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/not_reviewed/$", "review_section", {"reviewed": "not_reviewed"}, name="user_not_reviewed"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/assignments/$", "review_section", {"assigned": True}, name="review_section_assignments"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/status/$", "review_status", name="review_status"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/status/(?P<key>\w+)/$", "review_status", name="review_status"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/list/(?P<user_pk>\d+)/$", "review_list", name="review_list_user"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/admin/$", "review_admin", name="review_admin"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/admin/accept/$", "review_bulk_accept", name="review_bulk_accept"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/notification/(?P<status>\w+)/$", "result_notification", name="result_notification"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/notification/(?P<status>\w+)/prepare/$", "result_notification_prepare", name="result_notification_prepare"),
 
    url(r"^section/(?P<section_slug>[\w\-]+)/notification/(?P<status>\w+)/send/$", "result_notification_send", name="result_notification_send"),
 

	
 
    url(r"^review/(?P<pk>\d+)/$", "review_detail", name="review_detail"),
 

	
 
    url(r"^(?P<pk>\d+)/delete/$", "review_delete", name="review_delete"),
 
    url(r"^assignments/$", "review_assignments", name="review_assignments"),
 
    url(r"^assignment/(?P<pk>\d+)/opt-out/$", "review_assignment_opt_out", name="review_assignment_opt_out"),
 
)
symposion/schedule/models.py
Show inline comments
 
import datetime
 

	
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.db import models
 

	
 
from markitup.fields import MarkupField
 

	
 
from symposion.proposals.models import ProposalBase
 
from symposion.conference.models import Section
 

	
 

	
 
class Schedule(models.Model):
 

	
 
    section = models.OneToOneField(Section)
 
    published = models.BooleanField(default=True)
 
    hidden = models.BooleanField("Hide schedule from overall conference view", default=False)
 

	
 
    def __unicode__(self):
 
        return "%s Schedule" % self.section
 

	
 
    class Meta:
 
        ordering = ["section"]
 

	
 

	
 
class Day(models.Model):
 

	
 
    schedule = models.ForeignKey(Schedule)
 
    date = models.DateField()
 

	
 
    def __unicode__(self):
 
        return "%s" % self.date
 

	
 
    class Meta:
 
        unique_together = [("schedule", "date")]
 
        ordering = ["date"]
 

	
 

	
 
class Room(models.Model):
 

	
 
    schedule = models.ForeignKey(Schedule)
 
    name = models.CharField(max_length=65)
 
    order = models.PositiveIntegerField()
 

	
 
    def __unicode__(self):
 
        return self.name
 

	
 

	
 
class SlotKind(models.Model):
 
    """
 
    A slot kind represents what kind a slot is. For example, a slot can be a
 
    break, lunch, or X-minute talk.
 
    """
 

	
 
    schedule = models.ForeignKey(Schedule)
 
    label = models.CharField(max_length=50)
 

	
 
    def __unicode__(self):
 
        return self.label
 

	
 

	
 
class Slot(models.Model):
 

	
 
    day = models.ForeignKey(Day)
 
    kind = models.ForeignKey(SlotKind)
 
    start = models.TimeField()
 
    end = models.TimeField()
 
    content_override = MarkupField(blank=True)
 

	
 
    def assign(self, content):
 
        """
 
        Assign the given content to this slot and if a previous slot content
 
        was given we need to unlink it to avoid integrity errors.
 
        """
 
        self.unassign()
 
        content.slot = self
 
        content.save()
 

	
 
    def unassign(self):
 
        """
 
        Unassign the associated content with this slot.
 
        """
 
        if self.content and self.content.slot_id:
 
            self.content.slot = None
 
            self.content.save()
 
            presentation = self.content
 
            presentation.slot = None
 
            presentation.save()
 

	
 
    @property
 
    def content(self):
 
        """
 
        Return the content this slot represents.
 
        @@@ hard-coded for presentation for now
 
        """
 
        try:
 
            return self.content_ptr
 
        except ObjectDoesNotExist:
 
            return None
 

	
 
    @property
 
    def start_datetime(self):
 
        return datetime.datetime(
 
            self.day.date.year,
 
            self.day.date.month,
 
            self.day.date.day,
 
            self.start.hour,
 
            self.start.minute)
 

	
 
    @property
 
    def end_datetime(self):
 
        return datetime.datetime(
 
            self.day.date.year,
 
            self.day.date.month,
 
            self.day.date.day,
 
            self.end.hour,
 
            self.end.minute)
 

	
 
    @property
 
    def length_in_minutes(self):
 
        return int(
 
            (self.end_datetime - self.start_datetime).total_seconds() / 60)
 

	
 
    @property
 
    def rooms(self):
 
        return Room.objects.filter(pk__in=self.slotroom_set.values("room"))
 

	
 
    def __unicode__(self):
 
        return "%s %s (%s - %s)" % (self.day, self.kind, self.start, self.end)
 

	
 
    class Meta:
 
        ordering = ["day", "start", "end"]
 

	
 

	
 
class SlotRoom(models.Model):
 
    """
 
    Links a slot with a room.
 
    """
 

	
 
    slot = models.ForeignKey(Slot)
 
    room = models.ForeignKey(Room)
 

	
 
    def __unicode__(self):
 
        return "%s %s" % (self.room, self.slot)
 

	
 
    class Meta:
 
        unique_together = [("slot", "room")]
 
        ordering = ["slot", "room__order"]
 

	
 

	
 
class Presentation(models.Model):
 

	
 
    slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr")
 
    title = models.CharField(max_length=100)
 
    description = MarkupField()
 
    abstract = MarkupField()
 
    speaker = models.ForeignKey("speakers.Speaker", related_name="presentations")
 
    additional_speakers = models.ManyToManyField("speakers.Speaker", related_name="copresentations",
 
                                                 blank=True)
 
    cancelled = models.BooleanField(default=False)
 
    proposal_base = models.OneToOneField(ProposalBase, related_name="presentation")
 
    section = models.ForeignKey(Section, related_name="presentations")
 

	
 
    @property
 
    def number(self):
 
        return self.proposal.number
 

	
 
    @property
 
    def proposal(self):
 
        if self.proposal_base_id is None:
 
            return None
 
        return ProposalBase.objects.get_subclass(pk=self.proposal_base_id)
 

	
 
    def speakers(self):
 
        yield self.speaker
 
        for speaker in self.additional_speakers.all():
 
            if speaker.user:
 
                yield speaker
 

	
 
    def __unicode__(self):
 
        return "#%s %s (%s)" % (self.number, self.title, self.speaker)
 

	
 
    class Meta:
 
        ordering = ["slot"]
symposion/schedule/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import url, patterns
 
from django.conf.urls import url, patterns
 

	
 

	
 
urlpatterns = patterns("symposion.schedule.views",
 
    url(r"^$", "schedule_conference", name="schedule_conference"),
 
    url(r"^edit/$", "schedule_edit", name="schedule_edit"),
 
    url(r"^list/$", "schedule_list", name="schedule_list"),
 
    url(r"^presentations.csv$", "schedule_list_csv", name="schedule_list_csv"),
 
    url(r"^presentation/(\d+)/$", "schedule_presentation_detail", name="schedule_presentation_detail"),
 
    url(r"^([\w\-]+)/$", "schedule_detail", name="schedule_detail"),
 
    url(r"^([\w\-]+)/edit/$", "schedule_edit", name="schedule_edit"),
 
    url(r"^([\w\-]+)/list/$", "schedule_list", name="schedule_list"),
 
    url(r"^([\w\-]+)/presentations.csv$", "schedule_list_csv", name="schedule_list_csv"),
 
    url(r"^([\w\-]+)/edit/slot/(\d+)/", "schedule_slot_edit", name="schedule_slot_edit"),
 
    url(r"^conference.json", "schedule_json", name="schedule_json"),
 
)
symposion/speakers/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import *
 
from django.conf.urls import patterns, url
 

	
 

	
 
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"),
 
    url(r"^staff/create/(\d+)/$", "speaker_create_staff", name="speaker_create_staff"),
 
)
symposion/sponsorship/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import patterns, url
 
from django.views.generic.simple import direct_to_template
 
from django.conf.urls import patterns, url
 
from django.views.generic import TemplateView
 

	
 

	
 
urlpatterns = patterns("symposion.sponsorship.views",
 
    url(r"^$", direct_to_template, {"template": "sponsorship/list.html"}, name="sponsor_list"),
 
    url(r"^$", TemplateView.as_view(template_name="sponsorship/list.html"), name="sponsor_list"),
 
    url(r"^apply/$", "sponsor_apply", name="sponsor_apply"),
 
    url(r"^add/$", "sponsor_add", name="sponsor_add"),
 
    url(r"^(?P<pk>\d+)/$", "sponsor_detail", name="sponsor_detail"),
 
)
symposion/teams/urls.py
Show inline comments
 
# flake8: noqa
 
from django.conf.urls.defaults import *
 
from django.conf.urls import patterns, url
 

	
 

	
 
urlpatterns = patterns("symposion.teams.views",
 
    # team specific
 
    url(r"^(?P<slug>[\w\-]+)/$", "team_detail", name="team_detail"),
 
    url(r"^(?P<slug>[\w\-]+)/join/$", "team_join", name="team_join"),
 
    url(r"^(?P<slug>[\w\-]+)/leave/$", "team_leave", name="team_leave"),
 
    url(r"^(?P<slug>[\w\-]+)/apply/$", "team_apply", name="team_apply"),
 

	
 
    # membership specific
 
    url(r"^promote/(?P<pk>\d+)/$", "team_promote", name="team_promote"),
 
    url(r"^demote/(?P<pk>\d+)/$", "team_demote", name="team_demote"),
 
    url(r"^accept/(?P<pk>\d+)/$", "team_accept", name="team_accept"),
 
    url(r"^reject/(?P<pk>\d+)/$", "team_reject", name="team_reject"),
 
)
0 comments (0 inline, 0 general)