2016-06-12 20:45:22 +00:00
|
|
|
from enum import IntEnum
|
|
|
|
|
2016-06-12 17:00:04 +00:00
|
|
|
from django.contrib.auth.models import User
|
2016-06-11 13:47:08 +00:00
|
|
|
from django.contrib.sites.models import Site
|
2016-06-12 16:35:59 +00:00
|
|
|
from django.core.urlresolvers import reverse
|
2016-06-29 23:13:59 +00:00
|
|
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
2016-06-11 13:47:08 +00:00
|
|
|
from django.db import models
|
2016-07-23 10:03:12 +00:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2016-08-22 15:23:01 +00:00
|
|
|
from django.utils.translation import ugettext
|
2016-09-28 19:17:56 +00:00
|
|
|
from django.utils import timezone
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-06-11 13:47:08 +00:00
|
|
|
from autoslug import AutoSlugField
|
2016-10-16 21:36:03 +00:00
|
|
|
from colorful.fields import RGBColorField
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-06-19 23:00:08 +00:00
|
|
|
from accounts.models import Participation
|
2016-06-25 11:39:28 +00:00
|
|
|
from ponyconf.utils import PonyConfModel, enum_to_choices
|
2016-10-11 09:31:32 +00:00
|
|
|
from planning.models import Room
|
2016-06-12 20:45:22 +00:00
|
|
|
|
2016-07-01 23:03:07 +00:00
|
|
|
from .utils import query_sum
|
|
|
|
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-08-07 10:51:38 +00:00
|
|
|
class Conference(models.Model):
|
|
|
|
|
2016-09-28 17:44:06 +00:00
|
|
|
site = models.OneToOneField(Site, on_delete=models.CASCADE)
|
2016-08-07 10:51:38 +00:00
|
|
|
home = models.TextField(blank=True, default="")
|
2016-09-28 19:17:56 +00:00
|
|
|
cfp_opening_date = models.DateTimeField(null=True, blank=True, default=None)
|
|
|
|
cfp_closing_date = models.DateTimeField(null=True, blank=True, default=None)
|
|
|
|
|
|
|
|
def cfp_is_open(self):
|
|
|
|
now = timezone.now()
|
|
|
|
if self.cfp_opening_date and now < self.cfp_opening_date:
|
|
|
|
return False
|
|
|
|
if self.cfp_closing_date and now > self.cfp_closing_date:
|
|
|
|
return False
|
|
|
|
return True
|
2016-08-07 10:51:38 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.site)
|
|
|
|
|
|
|
|
|
2016-09-22 22:51:07 +00:00
|
|
|
class Track(PonyConfModel):
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-07-06 16:30:15 +00:00
|
|
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
|
|
|
|
2016-07-23 10:03:12 +00:00
|
|
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
2016-09-22 22:51:07 +00:00
|
|
|
slug = AutoSlugField(populate_from='name')
|
2016-08-07 08:20:26 +00:00
|
|
|
description = models.TextField(blank=True, verbose_name=_('Description'))
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-10-05 19:06:10 +00:00
|
|
|
managers = models.ManyToManyField(User, blank=True, verbose_name=_('Managers'))
|
|
|
|
|
2016-07-11 20:58:46 +00:00
|
|
|
class Meta:
|
|
|
|
unique_together = ('site', 'name')
|
|
|
|
|
2016-10-05 19:46:59 +00:00
|
|
|
def estimated_duration(self):
|
|
|
|
return sum([talk.estimated_duration() for talk in self.talk_set.all()])
|
|
|
|
|
2016-06-07 20:59:13 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2016-09-28 20:55:51 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('list-talks') + '?track=%s' % self.slug
|
|
|
|
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-09-22 22:51:07 +00:00
|
|
|
class Topic(PonyConfModel):
|
2016-09-21 22:53:09 +00:00
|
|
|
|
|
|
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
|
|
|
|
|
|
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
2016-09-22 22:51:07 +00:00
|
|
|
slug = AutoSlugField(populate_from='name', unique=True)
|
2016-09-21 22:53:09 +00:00
|
|
|
description = models.TextField(blank=True, verbose_name=_('Description'))
|
2016-09-22 22:51:07 +00:00
|
|
|
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Destination track'))
|
|
|
|
|
|
|
|
reviewers = models.ManyToManyField(User, blank=True, verbose_name=_('Reviewers'))
|
2016-09-21 22:53:09 +00:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ('site', 'name')
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2016-09-22 22:51:07 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('list-talks') + '?topic=%s' % self.slug
|
|
|
|
|
2016-09-21 22:53:09 +00:00
|
|
|
|
2016-08-22 15:23:01 +00:00
|
|
|
class Event(models.Model):
|
|
|
|
|
|
|
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
|
|
|
name = models.CharField(max_length=64)
|
2016-10-16 21:36:03 +00:00
|
|
|
duration = models.IntegerField(default=0, verbose_name=_('Default duration (min)'))
|
|
|
|
color = RGBColorField(default='#ffffff', verbose_name=_("Color on program"))
|
2016-08-22 15:23:01 +00:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ('site', 'name')
|
2016-09-18 00:00:46 +00:00
|
|
|
ordering = ('pk',)
|
2016-08-22 15:23:01 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return ugettext(self.name)
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-09-18 00:34:48 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('list-talks') + '?kind=%d' % self.pk
|
|
|
|
|
2016-08-22 15:23:01 +00:00
|
|
|
|
|
|
|
class Talk(PonyConfModel):
|
2016-06-12 20:45:22 +00:00
|
|
|
|
2016-06-07 20:59:13 +00:00
|
|
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
|
|
|
|
2016-06-14 21:58:04 +00:00
|
|
|
proposer = models.ForeignKey(User, related_name='+')
|
2016-07-23 10:03:12 +00:00
|
|
|
speakers = models.ManyToManyField(User, verbose_name=_('Speakers'))
|
2016-10-15 12:05:27 +00:00
|
|
|
title = models.CharField(max_length=128, verbose_name=_('Title'), help_text=_('After submission, title can only be changed by the staff.'))
|
2016-06-07 20:59:13 +00:00
|
|
|
slug = AutoSlugField(populate_from='title', unique=True)
|
2016-08-08 21:54:05 +00:00
|
|
|
abstract = models.CharField(max_length=255, blank=True, verbose_name=_('Abstract'))
|
2016-07-23 10:03:12 +00:00
|
|
|
description = models.TextField(blank=True, verbose_name=_('Description'))
|
2016-10-15 12:05:27 +00:00
|
|
|
topics = models.ManyToManyField(Topic, blank=True, verbose_name=_('Topics'), help_text=_('The topics can not be changed after submission.'))
|
2016-09-21 22:53:09 +00:00
|
|
|
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'))
|
2016-08-08 21:54:05 +00:00
|
|
|
notes = models.TextField(blank=True, verbose_name=_('Notes'))
|
2016-09-03 22:36:06 +00:00
|
|
|
event = models.ForeignKey(Event, verbose_name=_('Intervention kind'))
|
2016-07-03 20:39:29 +00:00
|
|
|
accepted = models.NullBooleanField(default=None)
|
2016-10-11 17:20:36 +00:00
|
|
|
start_date = models.DateTimeField(null=True, blank=True, default=None)
|
2016-10-05 20:14:31 +00:00
|
|
|
duration = models.IntegerField(default=0, verbose_name=_('Duration (min)'))
|
2016-10-11 17:20:36 +00:00
|
|
|
room = models.ForeignKey(Room, blank=True, null=True, default=None)
|
2016-06-07 20:59:13 +00:00
|
|
|
|
2016-09-18 15:15:10 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ('title',)
|
|
|
|
|
2016-06-07 20:59:13 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.title
|
|
|
|
|
2016-10-16 21:36:03 +00:00
|
|
|
def get_speakers_str(self):
|
|
|
|
speakers = [str(speaker) for speaker in self.speakers.all()]
|
|
|
|
if len(speakers) == 1:
|
|
|
|
return speakers[0]
|
|
|
|
else:
|
|
|
|
return ', '.join(speakers[:-1]) + ' & ' + str(speakers[-1])
|
|
|
|
|
2016-10-05 19:46:59 +00:00
|
|
|
def estimated_duration(self):
|
|
|
|
return self.duration or self.event.duration
|
|
|
|
|
2016-06-12 16:35:59 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('show-talk', kwargs={'slug': self.slug})
|
|
|
|
|
2016-07-01 21:42:22 +00:00
|
|
|
def is_moderable_by(self, user):
|
2016-06-14 21:58:04 +00:00
|
|
|
if user.is_superuser:
|
|
|
|
return True
|
|
|
|
try:
|
2016-07-09 19:30:49 +00:00
|
|
|
participation = Participation.objects.get(site=self.site, user=user)
|
2016-06-14 21:58:04 +00:00
|
|
|
except Participation.DoesNotExists:
|
|
|
|
return False
|
2016-10-08 18:31:28 +00:00
|
|
|
if participation.orga:
|
|
|
|
return True
|
2016-10-10 11:55:18 +00:00
|
|
|
if self.topics.filter(reviewers=user).exists():
|
2016-10-08 18:31:28 +00:00
|
|
|
return True
|
2016-10-10 11:55:18 +00:00
|
|
|
if self.track and user in self.track.managers.all():
|
2016-10-08 18:31:28 +00:00
|
|
|
return True
|
|
|
|
return False
|
2016-06-29 23:13:59 +00:00
|
|
|
|
2016-07-01 21:42:22 +00:00
|
|
|
def is_editable_by(self, user):
|
|
|
|
return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
|
|
|
|
|
2016-07-01 23:03:07 +00:00
|
|
|
def score(self):
|
2016-09-16 16:12:21 +00:00
|
|
|
if self.vote_set.exists():
|
|
|
|
return query_sum(self.vote_set, 'vote') / len(self.vote_set.all())
|
|
|
|
else:
|
|
|
|
return 0
|
2016-07-01 23:03:07 +00:00
|
|
|
|
2016-08-21 22:28:14 +00:00
|
|
|
class Meta:
|
2016-08-22 15:23:01 +00:00
|
|
|
ordering = ('event__id',)
|
2016-08-21 22:28:14 +00:00
|
|
|
|
2016-06-29 23:13:59 +00:00
|
|
|
|
|
|
|
class Vote(PonyConfModel):
|
|
|
|
|
|
|
|
talk = models.ForeignKey(Talk)
|
2016-07-11 19:33:34 +00:00
|
|
|
user = models.ForeignKey(User)
|
2016-06-29 23:13:59 +00:00
|
|
|
vote = models.IntegerField(validators=[MinValueValidator(-2), MaxValueValidator(2)], default=0)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ('talk', 'user')
|
2016-07-01 23:03:07 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return "%+i by %s for %s" % (self.vote, self.user, self.talk)
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
|
return self.talk.get_absolute_url()
|