c9bd6da02e064fcc2e41df10b568f272cd706bc6
[philo.git] / contrib / julian / models.py
1 from django.conf import settings
2 from django.contrib.localflavor.us.models import USStateField
3 from django.contrib.contenttypes.generic import GenericForeignKey, GenericRelation
4 from django.contrib.contenttypes.models import ContentType
5 from django.core.exceptions import ValidationError
6 from django.core.validators import RegexValidator, MinValueValidator, MaxValueValidator
7 from django.db import models
8 from philo.contrib.julian.fields import USZipCodeField
9 from philo.models.base import Tag, Entity, Titled
10 from philo.models.fields import TemplateField
11 from philo.utils import ContentTypeSubclassLimiter
12 import datetime
13 import re
14
15
16 # TODO: Could this regex more closely match the Formal Public Identifier spec?
17 # http://xml.coverpages.org/tauber-fpi.html
18 FPI_REGEX = re.compile(r"(|\+//|-//)[^/]+//[^/]+//[A-Z]{2}")
19
20
21 class Location(Entity):
22         name = models.CharField(max_length=150, blank=True)
23         description = models.TextField(blank=True)
24         
25         longitude = models.FloatField(blank=True, validators=[MinValueValidator(-180), MaxValueValidator(180)])
26         latitude = models.FloatField(blank=True, validators=[MinValueValidator(-90), MaxValueValidator(90)])
27         
28         events = GenericRelation('Event')
29         
30         def clean(self):
31                 if not (self.name or self.description) or (self.longitude is None and self.latitude is None):
32                         raise ValidationError("Either a name and description or a latitude and longitude must be defined.")
33         
34         class Meta:
35                 abstract = True
36
37
38 _location_content_type_limiter = ContentTypeSubclassLimiter(Location)
39
40
41 # TODO: Can we track when a building is open? Hmm...
42 class Building(Location):
43         """A building is a location with a street address."""
44         address = models.CharField(max_length=255)
45         city = models.CharField(max_length=150)
46         
47         class Meta:
48                 abstract = True
49
50
51 _building_content_type_limiter = ContentTypeSubclassLimiter(Building)
52
53
54 class USBuilding(Building):
55         state = USStateField()
56         zipcode = USZipCodeField()
57         
58         class Meta:
59                 verbose_name = "Building (US)"
60                 verbose_name_plural = "Buildings (US)"
61
62
63 class Venue(Location):
64         """A venue is a location inside a building"""
65         building_content_type = models.ForeignKey(ContentType, limit_choices_to=_building_content_type_limiter)
66         building_pk = models.TextField()
67         building = GenericForeignKey('building_content_type', 'building_pk')
68
69
70 class TimedModel(models.Model):
71         start_date = models.DateField(help_text="YYYY-MM-DD")
72         start_time = models.TimeField(blank=True, null=True, help_text="HH:MM:SS - 24 hour clock")
73         end_date = models.DateField()
74         end_time = models.TimeField(blank=True, null=True)
75         
76         def is_all_day(self):
77                 return self.start_time is None and self.end_time is None
78         
79         class Meta:
80                 abstract = True
81
82
83 class Event(Entity, Titled, TimedModel):
84         location_content_type = models.ForeignKey(ContentType, limit_choices_to=_location_content_type_limiter)
85         location_pk = models.TextField()
86         location = GenericForeignKey('location_content_type', 'location_pk')
87         
88         description = TemplateField()
89         
90         tags = models.ManyToManyField(Tag, blank=True, null=True)
91         
92         parent_event = models.ForeignKey('self', blank=True, null=True)
93         
94         owner = models.ForeignKey(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'))
95
96
97 class Calendar(Entity):
98         name = models.CharField(max_length=100)
99         #slug = models.SlugField(max_length=255, unique=True)
100         events = models.ManyToManyField(Event, related_name='calendars')
101         
102         # TODO: Can we auto-generate this on save based on site id and calendar name and settings language?
103         uuid = models.CharField("Calendar UUID", max_length=100, unique=True, help_text="Should conform to Formal Public Identifier format. See <http://en.wikipedia.org/wiki/Formal_Public_Identifier>", validators=[RegexValidator(FPI_REGEX)])