Skip to content

Subscriptions Management & Implementation

mjumbewu edited this page Aug 24, 2011 · 5 revisions

Subscriptions Management & Implementation

A user can subscribe to various types of streams through Councilmatic:

  • new legislation
  • newly scheduled meetings/agenda items

If a user wants to receive updates (new actions, or comments) to content they can "bookmark" the content. A user is subscribed to any updates to their bookmarked content. They can bookmark or unbookmark content at any point in the content's life.

Management

A few tasks must be regularly carried out to ensure up-to-date information: updating the cache of legislation content, updating the search index, updating the feeds, and sending off new content notifications. These are made accessible through Django management commands.

Sending feed updates

To send off emails to subscribers, use the command:

python manage.py sendfeedupdates

This command will get run once daily. A feed will only be sent to a subscriber if there have been changes to the content, and only changed content will be sent. The process that Councilmatic goes through is:

  1. Update all the site data.
  2. Update the newest data datetime on each feed.
  3. Go through each subscription and compare the last sent date to the latest updated date in the subscription feed.
  4. For each user, collect subscriptions that do have new content.
  5. Send the collection of new content to the user through the appropriate channel.
  6. Update the last sent date for the subscriber

Under the hood

The subscriptions.ContentFeed model stores information necessary for retrieving a queryset of content. The subscriptions.Subscription model associates a User with a ContentFeed, and stores information about the last time the user was sent the feed, etc.

Content Feeds

subscriptions/models.py:

class ContentFeed (models.Model):
    queryset = models.TextField()
    last_updated_calc = models.TextField()
    last_updated = models.DateTimeField(default=datetime(1970,1,1,0,0,0))

    def get_content(self):
        ...

    def get_last_updated(self, results):
        ...

    @classmethod
    def factory(cls, queryset, last_updated_calc):
        ...

The query for the ContentFeed is stored as a pickled iterable object. Don't judge me!!! Calling get_content on a ContentFeed will return you the results of the query. Calling get_last_updated will return you the last time the given set of content was updated.

To create a ContentFeed object, use the factory method. This will take your parameters and pickle them for you, returning a valid ContentFeed object. you must specify a last_updated_calc callable, because each set of content may have a different way of determining when it was last updated.

Subscriptions

subscriptions/models.py:

import django.contrib.auth.models as auth

class Subscriber (auth.User):
    def subscribe(self, feed):
        ...

class Subscription (models.Model):
    user = models.ForeignKey('Subscriber', related_name='subscriptions')
    feed = models.ForeignKey('ContentFeed')
    last_sent = models.DateTimeField()

A subscriber is a normal user. To subscribe a user to a content feed, simply call subscribe on the Subscriber. Note, if you just have an auth.User object (say, from the request or in a template), you get the subscriber version of the user with user.subscriber. If the User is not a Subscriber (which it normally will be), this will raise a Subscriber.DoesNotExist error.

When a Subscription is first saved, the last_sent time is set to the current time. This prevents subscribers from being bothered with content that was posted to a feed before the user subscribed to the feed.