forked from rc/aircox
new management tool: add
This commit is contained in:
@ -1,45 +1,38 @@
|
||||
import datetime
|
||||
import os
|
||||
|
||||
# django
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.template.defaultfilters import slugify
|
||||
|
||||
from django.http import HttpResponse, Http404
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
# extensions
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
|
||||
import programs.settings as settings
|
||||
|
||||
|
||||
|
||||
AFrequency = {
|
||||
'ponctual': 0x000000,
|
||||
'every week': 0b001111,
|
||||
'first week': 0x000001,
|
||||
'second week': 0x000010,
|
||||
'third week': 0x000100,
|
||||
'fourth week': 0x001000,
|
||||
'first and third': 0x000101,
|
||||
'second and fourth': 0x001010,
|
||||
'one week on two': 0x010010,
|
||||
#'uneven week': 0x100000,
|
||||
# TODO 'every day': 0x110000
|
||||
Frequency = {
|
||||
'ponctual': 0b000000
|
||||
, 'every week': 0b001111
|
||||
, 'first week': 0b000001
|
||||
, 'second week': 0b000010
|
||||
, 'third week': 0b000100
|
||||
, 'fourth week': 0b001000
|
||||
, 'first and third': 0b000101
|
||||
, 'second and fourth': 0b001010
|
||||
, 'one week on two': 0b010010
|
||||
#'uneven week': 0b100000
|
||||
# TODO 'every day': 0b110000
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Translators: html safe values
|
||||
ugettext_lazy('ponctual')
|
||||
ugettext_lazy('every week')
|
||||
@ -52,10 +45,15 @@ ugettext_lazy('second and fourth')
|
||||
ugettext_lazy('one week on two')
|
||||
|
||||
|
||||
Frequency = [ (y, x) for x,y in AFrequency.items() ]
|
||||
RFrequency = { y: x for x,y in AFrequency.items() }
|
||||
EventType = {
|
||||
'play': 0x02 # the sound is playing / planified to play
|
||||
, 'cancel': 0x03 # the sound has been canceled from grid; useful to give
|
||||
# the info to the users
|
||||
, 'stop': 0x04 # the sound has been arbitrary stopped (non-stop or not)
|
||||
, 'non-stop': 0x05 # the sound has been played as non-stop
|
||||
#, 'streaming'
|
||||
}
|
||||
|
||||
Frequency.sort(key = lambda e: e[0])
|
||||
|
||||
|
||||
class Model (models.Model):
|
||||
@ -106,7 +104,7 @@ class Metadata (Model):
|
||||
)
|
||||
date = models.DateTimeField(
|
||||
_('date')
|
||||
, default = datetime.datetime.now
|
||||
, default = timezone.datetime.now
|
||||
)
|
||||
public = models.BooleanField(
|
||||
_('public')
|
||||
@ -190,12 +188,6 @@ class Publication (Metadata):
|
||||
#
|
||||
# Instance's methods
|
||||
#
|
||||
def get_parent (self, raise_404 = False ):
|
||||
if not parent and raise_404:
|
||||
raise Http404
|
||||
return parent
|
||||
|
||||
|
||||
def get_parents ( self, order_by = "desc", include_fields = None ):
|
||||
"""
|
||||
Return an array of the parents of the item.
|
||||
@ -262,10 +254,9 @@ class SoundFile (Metadata):
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
file = models.FileField(
|
||||
file = models.FileField( #FIXME: filefield
|
||||
_('file')
|
||||
, upload_to = "data/tracks"
|
||||
, blank = True
|
||||
, upload_to = lambda i, f: SoundFile.__upload_path(i,f)
|
||||
)
|
||||
duration = models.TimeField(
|
||||
_('duration')
|
||||
@ -277,12 +268,24 @@ class SoundFile (Metadata):
|
||||
, default = False
|
||||
, help_text = _("the file has been cut")
|
||||
)
|
||||
embed = models.TextField (
|
||||
embed = models.TextField(
|
||||
_('embed HTML code from external website')
|
||||
, blank = True
|
||||
, null = True
|
||||
, help_text = _('if set, consider the sound podcastable from there')
|
||||
)
|
||||
removed = models.BooleanField(
|
||||
default = False
|
||||
, help_text = _('this sound has been removed from filesystem')
|
||||
)
|
||||
|
||||
|
||||
def __upload_path (self, filename):
|
||||
if self.parent and self.parent.parent:
|
||||
path = self.parent.parent.path
|
||||
else:
|
||||
path = settings.AIRCOX_SOUNDFILE_DEFAULT_DIR
|
||||
return os.path.join(path, filename)
|
||||
|
||||
|
||||
def __str__ (self):
|
||||
@ -294,29 +297,44 @@ class SoundFile (Metadata):
|
||||
verbose_name_plural = _('Sounds')
|
||||
|
||||
|
||||
|
||||
class Schedule (Model):
|
||||
parent = models.ForeignKey( 'Program', blank = True, null = True )
|
||||
date = models.DateTimeField(_('start'))
|
||||
duration = models.TimeField(_('duration'))
|
||||
frequency = models.SmallIntegerField(_('frequency'), choices = Frequency)
|
||||
duration = models.TimeField(
|
||||
_('duration')
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
frequency = models.SmallIntegerField(
|
||||
_('frequency')
|
||||
, choices = [ (y, x) for x,y in Frequency.items() ]
|
||||
)
|
||||
rerun = models.BooleanField(_('rerun'), default = False)
|
||||
|
||||
|
||||
def match_week (self, at = datetime.date.today()):
|
||||
def match_date (self, at = timezone.datetime.today()):
|
||||
"""
|
||||
Return True if the given datetime matches the schedule
|
||||
"""
|
||||
if self.date.weekday() == at.weekday() and self.match_week(date):
|
||||
return self.date.time() == at.date.time()
|
||||
return False
|
||||
|
||||
|
||||
def match_week (self, at = timezone.datetime.today()):
|
||||
"""
|
||||
Return True if the given week number matches the schedule, False
|
||||
otherwise.
|
||||
If the schedule is ponctual, return None.
|
||||
"""
|
||||
if self.frequency == AFrequency['ponctual']:
|
||||
if self.frequency == Frequency['ponctual']:
|
||||
return None
|
||||
|
||||
if self.frequency == AFrequency['one week on two']:
|
||||
if self.frequency == Frequency['one week on two']:
|
||||
week = at.isocalendar()[1]
|
||||
return (week % 2) == (self.date.isocalendar()[1] % 2)
|
||||
|
||||
first_of_month = datetime.date(at.year, at.month, 1)
|
||||
first_of_month = timezone.datetime.date(at.year, at.month, 1)
|
||||
week = at.isocalendar()[1] - first_of_month.isocalendar()[1]
|
||||
|
||||
# weeks of month
|
||||
@ -326,30 +344,29 @@ class Schedule (Model):
|
||||
return (self.frequency & (0b0001 << week) > 0)
|
||||
|
||||
|
||||
|
||||
def next_date (self, at = datetime.date.today()):
|
||||
if self.frequency == AFrequency['ponctual']:
|
||||
def next_date (self, at = timezone.datetime.today()):
|
||||
if self.frequency == Frequency['ponctual']:
|
||||
return None
|
||||
|
||||
# first day of the week
|
||||
date = at - datetime.timedelta( days = at.weekday() )
|
||||
date = at - timezone.timedelta( days = at.weekday() )
|
||||
|
||||
# for the next five week, we look for a matching week.
|
||||
# when found, add the number of day since de start of the
|
||||
# we need to test if the result is >= at
|
||||
for i in range(0,5):
|
||||
if self.match_week(date):
|
||||
date_ = date + datetime.timedelta( days = self.date.weekday() )
|
||||
date_ = date + timezone.timedelta( days = self.date.weekday() )
|
||||
if date_ >= at:
|
||||
# we don't want past events
|
||||
return datetime.datetime(date_.year, date_.month, date_.day,
|
||||
return timezone.datetime(date_.year, date_.month, date_.day,
|
||||
self.date.hour, self.date.minute)
|
||||
date += datetime.timedelta( days = 7 )
|
||||
date += timezone.timedelta( days = 7 )
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def next_dates (self, at = datetime.date.today(), n = 52):
|
||||
def next_dates (self, at = timezone.datetime.today(), n = 52):
|
||||
# we could have optimized this function, but since it should not
|
||||
# be use too often, we keep a more readable and easier to debug
|
||||
# solution
|
||||
@ -362,20 +379,20 @@ class Schedule (Model):
|
||||
if not e:
|
||||
break
|
||||
res.append(e)
|
||||
at = res[-1] + datetime.timedelta(days = 1)
|
||||
at = res[-1] + timezone.timedelta(days = 1)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def to_string(self):
|
||||
s = ugettext_lazy( RFrequency[self.frequency] )
|
||||
if self.rerun:
|
||||
return s + ' (' + _('rerun') + ')'
|
||||
return s
|
||||
|
||||
#def to_string(self):
|
||||
# s = ugettext_lazy( RFrequency[self.frequency] )
|
||||
# if self.rerun:
|
||||
# return s + ' (' + _('rerun') + ')'
|
||||
# return s
|
||||
|
||||
def __str__ (self):
|
||||
return self.parent.title + ': ' + RFrequency[self.frequency]
|
||||
frequency = [ x for x,y in Frequency.items() if y == self.frequency ]
|
||||
return self.parent.title + ': ' + frequency[0]
|
||||
|
||||
|
||||
class Meta:
|
||||
@ -427,15 +444,17 @@ class Program (Publication):
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
tag = models.CharField(
|
||||
_('tag')
|
||||
, max_length = 64
|
||||
, help_text = _('used in articles to refer to it')
|
||||
non_stop = models.SmallIntegerField(
|
||||
_('non-stop priority')
|
||||
, help_text = _('this program can be used as non-stop')
|
||||
, default = -1
|
||||
)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return settings.AIRCOX_PROGRAMS_DATA + slugify(self.title + '_' + self.id)
|
||||
return os.path.join( settings.AIRCOX_PROGRAMS_DIR
|
||||
, slugify(self.title + '_' + str(self.id))
|
||||
)
|
||||
|
||||
|
||||
class Meta:
|
||||
@ -455,8 +474,6 @@ class Episode (Publication):
|
||||
parent = models.ForeignKey(
|
||||
Program
|
||||
, verbose_name = _('parent')
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
tracks = models.ManyToManyField(
|
||||
Track
|
||||
@ -473,37 +490,22 @@ class Episode (Publication):
|
||||
|
||||
class Event (Model):
|
||||
"""
|
||||
Event logs and planification of a sound file
|
||||
"""
|
||||
parent = models.ForeignKey (
|
||||
Episode
|
||||
, verbose_name = _('episode')
|
||||
, blank = True
|
||||
, null = True
|
||||
sound = models.ForeignKey (
|
||||
SoundFile
|
||||
, verbose_name = _('sound file')
|
||||
)
|
||||
date = models.DateTimeField( _('date of start') )
|
||||
date_end = models.DateTimeField(
|
||||
_('date of end')
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
public = models.BooleanField(
|
||||
_('public')
|
||||
, default = False
|
||||
, help_text = _('publication is accessible to the public')
|
||||
type = models.SmallIntegerField(
|
||||
_('type')
|
||||
, choices = [ (y, x) for x,y in EventType.items() ]
|
||||
)
|
||||
date = models.DateTimeField( _('date of event start') )
|
||||
meta = models.TextField (
|
||||
_('meta')
|
||||
, blank = True
|
||||
, null = True
|
||||
)
|
||||
canceled = models.BooleanField( _('canceled'), default = False )
|
||||
|
||||
|
||||
def testify (self):
|
||||
parent = self.parent
|
||||
self.parent.testify()
|
||||
self.parent.date = self.date
|
||||
return self.parent
|
||||
|
||||
|
||||
class Meta:
|
||||
|
Reference in New Issue
Block a user