PonyConf/proposals/models.py

197 lines
6.6 KiB
Python

from enum import IntEnum
from datetime import timedelta
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.utils import timezone
from autoslug import AutoSlugField
from colorful.fields import RGBColorField
from accounts.models import Participation
from ponyconf.utils import PonyConfModel, enum_to_choices
from planning.models import Room
from .utils import query_sum
class Conference(models.Model):
site = models.OneToOneField(Site, on_delete=models.CASCADE)
home = models.TextField(blank=True, default="")
venue = models.TextField(blank=True, default="")
city = models.CharField(max_length=64, blank=True, default="")
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
def __str__(self):
return str(self.site)
class Track(PonyConfModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE)
name = models.CharField(max_length=128, verbose_name=_('Name'))
slug = AutoSlugField(populate_from='name')
description = models.TextField(blank=True, verbose_name=_('Description'))
managers = models.ManyToManyField(User, blank=True, verbose_name=_('Managers'))
class Meta:
unique_together = ('site', 'name')
def estimated_duration(self):
return sum([talk.estimated_duration for talk in self.talk_set.all()])
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('list-talks') + '?track=%s' % self.slug
class Topic(PonyConfModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE)
name = models.CharField(max_length=128, verbose_name=_('Name'))
slug = AutoSlugField(populate_from='name', unique=True)
description = models.TextField(blank=True, verbose_name=_('Description'))
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Destination track'))
reviewers = models.ManyToManyField(User, blank=True, verbose_name=_('Reviewers'))
class Meta:
unique_together = ('site', 'name')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('list-talks') + '?topic=%s' % self.slug
class Event(models.Model):
site = models.ForeignKey(Site, on_delete=models.CASCADE)
name = models.CharField(max_length=64)
duration = models.PositiveIntegerField(default=0, verbose_name=_('Default duration (min)'))
color = RGBColorField(default='#ffffff', verbose_name=_("Color on program"))
class Meta:
unique_together = ('site', 'name')
ordering = ('pk',)
def __str__(self):
return ugettext(self.name)
def get_absolute_url(self):
return reverse('list-talks') + '?kind=%d' % self.pk
class Talk(PonyConfModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE)
proposer = models.ForeignKey(User, related_name='+')
speakers = models.ManyToManyField(User, verbose_name=_('Speakers'))
title = models.CharField(max_length=128, verbose_name=_('Title'), help_text=_('After submission, title can only be changed by the staff.'))
slug = AutoSlugField(populate_from='title', unique=True)
abstract = models.CharField(max_length=255, blank=True, verbose_name=_('Abstract'))
description = models.TextField(blank=True, verbose_name=_('Description'))
topics = models.ManyToManyField(Topic, blank=True, verbose_name=_('Topics'), help_text=_('The topics can not be changed after submission.'))
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'))
notes = models.TextField(blank=True, verbose_name=_('Notes'))
event = models.ForeignKey(Event, verbose_name=_('Intervention kind'))
accepted = models.NullBooleanField(default=None)
start_date = models.DateTimeField(null=True, blank=True, default=None)
duration = models.PositiveIntegerField(default=0, verbose_name=_('Duration (min)'))
room = models.ForeignKey(Room, blank=True, null=True, default=None)
plenary = models.BooleanField(default=False)
class Meta:
ordering = ('title',)
def __str__(self):
return self.title
def get_speakers_str(self):
speakers = [str(Participation.objects.get(site=self.site, user=speaker)) for speaker in self.speakers.all()]
if len(speakers) == 0:
return 'superman'
elif len(speakers) == 1:
return speakers[0]
else:
return ', '.join(speakers[:-1]) + ' & ' + str(speakers[-1])
@property
def estimated_duration(self):
return self.duration or self.event.duration
def get_absolute_url(self):
return reverse('show-talk', kwargs={'slug': self.slug})
def is_moderable_by(self, user):
if user.is_superuser:
return True
try:
participation = Participation.objects.get(site=self.site, user=user)
except Participation.DoesNotExists:
return False
if participation.orga:
return True
if self.topics.filter(reviewers=user).exists():
return True
if self.track and user in self.track.managers.all():
return True
return False
def is_editable_by(self, user):
return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
def score(self):
if self.vote_set.exists():
return query_sum(self.vote_set, 'vote') / len(self.vote_set.all())
else:
return 0
@property
def end_date(self):
if self.estimated_duration:
return self.start_date + timedelta(minutes=self.estimated_duration)
else:
return None
class Meta:
ordering = ('event__id',)
class Vote(PonyConfModel):
talk = models.ForeignKey(Talk)
user = models.ForeignKey(User)
vote = models.IntegerField(validators=[MinValueValidator(-2), MaxValueValidator(2)], default=0)
class Meta:
unique_together = ('talk', 'user')
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()