From a599f133a14410a252b096ee8ca8a22c31c6cde1 Mon Sep 17 00:00:00 2001 From: bkfox Date: Sun, 14 May 2017 22:33:11 +0200 Subject: [PATCH] add date into diffusion menu in wagtail nav; get larger menus in back-office --- aircox/admin.py | 11 ++-- aircox/management/commands/diffusions.py | 54 ++++------------- aircox/models.py | 60 ++++++++++++------- aircox_cms/admin.py | 3 + aircox_cms/static/wagtailadmin/css/core.css | 60 +++++++++---------- .../templates/aircox_cms/diffusion_page.html | 2 + .../templates/aircox_cms/program_page.html | 2 +- aircox_cms/wagtail_hooks.py | 17 +++++- notes.md | 20 +++++-- 9 files changed, 121 insertions(+), 108 deletions(-) diff --git a/aircox/admin.py b/aircox/admin.py index 2af1bee..eb807a9 100755 --- a/aircox/admin.py +++ b/aircox/admin.py @@ -101,9 +101,9 @@ class DiffusionAdmin(admin.ModelAdmin): sounds = [ str(s) for s in obj.get_archives()] return ', '.join(sounds) if sounds else '' - def conflicts(self, obj): - if obj.type == Diffusion.Type.unconfirmed: - return ', '.join([ str(d) for d in obj.get_conflicts()]) + def conflicts_(self, obj): + if obj.conflicts.count(): + return obj.conflicts.count() return '' def end_time(self, obj): @@ -113,12 +113,13 @@ class DiffusionAdmin(admin.ModelAdmin): def first(self, obj): return obj.initial.start if obj.initial else '' - list_display = ('id', 'program', 'start', 'end_time', 'type', 'first', 'archives', 'conflicts') + list_display = ('id', 'program', 'start', 'end_time', 'type', 'first', 'archives', 'conflicts_') list_filter = ('type', 'start', 'program') list_editable = ('type',) ordering = ('-start', 'id') - fields = ['type', 'start', 'end', 'initial', 'program'] + fields = ['type', 'start', 'end', 'initial', 'program', 'conflicts'] + readonly_fields = ('conflicts',) inlines = [ DiffusionInline, SoundInline ] diff --git a/aircox/management/commands/diffusions.py b/aircox/management/commands/diffusions.py index 9841411..8e4b28b 100755 --- a/aircox/management/commands/diffusions.py +++ b/aircox/management/commands/diffusions.py @@ -25,43 +25,12 @@ from aircox.models import * logger = logging.getLogger('aircox.tools') +import time + class Actions: - @staticmethod - def __check_conflicts (item, saved_items): - """ - Check for conflicts, and update conflictual - items if they have been generated during this - update. - - It set an attribute 'do_not_save' if the item should not - be saved. FIXME: find proper way - - Return the number of conflicts - """ - conflicts = list(item.get_conflicts()) - for i, conflict in enumerate(conflicts): - if conflict.program == item.program: - item.do_not_save = True - del conflicts[i] - continue - - if conflict.pk in saved_items and \ - conflict.type != Diffusion.Type.unconfirmed: - conflict.type = Diffusion.Type.unconfirmed - conflict.save() - - if not conflicts: - item.type = Diffusion.Type.normal - return 0 - - item.type = Diffusion.Type.unconfirmed - return len(conflicts) - @classmethod def update (cl, date, mode): manual = (mode == 'manual') - if not manual: - saved_items = set() count = [0, 0] for schedule in Schedule.objects.filter(program__active = True) \ @@ -71,16 +40,15 @@ class Actions: items = schedule.diffusions_of_month(date, exclude_saved = True) count[0] += len(items) - if manual: - Diffusion.objects.bulk_create(items) - else: - for item in items: - count[1] += cl.__check_conflicts(item, saved_items) - if hasattr(item, 'do_not_save'): - count[0] -= 1 - continue - item.save() - saved_items.add(item) + # we can't bulk create because we ned signal processing + for item in items: + conflicts = item.get_conflicts() + item.type = Diffusion.Type.unconfirmed \ + if manual or conflicts.count() else \ + Diffusion.Type.normal + item.save(no_check = True) + if conflicts.count(): + item.conflicts.set(conflicts.all()) logger.info('[update] schedule %s: %d new diffusions', str(schedule), len(items), diff --git a/aircox/models.py b/aircox/models.py index 8105994..22fcf22 100755 --- a/aircox/models.py +++ b/aircox/models.py @@ -720,19 +720,6 @@ class DiffusionManager(models.Manager): qs = self if qs is None else qs return qs.filter(program__station = station) - @staticmethod - def __in_range(field, range, field_ = None, reversed = False): - """ - Return a kwargs to catch diffusions based on the given field name - and datetime range. - """ - if reversed: - return { field + "__lte": range[1], - (field_ or field) + "__gte": range[0] } - - return { field + "__gte" : range[0], - (field_ or field) + "__lte" : range[1] } - def at(self, station, date = None, next = False, qs = None): """ Return diffusions occuring at the given date, ordered by +start @@ -754,22 +741,21 @@ class DiffusionManager(models.Manager): if isinstance(date, datetime.datetime): # use datetime: we want diffusion that occurs around this # range - range = date, date - filters = self.__in_range('start', range, 'end', True) + filters = { 'start__lte': date, 'end__gte': date } if next: qs = qs.filter( - models.Q(date__gte = date) | models.Q(**filters) + models.Q(start__gte = date) | models.Q(**filters) ) else: qs = qs.filter(**filters) else: # use date: we want diffusions that occurs this day - range = utils.date_range(date) - filters = models.Q(**self.__in_range('start', range)) | \ - models.Q(**self.__in_range('end', range)) + start, end = utils.date_range(date) + filters = models.Q(start__gte = start, start__lte = end) | \ + models.Q(end__gt = start, end__lt = end) if next: # include also diffusions of the next day - filters |= models.Q(start__gte = range[0]) + filters |= models.Q(start__gte = start) qs = qs.filter(filters) return self.station(station, qs).order_by('start').distinct() @@ -842,6 +828,12 @@ class Diffusion(models.Model): # blank = True, null = True, # help_text = _('use this input port'), # ) + conflicts = models.ManyToManyField( + 'self', + verbose_name = _('conflicts'), + blank = True, + help_text = _('conflicts'), + ) start = models.DateTimeField( _('start of the diffusion') ) end = models.DateTimeField( _('end of the diffusion') ) @@ -891,22 +883,44 @@ class Diffusion(models.Model): """ Return a list of conflictual diffusions, based on the scheduled duration. """ - r = Diffusion.objects.filter( + return Diffusion.objects.filter( models.Q(start__lt = self.start, end__gt = self.start) | models.Q(start__gt = self.start, start__lt = self.end) ) - return r - def save(self, *args, **kwargs): + def check_conflicts(self): + conflicts = self.get_conflicts() + self.conflicts.set(conflicts) + + __initial = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.__initial = { + 'start': self.start, + 'end': self.end, + } + + def save(self, no_check = False, *args, **kwargs): + if no_check: + return super().save(*args, **kwargs) + if self.initial: # force link to the top initial diffusion if self.initial.initial: self.initial = self.initial.initial self.program = self.initial.program + super().save(*args, **kwargs) + if self.__initial: + if self.start != self.__initial['start'] or \ + self.end != self.__initial['end']: + self.check_conflicts() + + def __str__(self): return '{self.program.name} {date} #{self.pk}'.format( self=self, date=self.date.strftime('%Y-%m-%d %H:%M') diff --git a/aircox_cms/admin.py b/aircox_cms/admin.py index 8c38f3f..3c21844 100755 --- a/aircox_cms/admin.py +++ b/aircox_cms/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin # Register your models here. + + + diff --git a/aircox_cms/static/wagtailadmin/css/core.css b/aircox_cms/static/wagtailadmin/css/core.css index 3d5ec48..47d7d32 100644 --- a/aircox_cms/static/wagtailadmin/css/core.css +++ b/aircox_cms/static/wagtailadmin/css/core.css @@ -150,7 +150,7 @@ @-webkit-keyframes MenuAnimOut1 { 50% { - -webkit-transform: translateZ(-250px) rotateY(30deg); + -webkit-transform: translateZ(-220px) rotateY(30deg); } 75% { -webkit-transform: translateZ(-372.5px) rotateY(15deg); @@ -192,8 +192,8 @@ @keyframes MenuAnimOut1 { 50% { - -webkit-transform: translateZ(-250px) rotateY(30deg); - transform: translateZ(-250px) rotateY(30deg); + -webkit-transform: translateZ(-220px) rotateY(30deg); + transform: translateZ(-220px) rotateY(30deg); } 75% { -webkit-transform: translateZ(-372.5px) rotateY(15deg); @@ -270,7 +270,7 @@ opacity: 0; } 20% { - -webkit-transform: translateZ(-250px) rotateY(30deg); + -webkit-transform: translateZ(-220px) rotateY(30deg); opacity: 0.5; } 100% { @@ -330,8 +330,8 @@ opacity: 0; } 20% { - -webkit-transform: translateZ(-250px) rotateY(30deg); - transform: translateZ(-250px) rotateY(30deg); + -webkit-transform: translateZ(-220px) rotateY(30deg); + transform: translateZ(-220px) rotateY(30deg); opacity: 0.5; } 100% { @@ -1932,7 +1932,7 @@ body.ready .fade { @media screen and (min-width: 50em) { .modal-dialog { - padding: 0 0 2em 180px; + padding: 0 0 2em 220px; } } @@ -3846,7 +3846,7 @@ table.listing { } .listing.images > li .image { text-align: center; - height: 180px; + height: 220px; } .listing.images > li .image:before { content: ''; @@ -4881,8 +4881,8 @@ body.ready .progress .bar { .nav-wrapper { position: relative; - margin-left: -180px; - width: 180px; + margin-left: -220px; + width: 220px; float: left; height: 100%; min-height: 800px; @@ -5005,13 +5005,13 @@ body.ready .nav-main a { display: none; } -.nav-submenu .menu-item a { - white-space: normal; - padding: 0.9em 1.7em 0.9em 4.5em; +.nav-submenu .menu-item .info { + margin-right: 1em; } -.nav-submenu .menu-item a:before { - margin-left: -1.5em; +.nav-submenu .menu-item a { + white-space: normal; + padding: 0.9em 1em 0.9em 1em; } .nav-submenu .menu-item a:hover { @@ -5106,8 +5106,8 @@ body.ready .nav-main a { } body.nav-open .wrapper { - transform: translate3d(180px, 0, 0); - -webkit-transform: translate3d(180px, 0, 0); + transform: translate3d(220px, 0, 0); + -webkit-transform: translate3d(220px, 0, 0); } body.nav-open .content-wrapper { @@ -5163,7 +5163,7 @@ body.explorer-open .explorer-close { -webkit-transform: none; -ms-transform: none; transform: none; - padding-left: 180px; + padding-left: 220px; } .nav-wrapper { position: absolute; @@ -5174,7 +5174,7 @@ body.explorer-open .explorer-close { .nav-wrapper .inner { height: 100%; position: fixed; - width: 180px; + width: 220px; } .nav-toggle { display: none; @@ -5186,7 +5186,7 @@ body.explorer-open .explorer-close { } .nav-main .footer { position: fixed; - width: 180px; + width: 220px; bottom: 0; } .nav-main .footer-open .footer-submenu { @@ -5256,14 +5256,14 @@ body.explorer-open .explorer-close { width: 0; padding: 0; top: 0; - left: 180px; + left: 220px; overflow: auto; max-height: 100%; } .nav-submenu h2, .nav-submenu ul { float: right; - width: 180px; + width: 220px; } .nav-submenu h2 { display: block; @@ -5296,14 +5296,14 @@ body.explorer-open .explorer-close { } li.submenu-active .nav-submenu { box-shadow: 2px 0 2px rgba(0, 0, 0, 0.35); - width: 180px; - padding: 0 0 1.5em; + width: 220px; + padding: 0 0 0.5em; } body.ready li.submenu-active .nav-submenu { transition: width 0.2s ease; } li.submenu-active .nav-submenu a { - padding-left: 3.5em; + padding-left: 1em; } .explorer { width: 400px; @@ -5325,7 +5325,7 @@ body.explorer-open .explorer-close { } body.explorer-open .nav-wrapper { margin-left: 0; - width: 180px; + width: 220px; } body.explorer-open .explorer:before { display: none; @@ -5356,7 +5356,7 @@ body.explorer-open .explorer-close { -webkit-transform: none; -ms-transform: none; transform: none; - left: 180px; + left: 220px; position: relative; } body.explorer-open .wrapper { @@ -5375,7 +5375,7 @@ body.explorer-open .explorer-close { left: 0; } body.explorer-open .nav-wrapper { - width: 180px; + width: 220px; } } @@ -5603,7 +5603,7 @@ body.explorer-open .explorer-close { position: absolute; z-index: 25; top: 0; - left: 180px; + left: 220px; } #wagtail .c-state-indicator { @@ -5811,7 +5811,7 @@ footer li { } footer .actions { - width: 250px; + width: 220px; margin-right: 1.5%; } diff --git a/aircox_cms/templates/aircox_cms/diffusion_page.html b/aircox_cms/templates/aircox_cms/diffusion_page.html index 5a9625c..8ea064e 100755 --- a/aircox_cms/templates/aircox_cms/diffusion_page.html +++ b/aircox_cms/templates/aircox_cms/diffusion_page.html @@ -18,6 +18,7 @@ {% endif %} {% endwith %} +{% if diffusion.diffusion_set.count %}

{% trans "Dates of diffusion" %}

+{% endif %} {% with podcasts=self.get_podcasts %} {% if podcasts %} diff --git a/aircox_cms/templates/aircox_cms/program_page.html b/aircox_cms/templates/aircox_cms/program_page.html index 9eb5af5..bfa7d46 100755 --- a/aircox_cms/templates/aircox_cms/program_page.html +++ b/aircox_cms/templates/aircox_cms/program_page.html @@ -8,7 +8,7 @@ {% block content_extras %}
-{% if page.program.active %} +{% if page.program.active and page.program.schedule_set.count %}

{% trans "Schedule" %}