Files @ 6d5c24e6354f
Branch filter:

Location: symposion_app/symposion/proposals/models.py - annotation

Patrick Altman
Merge pull request #56 from chromano/master

Fix flake8 warnings
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
63d07f8db31c
7596922f4d68
7596922f4d68
7596922f4d68
6cf7a62da1cb
6cf7a62da1cb
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7b4c5cd205b5
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
e00b646f20bf
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
36ab6d599ffc
63d07f8db31c
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
36ab6d599ffc
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
96830f3c215f
7596922f4d68
36ab6d599ffc
36ab6d599ffc
7596922f4d68
7596922f4d68
63d07f8db31c
36ab6d599ffc
36ab6d599ffc
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
36ab6d599ffc
36ab6d599ffc
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
36ab6d599ffc
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
36ab6d599ffc
7e7d85c7e7bb
7e7d85c7e7bb
7e7d85c7e7bb
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
36ab6d599ffc
36ab6d599ffc
36ab6d599ffc
7596922f4d68
36ab6d599ffc
bd2fd5338d8d
bd2fd5338d8d
bd2fd5338d8d
bd2fd5338d8d
bd2fd5338d8d
bd2fd5338d8d
7596922f4d68
7596922f4d68
6cf7a62da1cb
6cf7a62da1cb
6cf7a62da1cb
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
63d07f8db31c
63d07f8db31c
63d07f8db31c
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
36ab6d599ffc
7596922f4d68
7596922f4d68
7596922f4d68
7596922f4d68
36ab6d599ffc
36ab6d599ffc
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.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(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:
            return False
        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,
        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)

    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()])