diff --git a/src/camps/models.py b/src/camps/models.py index 2982dfec..f868fd64 100644 --- a/src/camps/models.py +++ b/src/camps/models.py @@ -1,7 +1,7 @@ import datetime from django.db import models from utils.models import UUIDModel, CreatedUpdatedModel -from program.models import EventType +from program.models import EventType, EventLocation from django.contrib.postgres.fields import DateTimeRangeField from psycopg2.extras import DateTimeTZRange from django.core.exceptions import ValidationError @@ -72,6 +72,11 @@ class Camp(CreatedUpdatedModel, UUIDModel): # return all event types with at least one event in this camp return EventType.objects.filter(event__instances__isnull=False, event__camp=self).distinct() + @property + def event_locations(self): + ''' Return all event locations with at least one event in this camp''' + return EventLocation.objects.filter(eventinstances__isnull=False, camp=self).distinct() + @property def logo_small(self): return 'img/%(slug)s/logo/%(slug)s-logo-small.png' % {'slug': self.slug} diff --git a/src/program/migrations/0019_auto_20170205_1940.py b/src/program/migrations/0019_auto_20170205_1940.py new file mode 100644 index 00000000..3d4ce550 --- /dev/null +++ b/src/program/migrations/0019_auto_20170205_1940.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-02-05 18:40 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('camps', '0019_auto_20170131_1849'), + ('program', '0018_eventtype_notifications'), + ] + + operations = [ + migrations.CreateModel( + name='EventLocation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('name', models.CharField(max_length=100, unique=True)), + ('slug', models.SlugField()), + ('icon', models.URLField()), + ('camp', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='eventlocations', to='camps.Camp')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='eventinstance', + name='location', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='eventinstances', to='program.EventLocation'), + ), + ] diff --git a/src/program/migrations/0020_auto_20170205_1940.py b/src/program/migrations/0020_auto_20170205_1940.py new file mode 100644 index 00000000..8d196893 --- /dev/null +++ b/src/program/migrations/0020_auto_20170205_1940.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-02-05 18:40 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('program', '0019_auto_20170205_1940'), + ] + + operations = [ + migrations.AlterField( + model_name='eventinstance', + name='location', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='eventinstances', to='program.EventLocation'), + ), + ] diff --git a/src/program/migrations/0021_auto_20170205_2130.py b/src/program/migrations/0021_auto_20170205_2130.py new file mode 100644 index 00000000..d85af26c --- /dev/null +++ b/src/program/migrations/0021_auto_20170205_2130.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-02-05 20:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('camps', '0019_auto_20170131_1849'), + ('program', '0020_auto_20170205_1940'), + ] + + operations = [ + migrations.AlterField( + model_name='eventlocation', + name='icon', + field=models.CharField(max_length=100), + ), + migrations.AlterField( + model_name='eventlocation', + name='name', + field=models.CharField(max_length=100), + ), + migrations.AlterUniqueTogether( + name='eventlocation', + unique_together=set([('camp', 'slug'), ('camp', 'name')]), + ), + ] diff --git a/src/program/models.py b/src/program/models.py index 1cb0bfcf..3697a787 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -1,4 +1,3 @@ - from django.contrib.postgres.fields import DateTimeRangeField from django.db import models from django.utils.text import slugify @@ -8,6 +7,20 @@ from django.core.exceptions import ValidationError from datetime import timedelta +class EventLocation(CreatedUpdatedModel): + """ The places where stuff happens """ + name = models.CharField(max_length=100) + slug = models.SlugField() + icon = models.CharField(max_length=100) + camp = models.ForeignKey('camps.Camp', null=True, related_name="eventlocations") + + def __str__(self): + return self.name + + class Meta: + unique_together = (('camp', 'slug'), ('camp', 'name')) + + class EventType(CreatedUpdatedModel): """ Every event needs to have a type. """ name = models.CharField(max_length=100, unique=True) @@ -52,6 +65,7 @@ class EventInstance(CreatedUpdatedModel): event = models.ForeignKey('program.event', related_name='instances') when = DateTimeRangeField() notifications_sent = models.BooleanField(default=False) + location = models.ForeignKey('program.EventLocation', related_name='eventinstances') class Meta: ordering = ['when'] @@ -61,17 +75,11 @@ class EventInstance(CreatedUpdatedModel): def __clean__(self): errors = [] - if self.when.lower > self.when.upper: - errors.append(ValidationError({'when', "Start should be earlier than finish"})) - - if self.when.lower.time().minute != 0 and self.when.lower.time().minute != 30: - errors.append(ValidationError({'when', "Start time minute should be 0 or 30."})) - - if self.when.upper.time().minute != 0 and self.when.upper.time().minute != 30: - errors.append(ValidationError({'when', "End time minute should be 0 or 30."})) + if self.location.camp != self.event.camp: + errors.append(ValidationError({'location', "Error: This location belongs to a different camp"})) if errors: - raise ValidationError(errors) + raise ValidationError(errors) @property def schedule_date(self): @@ -79,7 +87,8 @@ class EventInstance(CreatedUpdatedModel): Returns the schedule date of this eventinstance. Schedule date is determined by substracting settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS from the eventinstance start time. This means that if an event is scheduled for 00:30 wednesday evening (technically thursday) then the date - after substracting 5 hours would be wednesdays date, not thursdays. + after substracting 5 hours would be wednesdays date, not thursdays + (given settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS=5) """ return (self.when.lower-timedelta(hours=settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS)).date() diff --git a/src/program/templates/program_base.html b/src/program/templates/program_base.html index a223c3bf..c3cd2f10 100644 --- a/src/program/templates/program_base.html +++ b/src/program/templates/program_base.html @@ -1,49 +1,71 @@ {% extends 'schedule_base.html' %} +{% load dateutils %} {% block schedule_content %} -
- -