diff --git a/src/camps/migrations/0020_camp_read_only.py b/src/camps/migrations/0020_camp_read_only.py new file mode 100644 index 00000000..245ca9a3 --- /dev/null +++ b/src/camps/migrations/0020_camp_read_only.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-07 20:04 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('camps', '0019_auto_20170131_1849'), + ] + + operations = [ + migrations.AddField( + model_name='camp', + name='read_only', + field=models.BooleanField(default=False, help_text='Whether the camp is read only (i.e. in the past)'), + ), + ] diff --git a/src/camps/models.py b/src/camps/models.py index 7ffe489e..09239332 100644 --- a/src/camps/models.py +++ b/src/camps/models.py @@ -1,4 +1,3 @@ -import datetime from django.db import models from utils.models import UUIDModel, CreatedUpdatedModel from program.models import EventType, EventLocation @@ -47,6 +46,11 @@ class Camp(CreatedUpdatedModel, UUIDModel): help_text='The camp teardown period.', ) + read_only = models.BooleanField( + help_text='Whether the camp is read only (i.e. in the past)', + default=False + ) + def get_absolute_url(self): return reverse('camp_detail', kwargs={'camp_slug': self.slug}) @@ -110,7 +114,7 @@ class Camp(CreatedUpdatedModel, UUIDModel): # on the first day use actual start time instead of midnight days.append( DateTimeTZRange( - field.lower, + field.lower, (field.lower+timedelta(days=i+1)).replace(hour=0) ) ) diff --git a/src/info/models.py b/src/info/models.py index f4a04dea..12fb7b58 100644 --- a/src/info/models.py +++ b/src/info/models.py @@ -1,11 +1,9 @@ - -from django.contrib import messages from django.db import models -from utils.models import CreatedUpdatedModel +from utils.models import CreatedUpdatedModel, CampRelatedModel from django.core.exceptions import ValidationError -class InfoCategory(CreatedUpdatedModel): +class InfoCategory(CreatedUpdatedModel, CampRelatedModel): class Meta: ordering = ['weight', 'headline'] unique_together = (('anchor', 'camp'), ('headline', 'camp')) @@ -40,7 +38,7 @@ class InfoCategory(CreatedUpdatedModel): return '%s (%s)' % (self.headline, self.camp) -class InfoItem(CreatedUpdatedModel): +class InfoItem(CreatedUpdatedModel, CampRelatedModel): class Meta: ordering = ['weight', 'headline'] unique_together = (('anchor', 'category'), ('headline', 'category')) @@ -69,6 +67,10 @@ class InfoItem(CreatedUpdatedModel): default = 100, ) + @property + def camp(self): + return self.category.camp + def clean(self): if InfoCategory.objects.filter(camp=self.category.camp, anchor=self.anchor).exists(): # this anchor is already in use on a category, so it cannot be used here (they must be unique on the entire page) diff --git a/src/program/models.py b/src/program/models.py index 700ca2cb..422ae63e 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -3,12 +3,12 @@ from django.db import models from django.utils.text import slugify from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from utils.models import CreatedUpdatedModel +from utils.models import CreatedUpdatedModel, CampRelatedModel from django.core.exceptions import ValidationError from datetime import timedelta -class EventLocation(CreatedUpdatedModel): +class EventLocation(CreatedUpdatedModel, CampRelatedModel): """ The places where stuff happens """ name = models.CharField(max_length=100) slug = models.SlugField() @@ -34,7 +34,7 @@ class EventType(CreatedUpdatedModel): return self.name -class Event(CreatedUpdatedModel): +class Event(CreatedUpdatedModel, CampRelatedModel): """ Something that is on the program one or more times. """ title = models.CharField(max_length=255) slug = models.SlugField(blank=True, max_length=255) @@ -72,7 +72,7 @@ class Event(CreatedUpdatedModel): return False -class EventInstance(CreatedUpdatedModel): +class EventInstance(CreatedUpdatedModel, CampRelatedModel): """ An instance of an event """ event = models.ForeignKey('program.event', related_name='instances') when = DateTimeRangeField() @@ -93,6 +93,10 @@ class EventInstance(CreatedUpdatedModel): if errors: raise ValidationError(errors) + @property + def camp(self): + return self.event.camp + @property def schedule_date(self): """ @@ -123,7 +127,7 @@ def get_speaker_picture_upload_path(instance, filename): } -class Speaker(CreatedUpdatedModel): +class Speaker(CreatedUpdatedModel, CampRelatedModel): """ A Person anchoring an event. """ name = models.CharField(max_length=150) biography = models.TextField() diff --git a/src/utils/models.py b/src/utils/models.py index 9448ff01..a79e08cc 100644 --- a/src/utils/models.py +++ b/src/utils/models.py @@ -1,5 +1,6 @@ import uuid from django.core.exceptions import ValidationError +from django.contrib import messages from django.db import models @@ -11,7 +12,7 @@ class CleanedModel(models.Model): try: # call this models full_clean() method before saving, # which in turn calls .clean_fields(), .clean() and .validate_unique() - #self.full_clean() + # self.full_clean() # for some reason self.full_clean() appears to call self.clean() before self.clean_fields() # which is not supposed to happen. Call them manually one by one instead. self.clean_fields() @@ -46,3 +47,22 @@ class CreatedUpdatedModel(CleanedModel): updated = models.DateTimeField(auto_now=True) +class CampRelatedModel(CleanedModel): + class Meta: + abstract = True + + def save(self, **kwargs): + if self.camp.read_only: + if hasattr(self, 'request'): + messages.error(self.request, 'Camp is in read only mode.') + raise ValidationError('This camp is in read only mode.') + + super(CampRelatedModel, self).save(**kwargs) + + def delete(self, **kwargs): + if self.camp.read_only: + if hasattr(self, 'request'): + messages.error(self.request, 'Camp is in read only mode.') + raise ValidationError('This camp is in read only mode.') + + super(CampRelatedModel, self).save(**kwargs) diff --git a/src/villages/models.py b/src/villages/models.py index 84be713c..277e9e3c 100644 --- a/src/villages/models.py +++ b/src/villages/models.py @@ -1,15 +1,13 @@ - - from django.core.urlresolvers import reverse_lazy from django.db import models from django.utils.text import slugify -from utils.models import CreatedUpdatedModel, UUIDModel +from utils.models import CreatedUpdatedModel, UUIDModel, CampRelatedModel from .managers import VillageQuerySet -class Village(CreatedUpdatedModel, UUIDModel): +class Village(CreatedUpdatedModel, UUIDModel, CampRelatedModel): class Meta: ordering = ['name']