Commits

Dan Carroll  committed a20f77d

Start refactoring activity sync code into separate classes. Add provider interface and a test management command to facilitate development.

  • Participants
  • Parent commits bee850c
  • Branches activitysync-separation

Comments (0)

Files changed (4)

File mysite/activitysync/management/commands/updatetest.py

+from django.conf import settings
+from django.core import exceptions
+from django.core.management.base import NoArgsCommand
+from django.core.management.color import no_style
+from django.core.mail import mail_admins
+from optparse import make_option
+from activitysync.models import Activity
+from activitysync.providers import ActivityProvider, ActivityInfo
+
+import os
+import sys
+import time
+import socket
+import datetime
+import feedparser
+import twitter
+
+class Command(NoArgsCommand):
+    help = "Update activities by depositing them into the blog database."
+
+    def handle_noargs(self, **options): 
+        self.style = no_style()
+        
+        email_status_info = []
+        items_added = False
+        try:
+            # Go through provider list
+            provider_list = getattr(settings, 'ACTIVITYSYNC_PROVIDERS', [])
+            for provider_path in provider_list:
+                try:
+                    dot = provider_path.rindex('.')
+                except ValueError:
+                    raise exceptions.ImproperlyConfigured('%s is not an activity provider' % provider_path)
+                provider_module, provider_classname = provider_path[:dot], provider_path[dot+1:]
+                try:
+                    mod = __import__(provider_module, {}, {}, [''])
+                except ImportError, e:
+                    raise exceptions.ImproperlyConfigured('Error importing provider %s: %s' % (provider_module, e))
+                try:
+                    provider_class = getattr(mod, provider_classname)
+                except AttributeError:
+                    raise exceptions.ImproperlyConfigured('Provider module "%s" does not define a "%s" class' % (provider_module, provider_classname))
+
+                provider_instance = provider_class()
+                email_status_info.append('\n\n%s\n\n' % provider_instance.name())
+                for activity_item in provider_instance.get_activity():
+                    try:
+                        Activity.objects.get(guid=activity_item.guid)
+                    except Activity.DoesNotExist:
+                        print "Created item: %s (%s)" % (activity_item.title, activity_item.link)
+                        email_status_info.append("Created item: %s (%s)\n" % (activity_item.title, activity_item.link))
+                        items_added = True
+
+                        #Activity.objects.create(title=activity_item.title, link=activity_item.link, source=provider_instance.sourceid(), username=activity_item.username, author=activity_item.author, comments=activity_item.comments, pub_date=activity_item.pub_date, published=activity_item.published, guid=activity_item.guid)
+
+        except:
+            ### DEBUGGING CODE
+            raise
+            ### END DEBUGGING
+            items_added = True
+            print "Unexpected error:", sys.exc_info()[0]
+            email_status_info.append("Unexpected error: %s\n\n" % sys.exc_info()[0])    
+        finally:
+            if items_added:
+                mailBody = u""
+                for itemString in email_status_info:
+                    try:
+                        mailBody = mailBody.encode('utf-8') + itemString.encode('utf-8')
+                    except UnicodeDecodeError:
+                        mailBody = mailBody + "\n\nFAILED TO PARSE ACTIVITY\n\n"
+                ### DISABLED TEMPORARILY FOR DEBUGGING
+                #mail_admins('Update Activities command completed', mailBody, fail_silently=False)
+                #print 'Mail sent to admins'
+                ### END DISABLE

File mysite/activitysync/providers/__init__.py

+"""Base ActivityProvider class"""
+
+class ActivityProvider(object):
+    """
+    Base class for activity providers (networks that provide social activity)
+    """
+
+    def get_activity(self):
+        """Returns a list of ActivityInfo objects representing the provider's activity"""
+        raise NotImplementedError
+
+    def name(self):
+        """Name of the network the provider connects to"""
+        raise NotImplementedError
+
+    def prefix(self):
+        """Prefix to put before activity item representing the action of the activity (i.e. "shared", "liked", etc)"""
+        raise NotImplementedError
+
+    def link(self):
+        """Link to the network or user profile page on the network"""
+        raise NotImplementedError
+
+    def sourceid(self):
+        """String representing the name or identification for the network. Used to associate items with the provider."""
+        raise NotImplementedError
+
+class ActivityInfo(object):
+    def __init__(self, title, link, pub_date, guid, username=None, author=None, comments=None, published=True):
+        self.title = title
+        self.link = link
+        self.username = username
+        self.author = author
+        self.comments = comments
+        self.pub_date = pub_date
+        self.published = published
+        self.guid = guid
+

File mysite/activitysync/providers/googlereader.py

+from django.conf import settings
+from activitysync.providers import ActivityProvider, ActivityInfo
+
+import time
+import datetime
+import feedparser
+
+class GoogleReaderProvider(ActivityProvider):
+    """
+    Provider for accessing shared Google Reader items for one user.
+    """
+#class ActivityInfo(object):
+#    def __init__(self, title=None, link=None, username=None, author=None, comments=None, pub_data=None, published=True, guid=None)
+
+    def get_activity(self):
+        item_list = []
+
+        print 'Attempting to parse Google Reader feed'
+        parsed_feed = feedparser.parse("http://www.google.com/reader/public/atom/user%2F10780706687522073033%2Fstate%2Fcom.google%2Fbroadcast")
+    
+        for entry in parsed_feed.entries:
+            title = entry.title.encode(parsed_feed.encoding, "xmlcharrefreplace")
+            guid = entry.get("id", entry.link).encode(parsed_feed.encoding, "xmlcharrefreplace")
+            link = entry.link.encode(parsed_feed.encoding, "xmlcharrefreplace")
+
+            shared_by = u"Dan Carroll"
+            comments =u""
+                
+            if not guid:
+                guid = link
+                    
+            try:
+                if entry.has_key('published_parsed'):
+                    date_published = datetime.datetime.fromtimestamp(time.mktime(entry.published_parsed) - time.timezone)
+                elif entry.has_key('updated_parsed'):
+                    date_published = datetime.datetime.fromtimestamp(time.mktime(entry.updated_parsed) - time.timezone)
+                elif entry.has_key('modified_parsed'):
+                    date_published = datetime.datetime.fromtimestamp(time.mktime(entry.modified_parsed) - time.timezone)
+                else:
+                    date_published = datetime.datetime.now()
+            except TypeError:
+                date_published = datetime.datetime.now()
+                        
+            if entry.has_key('content'):        
+                if len(entry.content) == 2:
+                    comments = entry.content[1].value.encode(parsed_feed.encoding, "xmlcharrefreplace")
+            
+            activity_info = ActivityInfo(title=title, link=link, pub_date=date_published, guid=guid, username=shared_by, author=shared_by, comments=comments)
+            item_list.append(activity_info)
+
+        return item_list
+
+
+    def name(self):
+        return 'Google Reader'
+
+    def prefix(self):
+        return 'Shared'
+
+    def link(self):
+        return 'http://www.google.com/reader/shared/dancarroll'
+
+    def sourceid(self):
+        return 'GR'
+

File mysite/settings.py

 import os
 import deploy
 
+ACTIVITYSYNC_PROVIDERS = (
+    'activitysync.providers.googlereader.GoogleReaderProvider',
+)
+
 DEBUG = deploy.DEBUG
 TEMPLATE_DEBUG = DEBUG