diff --git a/cms/models.py b/cms/models.py index 53b0e42..4e2eb4a 100644 --- a/cms/models.py +++ b/cms/models.py @@ -648,7 +648,7 @@ class LogsPage(DatedListPage): logs = [] for date in context['nav_dates']['dates']: - items = self.station.get_on_air(date) + items = self.station.on_air(date = date) items = [ self.as_item(item) for item in items ] logs.append((date, items)) return logs diff --git a/cms/sections.py b/cms/sections.py index f375952..e20e690 100644 --- a/cms/sections.py +++ b/cms/sections.py @@ -32,6 +32,10 @@ from modelcluster.fields import ParentalKey from modelcluster.tags import ClusterTaggableManager from taggit.models import TaggedItemBase +# aircox +import aircox.programs.models as programs + + def related_pages_filter(reset_cache=False): """ @@ -398,12 +402,12 @@ class DatedListBase(models.Model): return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ] - def get_date_context(self, date): + def get_date_context(self, date = None): """ Return a dict that can be added to the context to be used by a date_list. """ - today = tz.now().today() + today = tz.now().date() if not date: date = today @@ -809,3 +813,41 @@ class SectionList(ListBase, SectionItem): ) return context + +@register_snippet +class SectionTimetable(SectionItem,DatedListBase): + panels = SectionItem.panels + DatedListBase.panels + + def get_queryset(self, context): + from aircox.cms.models import DiffusionPage + diffs = [] + for date in context['nav_dates']['dates']: + items = programs.Diffusion.objects.get_at(date).order_by('start') + items = [ DiffusionPage.as_item(item) for item in items ] + diffs.append((date, items)) + return diffs + + def get_context(self, request, page, *args, **kwargs): + context = super().get_context(request, page, *args, **kwargs) + context.update(self.get_date_context()) + context['object_list'] = self.get_queryset(context) + return context + + +@register_snippet +class SectionLogs(SectionItem): + count = models.SmallIntegerField( + _('count'), + default = 5, + help_text = _('number of items to display in the list'), + ) + + panels = SectionItem.panels + [ + FieldPanel('count'), + ] + + def get_context(self, request, page, *args, **kwargs): + pass + + + diff --git a/cms/wagtail_hooks.py b/cms/wagtail_hooks.py index 92207f9..764c4b0 100644 --- a/cms/wagtail_hooks.py +++ b/cms/wagtail_hooks.py @@ -74,7 +74,7 @@ class DiffusionsMenu(GenericMenu): def get_queryset(self): return programs.Diffusion.objects.filter( type = programs.Diffusion.Type.normal, - start__contains = tz.now().date() + tz.timedelta(days=2), + start__contains = tz.now().date(), ).order_by('start') def get_title(self, item): diff --git a/controllers/models.py b/controllers/models.py index 1cdde1d..444db29 100644 --- a/controllers/models.py +++ b/controllers/models.py @@ -150,7 +150,7 @@ class Station(programs.Nameable): * archive: if false, exclude log of diffusion's archives from the queryset; """ - qs = Log.get_for(model = models) \ + qs = Log.objects.get_for(model = models) \ .filter(station = self, type = Log.Type.play) if not archives and self.dealer: qs = qs.exclude( @@ -161,45 +161,66 @@ class Station(programs.Nameable): ) return qs.order_by('date') - def get_on_air(self, date = None): + + @staticmethod + def __mix_logs_and_diff(diffs, logs, count = 0): """ - Return a list of what should have normally been on air at the - given date, ordered descending on the diffusion time + Mix together logs and diffusion items ordering by their date. + Diffs and Logs are assumed to be ordered by -date, and so is + the resulting list + """ + # we fill a list with diff and retrieve logs that happened between + # each to put them too there + items = [] + diff_ = None + for diff in diffs: + logs_ = \ + logs.filter(date__gt = diff.end, date__lt = diff_.start) \ + if diff_ else logs.filter(date__gt = diff.end) + diff_ = diff + items.extends(logs_) + items.append(diff) + if count and len(items) >= count: + break + + if diff_ and not count or len(items) <= count: + logs_ = logs.filter(date__lt = diff_.end) + items.extend(logs_) + + return items[:count] if count else items + + + def on_air(self, date = None, count = 0): + """ + Return a list of what happened on air, based on logs and + diffusions informations. The list is sorted by -date. + + * date: only for what happened on this date; + * count: number of items to retrieve if not zero; + + Be careful with what you which for: the result is a plain list. The list contains: - - track logs: for the streamed programs; - - diffusion: for the scheduled diffusions; + * track logs: for the streamed programs; + * diffusion: for the scheduled diffusions; """ - # TODO: argument to get sound instead of tracks + # FIXME: as an iterator? + # TODO argument to get sound instead of tracks + # TODO #Station date = date or tz.now().date() if date > datetime.date.today(): return [] - logs = Log.get_for(model = programs.Track) \ - .filter(date__contains = date) \ - .order_by('date') - diffs = programs.Diffusion.objects.get_at(date) \ - .filter(type = programs.Diffusion.Type.normal) \ - .order_by('start') - - # mix up - items = [] - prev_diff = None - for diff in diffs: - logs_ = logs.filter(date__gt = prev_diff.end, - date__lt = diff.start) \ - if prev_diff else \ - logs.filter(date__lt = diff.start) - prev_diff = diff - items.extend(logs_) - items.append(diff) - - # last logs - if prev_diff: - logs_ = logs.filter(date__gt = prev_diff.end) - items.extend(logs_) - return reversed(items) - + logs = Log.objects.get_for(model = programs.Track) \ + .filter(station = self) \ + .order_by('-date') + diffs = programs.Diffusion.objects \ + .filter(type = Diffusion.Type.normal) \ + .order_by('-date') + if date: + logs = logs.filter(date__contains = date) + diffs = diffs.get_at(date) + return self.__mix_logs_and_diff(diffs, logs, count) def save(self, make_sources = True, *args, **kwargs): diff --git a/controllers/monitor.py b/controllers/monitor.py index 7027664..db7c1e9 100644 --- a/controllers/monitor.py +++ b/controllers/monitor.py @@ -66,7 +66,7 @@ class Monitor: if not current_sound or not current_source: return - log = Log.get_for(model = programs.Sound) \ + log = Log.objects.get_for(model = programs.Sound) \ .filter(station = self.station).order_by('date').last() # only streamed @@ -92,11 +92,11 @@ class Monitor: Log tracks for the given sound (for streamed programs); Called by self.trace """ - logs = Log.get_for(model = programs.Track) \ + logs = Log.objects.get_for(model = programs.Track) \ .filter(pk__gt = log.pk) logs = [ log.related_id for log in logs ] - tracks = programs.Track.get_for(object = log.related) \ + tracks = programs.Track.objects.get_for(object = log.related) \ .filter(in_seconds = True) if tracks and len(tracks) == len(logs): return diff --git a/programs/management/commands/sounds_monitor.py b/programs/management/commands/sounds_monitor.py index 6661b02..e45d154 100644 --- a/programs/management/commands/sounds_monitor.py +++ b/programs/management/commands/sounds_monitor.py @@ -127,7 +127,7 @@ class SoundInfo: if not os.path.exists(path): return - old = Track.get_for(object = sound) + old = Track.objects.get_for(object = sound) if old: return diff --git a/programs/models.py b/programs/models.py index 0a15419..ce53900 100755 --- a/programs/models.py +++ b/programs/models.py @@ -45,6 +45,29 @@ def date_or_default(date, no_time = False): return date +class RelatedManager(models.Manager): + def get_for(self, object = None, model = None): + """ + Return a queryset that filter on the given object or model(s) + + * object: if given, use its type and pk; match on models only. + * model: one model or an iterable of models + """ + if not model and object: + model = type(object) + + if hasattr(model, '__iter__'): + model = [ ContentType.objects.get_for_model(m).id + for m in model ] + qs = self.filter(related_type__pk__in = model) + else: + model = ContentType.objects.get_for_model(model) + qs = self.filter(related_type__pk = model.id) + if object: + qs = qs.filter(related_id = object.pk) + return qs + + class Related(models.Model): """ Add a field "related" of type GenericForeignKey, plus utilities. @@ -60,28 +83,7 @@ class Related(models.Model): 'related_type', 'related_id', ) - @classmethod - def get_for(cl, object = None, model = None): - """ - Return a queryset that filter on the given object or model(s) - - * object: if given, use its type and pk; match on models only. - * model: one model or list of models - """ - if not model and object: - model = type(object) - - if type(model) in (list, tuple): - model = [ ContentType.objects.get_for_model(m).id - for m in model ] - qs = cl.objects.filter(related_type__pk__in = model) - else: - model = ContentType.objects.get_for_model(model) - qs = cl.objects.filter(related_type__pk = model.id) - - if object: - qs = qs.filter(related_id = object.pk) - return qs + objects = RelatedManager() class Meta: abstract = True