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() # @@@ what is this used for?
@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 __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 Outline"),
max_length=400, # @@@ need to enforce 400 in UI
help_text="If your talk 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 description and outline. Will be made public if your talk is accepted. Edit using Markdown.")
)
additional_notes = MarkupField(
blank=True,
help_text=_("Anything else you'd like the program committee to know when making their selection: your past speaking experience, open source community experience, etc. Edit using Markdown.")
)
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 speaker_email(self):
return self.speaker.email
@property
def number(self):
return str(self.pk).zfill(3)
def speakers(self):
yield self.speaker
for speaker in self.additional_speakers.exclude(additionalspeaker__status=AdditionalSpeaker.SPEAKING_STATUS_DECLINED):
yield speaker
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()])