diff --git a/program/admin.py b/program/admin.py index db186ff7ef2aaa6b257042b8cfe35dc8fa75a6a7..e84d76fbfa24b19afe220c4f953a7d011d7f9fdc 100644 --- a/program/admin.py +++ b/program/admin.py @@ -8,7 +8,6 @@ from .forms import MusicFocusForm, CollisionForm from datetime import date, datetime, time, timedelta - class ActivityFilter(admin.SimpleListFilter): title = _("Activity") @@ -106,10 +105,6 @@ class NoteAdmin(admin.ModelAdmin): obj.save() -class TimeSlotAdmin(admin.ModelAdmin): - model = TimeSlot - template_name = 'calendar.html' - class TimeSlotInline(admin.TabularInline): model = TimeSlot ordering = ('-end',) @@ -405,7 +400,7 @@ class ShowAdmin(admin.ModelAdmin): self.programslot = programslot self.timeslots = timeslots self.collisions = collisions - self.num_collisions = len([ s for s in self.collisions if s != None]) # Number of real collisions displayed to the user + self.num_collisions = len([ s for s in self.collisions if s != 'None']) # Number of real collisions displayed to the user self.notes = notes self.showform = form self.programslotsform = formset diff --git a/program/models.py b/program/models.py index aa6e6b30790b526394c90963bfd70897c5ad4617..7eda390a7ca7238bbc1c33b6bc5132c768027deb 100644 --- a/program/models.py +++ b/program/models.py @@ -281,7 +281,7 @@ class RRule(models.Model): (5, _("Fifth")), (-1, _("Last")), ) - name = models.CharField(_("Name"), max_length=32, unique=True) # ,default=1 + name = models.CharField(_("Name"), max_length=32, unique=True) freq = models.IntegerField(_("Frequency"), choices=FREQ_CHOICES) interval = models.IntegerField(_("Interval"), default=1) bysetpos = models.IntegerField(_("Set position"), blank=True, @@ -344,58 +344,60 @@ class ProgramSlot(models.Model): def generate_timeslots(programslot): """ Returns a list of timeslot objects based on a programslot and its rrule - Returns past timeslots starting from dstart (not today) - - TODO for ENDING TIMES: - - 1. If rrule is 'on even or odd calendar weeks' and a timeslot lasts from SUN 23:00 - MON 00:00, - the end date will be in the next week, which is excluded by byweekno. Thus the end date will be in the week _after next_. - - 2. If rrule is 'on business days' and a timeslot lasts from FRI 23:00 - SAT 00:00, - the end date will be on a weekday, which is excluded by byweekday_end (and actually returns the next week-1day, which is quite unexpected) - - Solution: - - Correct those end-dates or find a better way to formulate rrule() - - Either determine byweekno for ends beforehand for that case (when byweekday_end is determined) - - Check if combinations of dend, byweekday_end, byweekno (or interval and bysetpos) might have something to do with the problem + Returns past timeslots as well starting from dstart (not today) """ byweekno = None + byweekno_end = None byweekday_end = int(programslot.byweekday) starts = [] ends = [] timeslots = [] + # Handle ending weekday for timeslots over midnight + if programslot.tend < programslot.tstart: + if programslot.byweekday < 6: + byweekday_end = int(programslot.byweekday + 1) + else: + byweekday_end = 0 + + # Handle ending dates for timeslots over midnight + if programslot.tend < programslot.tstart: + dend = programslot.dstart + timedelta(days=+1) + else: + dend = programslot.dstart + if programslot.rrule.freq == 0: # Ignore weekdays for one-time timeslots byweekday_start = None byweekday_end = None elif programslot.rrule.freq == 3 and programslot.rrule.pk == 2: # Daily timeslots byweekday_start = (0, 1, 2, 3, 4, 5, 6) byweekday_end = (0, 1, 2, 3, 4, 5, 6) - elif programslot.rrule.freq == 3 and programslot.rrule.pk == 3: # Business days MO - FR + elif programslot.rrule.freq == 3 and programslot.rrule.pk == 3: # Business days MO - FR/SA byweekday_start = (0, 1, 2, 3, 4) - byweekday_end = (0, 1, 2, 3, 4) + if programslot.tend < programslot.tstart: + # End days for over midnight + byweekday_end = (1, 2, 3, 4, 5) + else: + byweekday_end = (0, 1, 2, 3, 4) elif programslot.rrule.freq == 2 and programslot.rrule.pk == 7: # Even calendar weeks byweekday_start = int(programslot.byweekday) byweekno = list(range(2, 54, 2)) + # Reverse ending weeks if from Sun - Mon + if byweekday_start == 6 and byweekday_end == 0: + byweekno_end = list(range(1, 54, 2)) + else: + byweekno_end = byweekno elif programslot.rrule.freq == 2 and programslot.rrule.pk == 8: # Odd calendar weeks byweekday_start = int(programslot.byweekday) byweekno = list(range(1, 54, 2)) - else: - byweekday_start = int(programslot.byweekday) - - # Handle ending weekday for timeslots over midnight - if programslot.tend < programslot.tstart: - if programslot.byweekday < 6: - byweekday_end = int(programslot.byweekday + 1) + # Reverse ending weeks if from Sun - Mon + if byweekday_start == 6 and byweekday_end == 0: + byweekno_end = list(range(2, 54, 2)) else: - byweekday_end = 0 - - # Handle ending dates for timeslots over midnight - if programslot.tend < programslot.tstart: - dend = programslot.dstart + timedelta(days=+1) + byweekno_end = byweekno else: - dend = programslot.dstart + byweekday_start = int(programslot.byweekday) if programslot.rrule.freq == 0: starts.append(datetime.combine(programslot.dstart, programslot.tstart)) @@ -409,16 +411,18 @@ class ProgramSlot(models.Model): bysetpos=programslot.rrule.bysetpos, byweekday=byweekday_start, byweekno=byweekno)) + ends = list(rrule(freq=programslot.rrule.freq, dtstart=datetime.combine(dend, programslot.tend), interval=programslot.rrule.interval, until=programslot.until + relativedelta(days=+1), bysetpos=programslot.rrule.bysetpos, byweekday=byweekday_end, - byweekno=byweekno)) + byweekno=byweekno_end)) - for k in range(min(len(starts), len(ends))): - timeslots.append(TimeSlot(programslot=programslot, start=starts[k], end=ends[k]).generate()) + for k in range(min(len(starts), len(ends))): + timeslots.append(TimeSlot(programslot=programslot, start=starts[k], end=ends[k]).generate()) + print(str(starts[k]) + ' - ' + str(ends[k])) return timeslots @@ -441,7 +445,7 @@ class ProgramSlot(models.Model): ( Q(start__lte=ts.start) & Q(end__gte=ts.end) ) ) - if(collision): + if collision: collisions.append(collision[0]) # TODO: Do we really always retrieve one? else: collisions.append(None) @@ -509,7 +513,8 @@ class TimeSlotManager(models.Manager): @staticmethod def get_7d_timeslots(start): - end = start + timedelta(hours=168) + start = datetime.combine(start, time(0, 0)) + end = start + timedelta(days=7) return TimeSlot.objects.filter(Q(start__lte=start, end__gte=start) | Q(start__gt=start, start__lt=end)).exclude(end=start) diff --git a/program/templates/calendar.html b/program/templates/calendar.html index 5868714019817f5165431a82b24afaefe20a8428..2acfbaa92064e26a2434fb341d1addb2de5a9854 100644 --- a/program/templates/calendar.html +++ b/program/templates/calendar.html @@ -74,7 +74,7 @@ <div id="notification"></div> <div id="container"> - + {% csrf_token %} <div id="header">Kalender</div> <div class="breadcrumb"></div> @@ -83,8 +83,13 @@ <h1></h1> <div class="calendar-container"> - <div id="sidebar"> </div> <div id="calendar"></div> + <div id="sidebar"> + <div id="timeslot-id"></div> + <div id="timeslot-start"></div> + <div id="timeslot-end"></div> + <div id="response-message"></div> + </div> </div> </div> @@ -151,8 +156,29 @@ jQuery(this).find('.closeon').hide(); }, // Triggered when an event was clicked + // Load the timeslot into the sidebar form eventClick: function(calEvent, jsEvent, view) { console.log(calEvent); + jQuery.ajax({ + url: '/export/get_timeslot', + type: 'GET', + data: { + 'timeslot_id': calEvent.id, + 'csrfmiddlewaretoken': jQuery('input[name="csrfmiddlewartetoken"]').val() + }, + success: function(timeslot) { + jQuery("#timeslot-id").html(timeslot.id); + jQuery("#timeslot-start").html(timeslot.start); + jQuery("#timeslot-end").html(timeslot.end); + jQuery("#response-message").html("Success"); + }, + error: function() { + jQuery("#response-message").html("An error occured"); + } + + }); + + }, // How is this callback triggered? select: function( start, end, jsEvent, view ) { diff --git a/program/templates/collisions.html b/program/templates/collisions.html index 6881962f3dac64d1b47c82061d692af72ea643ec..c6ac173c54d961b99eeafffd73db253ce44f3a14 100644 --- a/program/templates/collisions.html +++ b/program/templates/collisions.html @@ -155,8 +155,8 @@ </div> <div style="display:none;"> - {{ programslotsform }} - {{ showform }} + {{ programslotsform.as_ul }} + {{ showform.as_ul }} </div> </form> diff --git a/program/views.py b/program/views.py index e2badc0bfedb25152c1259588e0445f8272ee250..1028f7851624c0e01f372c86ee3ad5583e048f59 100644 --- a/program/views.py +++ b/program/views.py @@ -2,11 +2,14 @@ import json from datetime import date, datetime, time, timedelta from django.db.models import Q -from django.http import HttpResponse +from django.core.exceptions import ObjectDoesNotExist +from django.forms.models import model_to_dict +from django.http import HttpResponse, JsonResponse from django.shortcuts import get_object_or_404 from django.views.generic.base import TemplateView from django.views.generic.detail import DetailView from django.views.generic.list import ListView +from pprint import pprint from .models import BroadcastFormat, MusicFocus, Note, Show, ShowInformation, ShowTopic, TimeSlot, Host @@ -277,4 +280,12 @@ def json_timeslots_specials(request): specials[automation_id]['pv_end'] = end return HttpResponse(json.dumps(specials, ensure_ascii=False).encode('utf8'), - content_type="application/json; charset=utf-8") \ No newline at end of file + content_type="application/json; charset=utf-8") + + +def json_get_timeslot(request): + if request.method == 'GET': + try: + return JsonResponse( model_to_dict(TimeSlot.objects.select_related('programslot').select_related('show').get(pk=int(request.GET.get('timeslot_id'))))) + except ObjectDoesNotExist: + return JsonResponse( list('Error') ); \ No newline at end of file diff --git a/pv/urls.py b/pv/urls.py index 5bd8dfcaa0092a5776858ba597d395b282b0106d..8135910840fbc39413baf192d2ede128a89eb2b3 100644 --- a/pv/urls.py +++ b/pv/urls.py @@ -3,7 +3,8 @@ from django.conf.urls import url, include from django.contrib import admin from django.views.static import serve -from program.views import json_day_schedule, json_week_schedule, json_timeslots_specials +from program.views import json_day_schedule, json_week_schedule, json_timeslots_specials, json_get_timeslot + admin.autodiscover() @@ -15,6 +16,7 @@ urlpatterns = [ url(r'^export/day_schedule/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', json_day_schedule), url(r'^export/week_schedule$', json_week_schedule), url(r'^export/timeslots_specials.json$', json_timeslots_specials), + url(r'^export/get_timeslot$', json_get_timeslot, name='get-timeslot'), ] if settings.DEBUG: