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
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}")
21 class Location(Entity):
22 name = models.CharField(max_length=150, blank=True)
23 description = models.TextField(blank=True)
25 longitude = models.FloatField(blank=True, validators=[MinValueValidator(-180), MaxValueValidator(180)])
26 latitude = models.FloatField(blank=True, validators=[MinValueValidator(-90), MaxValueValidator(90)])
28 events = GenericRelation('Event')
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.")
38 _location_content_type_limiter = ContentTypeSubclassLimiter(Location)
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)
51 _building_content_type_limiter = ContentTypeSubclassLimiter(Building)
54 class USBuilding(Building):
55 state = USStateField()
56 zipcode = USZipCodeField()
59 verbose_name = "Building (US)"
60 verbose_name_plural = "Buildings (US)"
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')
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)
77 return self.start_time is None and self.end_time is None
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')
88 description = TemplateField()
90 tags = models.ManyToManyField(Tag, blank=True, null=True)
92 parent_event = models.ForeignKey('self', blank=True, null=True)
94 owner = models.ForeignKey(getattr(settings, 'PHILO_PERSON_MODULE', 'auth.User'))
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')
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)])