-
Notifications
You must be signed in to change notification settings - Fork 147
/
models.py
184 lines (136 loc) · 5.38 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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):
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
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=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=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()])