252697b842
Upgrade site and modules to Django 2.2. Remove and replace obsolete functionality with current equivalents. Update requirements to latest versions where possible. Remove unused dependencies.
404 lines
11 KiB
Python
404 lines
11 KiB
Python
import datetime
|
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.contrib.auth import get_user_model
|
|
from django.db import models
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from symposion.managers import DefaultSelectRelatedManager
|
|
from symposion.text_parser import parse
|
|
from symposion.proposals.models import ProposalBase
|
|
from symposion.conference.models import Section
|
|
from symposion.speakers.models import Speaker
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class Schedule(models.Model):
|
|
objects = DefaultSelectRelatedManager()
|
|
|
|
section = models.OneToOneField(
|
|
Section,
|
|
verbose_name=_("Section"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
published = models.BooleanField(default=True, verbose_name=_("Published"))
|
|
hidden = models.BooleanField(_("Hide schedule from overall conference view"), default=False)
|
|
|
|
def __str__(self):
|
|
return "%s Schedule" % self.section
|
|
|
|
class SymposionMeta:
|
|
select_related = ('section', )
|
|
|
|
class Meta:
|
|
ordering = ["section"]
|
|
verbose_name = _('Schedule')
|
|
verbose_name_plural = _('Schedules')
|
|
|
|
|
|
class Day(models.Model):
|
|
objects = DefaultSelectRelatedManager()
|
|
|
|
|
|
schedule = models.ForeignKey(
|
|
Schedule,
|
|
verbose_name=_("Schedule"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
date = models.DateField(verbose_name=_("Date"))
|
|
|
|
def __str__(self):
|
|
return "%s: %s" % (self.schedule.section.name, self.date)
|
|
|
|
class SymposionMeta:
|
|
select_related = ('schedule__section', )
|
|
|
|
class Meta:
|
|
unique_together = [("schedule", "date")]
|
|
ordering = ["date"]
|
|
verbose_name = _("date")
|
|
verbose_name_plural = _("dates")
|
|
|
|
|
|
class Room(models.Model):
|
|
|
|
schedule = models.ForeignKey(
|
|
Schedule,
|
|
verbose_name=_("Schedule"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
name = models.CharField(max_length=65, verbose_name=_("Name"))
|
|
order = models.PositiveIntegerField(verbose_name=_("Order"))
|
|
|
|
def __unicode__(self):
|
|
return self.name
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class Meta:
|
|
verbose_name = _("Room")
|
|
verbose_name_plural = _("Rooms")
|
|
|
|
|
|
class Track(models.Model):
|
|
name = models.CharField(max_length=80, verbose_name=_("Track"))
|
|
room = models.ForeignKey(Room, on_delete=models.CASCADE)
|
|
day = models.ForeignKey(Day, on_delete=models.CASCADE)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class Meta:
|
|
unique_together = [('room', 'day')]
|
|
verbose_name = _("Track")
|
|
verbose_name_plural = _("Tracks")
|
|
|
|
|
|
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,
|
|
verbose_name=_("schedule"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
label = models.CharField(max_length=50, verbose_name=_("Label"))
|
|
|
|
def __str__(self):
|
|
return ": ".join((self.schedule.section.name, self.label))
|
|
|
|
class Meta:
|
|
verbose_name = _("Slot kind")
|
|
verbose_name_plural = _("Slot kinds")
|
|
|
|
|
|
class Slot(models.Model):
|
|
objects = DefaultSelectRelatedManager()
|
|
|
|
name = models.CharField(max_length=512, editable=False)
|
|
day = models.ForeignKey(
|
|
Day,
|
|
verbose_name=_("Day"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
kind = models.ForeignKey(
|
|
SlotKind,
|
|
verbose_name=_("Kind"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
start = models.TimeField(verbose_name=_("Start"))
|
|
end = models.TimeField(verbose_name=_("End"))
|
|
exclusive = models.BooleanField(
|
|
default=False,
|
|
help_text=_("Set to true if this is the only event during this "
|
|
"timeslot"),
|
|
)
|
|
content_override = models.TextField(blank=True, verbose_name=_("Content override"))
|
|
content_override_html = models.TextField(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.
|
|
"""
|
|
content = self.content
|
|
if content and content.slot_id:
|
|
content.slot = None
|
|
content.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 save(self, *args, **kwargs):
|
|
roomlist = ' '.join(map(str, self.rooms))
|
|
self.name = "%s %s (%s - %s) %s" % (self.day.date, self.kind.label, self.start, self.end, roomlist)
|
|
self.content_override_html = parse(self.content_override)
|
|
super(Slot, self).save(*args, **kwargs)
|
|
|
|
def __str__(self):
|
|
return "%s: %s" % (self.day.schedule.section.name, self.name)
|
|
|
|
class SymposionMeta:
|
|
select_related = ('kind__schedule__section', 'day')
|
|
|
|
class Meta:
|
|
ordering = ["day__schedule__section__name", "day", "start" ]
|
|
verbose_name = _("slot")
|
|
verbose_name_plural = _("slots")
|
|
|
|
|
|
class SlotRoom(models.Model):
|
|
"""
|
|
Links a slot with a room.
|
|
"""
|
|
|
|
slot = models.ForeignKey(
|
|
Slot,
|
|
verbose_name=_("Slot"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
room = models.ForeignKey(
|
|
Room,
|
|
verbose_name=_("Room"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
|
|
def __str__(self):
|
|
return "%s %s" % (self.room, self.slot)
|
|
|
|
class Meta:
|
|
unique_together = [("slot", "room")]
|
|
ordering = ["slot", "room__order"]
|
|
verbose_name = _("Slot room")
|
|
verbose_name_plural = _("Slot rooms")
|
|
|
|
|
|
class Presentation(models.Model):
|
|
objects = DefaultSelectRelatedManager()
|
|
|
|
slot = models.OneToOneField(
|
|
Slot,
|
|
null=True,
|
|
blank=True,
|
|
related_name="content_ptr",
|
|
verbose_name=_("Slot"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
title = models.CharField(max_length=100, verbose_name=_("Title"))
|
|
abstract = models.TextField(verbose_name=_("Abstract"))
|
|
abstract_html = models.TextField(blank=True)
|
|
speaker = models.ForeignKey(
|
|
Speaker,
|
|
related_name="presentations",
|
|
verbose_name=_("Speaker"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations",
|
|
blank=True, verbose_name=_("Additional speakers"))
|
|
unpublish = models.BooleanField(
|
|
default=False,
|
|
verbose_name=_("Do not publish"),
|
|
)
|
|
cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled"))
|
|
proposal_base = models.OneToOneField(
|
|
ProposalBase,
|
|
related_name="presentation",
|
|
verbose_name=_("Proposal base"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
section = models.ForeignKey(
|
|
Section,
|
|
related_name="presentations",
|
|
verbose_name=_("Section"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
|
|
def save(self, *args, **kwargs):
|
|
self.abstract_html = parse(self.abstract)
|
|
return super(Presentation, self).save(*args, **kwargs)
|
|
|
|
@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 __str__(self):
|
|
return "#%s %s (%s)" % (self.number, self.title, self.speaker)
|
|
|
|
class Meta:
|
|
ordering = ["slot"]
|
|
verbose_name = _("presentation")
|
|
verbose_name_plural = _("presentations")
|
|
|
|
|
|
class Session(models.Model):
|
|
|
|
day = models.ForeignKey(
|
|
Day,
|
|
related_name="sessions",
|
|
verbose_name=_("Day"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
slots = models.ManyToManyField(Slot, related_name="sessions", verbose_name=_("Slots"))
|
|
|
|
def sorted_slots(self):
|
|
return self.slots.order_by("start")
|
|
|
|
def start(self):
|
|
slots = self.sorted_slots()
|
|
if slots:
|
|
return list(slots)[0].start
|
|
else:
|
|
return None
|
|
|
|
def end(self):
|
|
slots = self.sorted_slots()
|
|
if slots:
|
|
return list(slots)[-1].end
|
|
else:
|
|
return None
|
|
|
|
def chair(self):
|
|
for role in self.sessionrole_set.all():
|
|
if role.role == SessionRole.SESSION_ROLE_CHAIR:
|
|
return role
|
|
return None
|
|
|
|
@property
|
|
def rooms(self):
|
|
return Room.objects.filter(slotroom__slot__in=self.slots.all()).distinct()
|
|
|
|
@property
|
|
def room_names(self):
|
|
return ', '.join(room.name for room in self.rooms)
|
|
|
|
def __str__(self):
|
|
start = self.start()
|
|
end = self.end()
|
|
rooms = ', '.join(room.name for room in self.rooms)
|
|
if start and end:
|
|
return "%s: %s - %s in %s" % (
|
|
self.day.date.strftime("%a"),
|
|
start.strftime("%X"),
|
|
end.strftime("%X"),
|
|
rooms
|
|
)
|
|
return ""
|
|
|
|
class Meta:
|
|
verbose_name = _("Session")
|
|
verbose_name_plural = _("Sessions")
|
|
|
|
|
|
class SessionRole(models.Model):
|
|
|
|
SESSION_ROLE_CHAIR = 1
|
|
SESSION_ROLE_RUNNER = 2
|
|
|
|
SESSION_ROLE_TYPES = [
|
|
(SESSION_ROLE_CHAIR, _("Session Chair")),
|
|
(SESSION_ROLE_RUNNER, _("Session Runner")),
|
|
]
|
|
|
|
session = models.ForeignKey(
|
|
Session,
|
|
verbose_name=_("Session"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
user = models.ForeignKey(
|
|
User,
|
|
verbose_name=_("User"),
|
|
on_delete=models.CASCADE,
|
|
)
|
|
role = models.IntegerField(choices=SESSION_ROLE_TYPES, verbose_name=_("Role"))
|
|
status = models.NullBooleanField(verbose_name=_("Status"))
|
|
|
|
submitted = models.DateTimeField(default=datetime.datetime.now)
|
|
|
|
class Meta:
|
|
unique_together = [("session", "user", "role")]
|
|
verbose_name = _("Session role")
|
|
verbose_name_plural = _("Session roles")
|
|
|
|
def __str__(self):
|
|
return "%s %s: %s" % (self.user, self.session,
|
|
self.SESSION_ROLE_TYPES[self.role - 1][1])
|