gremmie@1: """
gremmie@1: Models for the gcalendar application.
bgneal@456: 
gremmie@1: """
bgneal@458: import datetime
bgneal@458: 
gremmie@1: from django.db import models
gremmie@1: from django.db.models import Q
gremmie@1: from django.contrib.auth.models import User
bgneal@124: 
bgneal@128: from core.markup import site_markup
bgneal@228: import forums.tools
bgneal@458: from gcalendar.oauth import serialize_token, deserialize_token
gremmie@1: 
gremmie@1: 
bgneal@228: GIG_FORUM_SLUG = "gigs"
bgneal@228: 
gremmie@1: class PendingEventManager(models.Manager):
gremmie@1:     """A manager for pending events."""
gremmie@1: 
gremmie@1:     def get_query_set(self):
gremmie@1:         """Returns a queryset of events that have been approved to update
gremmie@1:         the Google calendar."""
gremmie@1:         return super(PendingEventManager, self).get_query_set().filter(
bgneal@456:                 Q(status=Event.NEW_APRV) |
bgneal@456:                 Q(status=Event.EDIT_APRV) |
gremmie@1:                 Q(status=Event.DEL_APRV)
gremmie@1:             )
gremmie@1: 
gremmie@1: 
gremmie@1: class Event(models.Model):
gremmie@1:     """Model to represent calendar events."""
gremmie@1: 
gremmie@1:     # Event status codes:
gremmie@1:     (NEW, NEW_APRV, EDIT_REQ, EDIT_APRV, DEL_REQ, DEL_APRV, ON_CAL) = range(7)
gremmie@1: 
gremmie@1:     STATUS_CHOICES = (
gremmie@1:         (NEW, 'New'),
gremmie@1:         (NEW_APRV, 'New Approved'),
gremmie@1:         (EDIT_REQ, 'Edit Request'),
gremmie@1:         (EDIT_APRV, 'Edit Approved'),
gremmie@1:         (DEL_REQ, 'Delete Request'),
gremmie@1:         (DEL_APRV, 'Delete Approved'),
gremmie@1:         (ON_CAL, 'On Calendar'),
gremmie@1:     )
gremmie@1: 
gremmie@1:     user = models.ForeignKey(User)
gremmie@1:     what = models.CharField(max_length=255)
gremmie@1:     start_date = models.DateField()
gremmie@1:     start_time = models.TimeField(null=True, blank=True)
gremmie@1:     end_date = models.DateField()
gremmie@1:     end_time = models.TimeField(null=True, blank=True)
gremmie@1:     time_zone = models.CharField(max_length=64, blank=True)
gremmie@1:     all_day = models.BooleanField(default=False)
gremmie@1:     where = models.CharField(max_length=255, blank=True)
gremmie@1:     description = models.TextField(blank=True)
gremmie@1:     html = models.TextField(blank=True)
gremmie@1:     date_submitted = models.DateTimeField(auto_now_add=True)
gremmie@1:     google_id = models.CharField(max_length=255, blank=True)
bgneal@228:     google_url = models.URLField(verify_exists=False, max_length=255,
bgneal@228:             blank=True)
bgneal@228:     status = models.SmallIntegerField(choices=STATUS_CHOICES, default=NEW,
bgneal@228:             db_index=True)
bgneal@228:     create_forum_thread = models.BooleanField(default=False)
gremmie@1: 
gremmie@1:     objects = models.Manager()
gremmie@1:     pending_events = PendingEventManager()
gremmie@1: 
gremmie@1:     def __unicode__(self):
gremmie@1:         return self.what
gremmie@1: 
gremmie@1:     class Meta:
gremmie@1:         ordering = ('-date_submitted', )
gremmie@1: 
gremmie@1:     def save(self, *args, **kwargs):
bgneal@128:         self.html = site_markup(self.description)
gremmie@1:         super(Event, self).save(*args, **kwargs)
gremmie@1: 
bgneal@139:     def is_approved(self):
bgneal@139:         return self.status not in (self.NEW, self.EDIT_REQ, self.DEL_REQ)
bgneal@139:     is_approved.boolean = True
gremmie@1: 
bgneal@228:     def google_html(self):
bgneal@228:         """Returns a HTML <a> tag to the event if it exits."""
bgneal@228:         if self.google_url:
bgneal@228:             return u'<a href="%s">On Google</a>' % self.google_url
bgneal@228:         return u''
bgneal@228:     google_html.allow_tags = True
bgneal@228:     google_html.short_description = 'Google Link'
bgneal@228: 
bgneal@228:     def notify_on_calendar(self):
bgneal@228:         """
bgneal@228:         This function should be called when the event has been added to the
bgneal@228:         Google calendar for the first time. This gives us a chance to perform
bgneal@228:         any first-time processing, like creating a forum thread.
bgneal@228:         """
bgneal@228:         if self.create_forum_thread:
bgneal@228:             topic_name = '%s: %s' % (self.start_date.strftime('%m/%d/%Y'),
bgneal@228:                     self.what)
bgneal@228:             post_body = "%s\n\n[Link to event on Google Calendar](%s)" % (
bgneal@228:                     self.description, self.google_url)
bgneal@228: 
bgneal@228:             forums.tools.create_topic(
bgneal@228:                 forum_slug=GIG_FORUM_SLUG,
bgneal@456:                 user=self.user,
bgneal@228:                 topic_name=topic_name,
bgneal@228:                 post_body=post_body)
bgneal@228: 
bgneal@228:             self.create_forum_thread = False
bgneal@228:             self.save()
bgneal@456: 
bgneal@456: 
bgneal@458: class AccessTokenManager(models.Manager):
bgneal@458:     """
bgneal@458:     A manager for the AccessToken table. Only one access token is saved in the
bgneal@458:     database. This manager provides a convenience method to either return that
bgneal@458:     access token or a brand new one.
bgneal@458: 
bgneal@458:     """
bgneal@458:     def get_token(self):
bgneal@458:         try:
bgneal@458:             token = self.get(pk=1)
bgneal@458:         except AccessToken.DoesNotExist:
bgneal@458:             token = AccessToken()
bgneal@458: 
bgneal@458:         return token
bgneal@458: 
bgneal@458: 
bgneal@456: class AccessToken(models.Model):
bgneal@456:     """
bgneal@456:     This model represents serialized OAuth access tokens for reading and
bgneal@456:     updating the Google Calendar.
bgneal@456: 
bgneal@456:     """
bgneal@456:     auth_date = models.DateTimeField()
bgneal@456:     token = models.TextField()
bgneal@456: 
bgneal@458:     objects = AccessTokenManager()
bgneal@458: 
bgneal@456:     def __unicode__(self):
bgneal@456:         return u'Access token created on ' + unicode(self.auth_date)
bgneal@456: 
bgneal@458:     def update(self, access_token, auth_date=None):
bgneal@458:         """
bgneal@458:         This function updates the AccessToken object with the input parameters:
bgneal@458:             access_token - an access token from Google's OAuth dance
bgneal@458:             auth_date - a datetime or None. If None, now() is used.
bgneal@458: 
bgneal@458:         """
bgneal@458:         self.auth_date = auth_date if auth_date else datetime.datetime.now()
bgneal@458:         self.token = serialize_token(access_token)
bgneal@458: 
bgneal@458:     def access_token(self):
bgneal@458:         """
bgneal@458:         This function returns a Google OAuth access token by deserializing the
bgneal@458:         token field from the database.
bgneal@458:         If the token attribute is empty, None is returned.
bgneal@458: 
bgneal@458:         """
bgneal@458:         return deserialize_token(self.token) if self.token else None