forked from rc/aircox
		
	start working on schedule command/view
This commit is contained in:
		@ -54,15 +54,15 @@ class MetadataAdmin (admin.ModelAdmin):
 | 
			
		||||
class PublicationAdmin (MetadataAdmin):
 | 
			
		||||
    fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
 | 
			
		||||
 | 
			
		||||
    list_display = ('id', 'title', 'date', 'status')
 | 
			
		||||
    list_filter = ['date', 'status']
 | 
			
		||||
    list_display = ('id', 'title', 'date', 'public')
 | 
			
		||||
    list_filter = ['date', 'public']
 | 
			
		||||
    search_fields = ['title', 'content']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__ (self, *args, **kwargs):
 | 
			
		||||
        self.fieldsets[0][1]['fields'].insert(1, 'subtitle')
 | 
			
		||||
        self.fieldsets[0][1]['fields'] += [ 'img', 'content' ]
 | 
			
		||||
        self.fieldsets[1][1]['fields'] += [ 'parent', 'status', 'enable_comments', 'meta' ],
 | 
			
		||||
        self.fieldsets[1][1]['fields'] += [ 'parent', 'public', 'can_comment', 'meta' ],
 | 
			
		||||
        return super(PublicationAdmin, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,12 @@ from django.core.management.base           import BaseCommand, CommandError
 | 
			
		||||
import programs.models                     as models
 | 
			
		||||
import programs.settings
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
 | 
			
		||||
class Command (BaseCommand):
 | 
			
		||||
    help= "Take a look at the programs directory to check on new podcasts"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def handle(self, *args, **options):
 | 
			
		||||
    def handle (self, *args, **options):
 | 
			
		||||
        programs = models.Program.objects.filter(schedule__isnull = True)
 | 
			
		||||
 | 
			
		||||
        for program in programs:
 | 
			
		||||
@ -24,6 +23,10 @@ class Command(BaseCommand):
 | 
			
		||||
            for filename in os.listdir(path):
 | 
			
		||||
                long_filename = path + '/' + filename
 | 
			
		||||
 | 
			
		||||
                # check for new sound files
 | 
			
		||||
                # stat the sound files
 | 
			
		||||
                # match sound files against episodes - if not found, create it
 | 
			
		||||
                # upload public podcasts to mixcloud if required
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										72
									
								
								programs/management/commands/schedule.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								programs/management/commands/schedule.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.core.management.base            import BaseCommand, CommandError
 | 
			
		||||
from django.utils                           import timezone, dateformat
 | 
			
		||||
 | 
			
		||||
import programs.models                      as models
 | 
			
		||||
import programs.settings
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Diffusion:
 | 
			
		||||
    ref = None
 | 
			
		||||
    date_start = None
 | 
			
		||||
    date_end = None
 | 
			
		||||
 | 
			
		||||
    def __init__ (self, ref, date_start, date_end):
 | 
			
		||||
        self.ref = ref
 | 
			
		||||
        self.date_start = date_start
 | 
			
		||||
        self.date_end = date_end
 | 
			
		||||
 | 
			
		||||
    def __lt__ (self, d):
 | 
			
		||||
        return self.date_start < d.date_start and \
 | 
			
		||||
               self.date_end < d.date_end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Command (BaseCommand):
 | 
			
		||||
    help= "check sounds to diffuse"
 | 
			
		||||
 | 
			
		||||
    diffusions = set()
 | 
			
		||||
 | 
			
		||||
    def handle(self, *args, **options):
 | 
			
		||||
        self.get_next_events()
 | 
			
		||||
        self.get_next_episodes()
 | 
			
		||||
 | 
			
		||||
        for diffusion in self.diffusions:
 | 
			
		||||
            print( diffusion.ref.__str__()
 | 
			
		||||
                 , diffusion.date_start
 | 
			
		||||
                 , diffusion.date_end)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_next_episodes (self):
 | 
			
		||||
        schedules = models.Schedule.objects.filter()
 | 
			
		||||
        for schedule in schedules:
 | 
			
		||||
            date = schedule.next_date()
 | 
			
		||||
            if not date:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            dt = datetime.timedelta( hours = schedule.duration.hour
 | 
			
		||||
                                   , minutes = schedule.duration.minute
 | 
			
		||||
                                   , seconds = schedule.duration.second )
 | 
			
		||||
 | 
			
		||||
            ref = models.Episode.objects.filter(date = date)[:1]
 | 
			
		||||
            if not ref:
 | 
			
		||||
                ref = ( schedule.parent, )
 | 
			
		||||
 | 
			
		||||
            diffusion = Diffusion(ref[0], date, date + dt)
 | 
			
		||||
            self.diffusions.add(diffusion)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_next_events (self):
 | 
			
		||||
        events = models.Event.objects.filter(date_end__gt = timezone.now(),
 | 
			
		||||
                                             canceled = False) \
 | 
			
		||||
                                     .extra(order_by = ['date'])[:10]
 | 
			
		||||
        for event in events:
 | 
			
		||||
            diffusion = Diffusion(event, event.date, event.date_end)
 | 
			
		||||
            self.diffusions.add(diffusion)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,17 +25,6 @@ import programs.settings                    as settings
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AStatus = {
 | 
			
		||||
    'private':    0,
 | 
			
		||||
    'public':     1,
 | 
			
		||||
    #  'canceled':   2,
 | 
			
		||||
    #  'finished':   3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Status = [ (y, ugettext_lazy(x)) for x,y in AStatus.items() ]
 | 
			
		||||
RStatus = { y: x  for x,y in AStatus.items() }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AFrequency = {
 | 
			
		||||
    'ponctual':          0x000000,
 | 
			
		||||
    'every week':        0b001111,
 | 
			
		||||
@ -106,23 +95,33 @@ class Metadata (Model):
 | 
			
		||||
    meta is used to extend a model for future needs
 | 
			
		||||
    """
 | 
			
		||||
    author      = models.ForeignKey (
 | 
			
		||||
                        User,
 | 
			
		||||
                        verbose_name = _('author'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
    date            = models.DateTimeField(
 | 
			
		||||
                        _('date'),
 | 
			
		||||
                        default = datetime.datetime.now )
 | 
			
		||||
                      User
 | 
			
		||||
                    , verbose_name = _('author')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    title       = models.CharField(
 | 
			
		||||
                        _('title'),
 | 
			
		||||
                        max_length = 128 )
 | 
			
		||||
                      _('title')
 | 
			
		||||
                    , max_length = 128
 | 
			
		||||
                  )
 | 
			
		||||
    date        = models.DateTimeField(
 | 
			
		||||
                      _('date')
 | 
			
		||||
                    , default = datetime.datetime.now
 | 
			
		||||
                  )
 | 
			
		||||
    public      = models.BooleanField(
 | 
			
		||||
                      _('public')
 | 
			
		||||
                    , default = False
 | 
			
		||||
                    , help_text = _('publication is accessible to the public')
 | 
			
		||||
                  )
 | 
			
		||||
    meta        = models.TextField(
 | 
			
		||||
                        _('meta'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
                      _('meta')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    tags        = TaggableManager(
 | 
			
		||||
                        _('tags'),
 | 
			
		||||
                        blank = True )
 | 
			
		||||
                      _('tags')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
@ -137,37 +136,35 @@ class Publication (Metadata):
 | 
			
		||||
        return self.title + ' (' + str(self.id) + ')'
 | 
			
		||||
 | 
			
		||||
    subtitle    = models.CharField(
 | 
			
		||||
                        _('subtitle'),
 | 
			
		||||
                        max_length = 128,
 | 
			
		||||
                        blank = True )
 | 
			
		||||
                      _('subtitle')
 | 
			
		||||
                    , max_length = 128
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
    img         = models.ImageField(
 | 
			
		||||
                        _('image'),
 | 
			
		||||
                        upload_to = "images",
 | 
			
		||||
                        blank = True )
 | 
			
		||||
                      _('image')
 | 
			
		||||
                    , upload_to = "images"
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
    content     = models.TextField(
 | 
			
		||||
                        _('content'),
 | 
			
		||||
                        blank = True )
 | 
			
		||||
    status          = models.SmallIntegerField(
 | 
			
		||||
                        _('status'),
 | 
			
		||||
                        choices = Status,
 | 
			
		||||
                        default = AStatus['public'] )
 | 
			
		||||
    enable_comments = models.BooleanField(
 | 
			
		||||
                        _('enable comments'),
 | 
			
		||||
                        default = True,
 | 
			
		||||
                        help_text = 'select to enable comments')
 | 
			
		||||
 | 
			
		||||
                      _('content')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
    can_comment = models.BooleanField(
 | 
			
		||||
                      _('enable comments')
 | 
			
		||||
                    , default = True
 | 
			
		||||
                    , help_text = _('comments are enabled on this publication')
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # Class methods
 | 
			
		||||
    #
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _exclude_args (allow_unpublished = False, prefix = ''):
 | 
			
		||||
        if allow_unpublished:
 | 
			
		||||
            return {}
 | 
			
		||||
 | 
			
		||||
        res = {}
 | 
			
		||||
        res[prefix + 'status'] = AStatus['private']
 | 
			
		||||
        res[prefix + 'public'] = False
 | 
			
		||||
        res[prefix + 'date__gt'] = timezone.now()
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
@ -180,7 +177,7 @@ class Publication (Metadata):
 | 
			
		||||
 | 
			
		||||
        Otherwise, return None
 | 
			
		||||
        """
 | 
			
		||||
        kwargs['status'] = AStatus['public']
 | 
			
		||||
        kwargs['public'] = True
 | 
			
		||||
        kwargs['date__lte'] = timezone.now()
 | 
			
		||||
 | 
			
		||||
        e = cl.objects.filter(**kwargs)
 | 
			
		||||
@ -193,10 +190,6 @@ class Publication (Metadata):
 | 
			
		||||
    #
 | 
			
		||||
    # Instance's methods
 | 
			
		||||
    #
 | 
			
		||||
    def is_private (self):
 | 
			
		||||
        return self.status == AStatus['private']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_parent (self, raise_404 = False ):
 | 
			
		||||
        if not parent and raise_404:
 | 
			
		||||
            raise Http404
 | 
			
		||||
@ -230,22 +223,24 @@ class Publication (Metadata):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Final models
 | 
			
		||||
# Usable models
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class Track (Model):
 | 
			
		||||
    artist      = models.CharField(
 | 
			
		||||
                        _('artist'),
 | 
			
		||||
                        max_length = 128,
 | 
			
		||||
                        blank = True)
 | 
			
		||||
                      _('artist')
 | 
			
		||||
                    , max_length = 128
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
    title       = models.CharField(
 | 
			
		||||
                        _('title'),
 | 
			
		||||
                        max_length = 128 )
 | 
			
		||||
                      _('title')
 | 
			
		||||
                    , max_length = 128
 | 
			
		||||
                  )
 | 
			
		||||
    version     = models.CharField(
 | 
			
		||||
                        _('version'),
 | 
			
		||||
                        max_length = 128,
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        help_text = _('additional informations on that track'))
 | 
			
		||||
                      _('version')
 | 
			
		||||
                    , max_length = 128
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , help_text = _('additional informations on that track')
 | 
			
		||||
                  )
 | 
			
		||||
    tags        = TaggableManager( blank = True )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -262,31 +257,31 @@ class Track (Model):
 | 
			
		||||
 | 
			
		||||
class SoundFile (Metadata):
 | 
			
		||||
    parent      = models.ForeignKey(
 | 
			
		||||
                        'Episode',
 | 
			
		||||
                        verbose_name = _('episode'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
                      'Episode'
 | 
			
		||||
                    , verbose_name = _('episode')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    file        = models.FileField(
 | 
			
		||||
                        _('file'),
 | 
			
		||||
                        upload_to = "data/tracks",
 | 
			
		||||
                        blank = True )
 | 
			
		||||
                      _('file')
 | 
			
		||||
                    , upload_to = "data/tracks"
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
    duration    = models.TimeField(
 | 
			
		||||
                        _('duration'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
    podcastable     = models.BooleanField(
 | 
			
		||||
                        _('podcastable'),
 | 
			
		||||
                        default = False,
 | 
			
		||||
                        help_text = _('if checked, the file can be podcasted from this server'))
 | 
			
		||||
                      _('duration')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    fragment    = models.BooleanField(
 | 
			
		||||
                        _('incomplete sound'),
 | 
			
		||||
                        default = False,
 | 
			
		||||
                        help_text = _("the file has been cut"))
 | 
			
		||||
                      _('incomplete sound')
 | 
			
		||||
                    , default = False
 | 
			
		||||
                    , help_text = _("the file has been cut")
 | 
			
		||||
                  )
 | 
			
		||||
    embed       = models.TextField (
 | 
			
		||||
                        _('embed HTML code from external website'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True,
 | 
			
		||||
                        help_text = _('if set, consider the sound podcastable from there')
 | 
			
		||||
                      _('embed HTML code from external website')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                    , help_text = _('if set, consider the sound podcastable from there')
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -300,12 +295,11 @@ class SoundFile (Metadata):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Schedule (Model):
 | 
			
		||||
    parent      = models.ForeignKey( 'Program', blank = True, null = True )
 | 
			
		||||
    date            = models.DateTimeField(_('schedule'))
 | 
			
		||||
    frequency       = models.SmallIntegerField(_('frequency'), choices = Frequency)
 | 
			
		||||
    date        = models.DateTimeField(_('start'))
 | 
			
		||||
    duration    = models.TimeField(_('duration'))
 | 
			
		||||
    frequency   = models.SmallIntegerField(_('frequency'), choices = Frequency)
 | 
			
		||||
    rerun       = models.BooleanField(_('rerun'), default = False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -337,7 +331,6 @@ class Schedule (Model):
 | 
			
		||||
        if self.frequency == AFrequency['ponctual']:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        print('#####')
 | 
			
		||||
        # first day of the week
 | 
			
		||||
        date = at - datetime.timedelta( days = at.weekday() )
 | 
			
		||||
 | 
			
		||||
@ -394,17 +387,20 @@ class Schedule (Model):
 | 
			
		||||
 | 
			
		||||
class Article (Publication):
 | 
			
		||||
    parent      = models.ForeignKey(
 | 
			
		||||
                        'self',
 | 
			
		||||
                        verbose_name = _('parent'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
                      'self'
 | 
			
		||||
                    , verbose_name = _('parent')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    static_page = models.BooleanField(
 | 
			
		||||
                        _('static page'),
 | 
			
		||||
                        default = False )
 | 
			
		||||
                      _('static page')
 | 
			
		||||
                    , default = False
 | 
			
		||||
                  )
 | 
			
		||||
    focus       = models.BooleanField(
 | 
			
		||||
                        _('article is focus'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        default = False )
 | 
			
		||||
                      _('article is focus')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , default = False
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
@ -457,14 +453,16 @@ class Episode (Publication):
 | 
			
		||||
    #   Duration can be retrieved from the sound file if there is one.
 | 
			
		||||
    #
 | 
			
		||||
    parent      = models.ForeignKey(
 | 
			
		||||
                        Program,
 | 
			
		||||
                        verbose_name = _('parent'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
                      Program
 | 
			
		||||
                    , verbose_name = _('parent')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    tracks      = models.ManyToManyField(
 | 
			
		||||
                        Track,
 | 
			
		||||
                        verbose_name = _('playlist'),
 | 
			
		||||
                        blank = True )
 | 
			
		||||
                      Track
 | 
			
		||||
                    , verbose_name = _('playlist')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                  )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
@ -477,25 +475,27 @@ class Event (Model):
 | 
			
		||||
    """
 | 
			
		||||
    """
 | 
			
		||||
    parent      = models.ForeignKey (
 | 
			
		||||
                        Episode,
 | 
			
		||||
                        verbose_name = _('episode'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
 | 
			
		||||
                      Episode
 | 
			
		||||
                    , verbose_name = _('episode')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    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')
 | 
			
		||||
                  )
 | 
			
		||||
    meta        = models.TextField (
 | 
			
		||||
                        _('meta'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True )
 | 
			
		||||
    date            = models.DateTimeField( _('date') )
 | 
			
		||||
    duration        = models.TimeField(
 | 
			
		||||
                        _('duration'),
 | 
			
		||||
                        blank = True,
 | 
			
		||||
                        null = True,
 | 
			
		||||
                        help_text = _('this is just indicative'))
 | 
			
		||||
    status          = models.SmallIntegerField(
 | 
			
		||||
                        _('status'),
 | 
			
		||||
                        choices = Status,
 | 
			
		||||
                        default = AStatus['public'] )
 | 
			
		||||
                      _('meta')
 | 
			
		||||
                    , blank = True
 | 
			
		||||
                    , null = True
 | 
			
		||||
                  )
 | 
			
		||||
    canceled    = models.BooleanField( _('canceled'), default = False )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user