changeset 70:f6a6a4b072e7

complete overhaul to allow event handlers
author Jeff Hammel <jhammel@mozilla.com>
date Wed, 07 Jul 2010 16:18:19 -0700
parents bcc3a59713c3
children 0c98d1c2c6df
files bitsyblog/bitsyblog.py bitsyblog/blog.py bitsyblog/factory.py
diffstat 3 files changed, 42 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/bitsyblog/bitsyblog.py
+++ b/bitsyblog/bitsyblog.py
@@ -55,30 +55,30 @@ class BitsyBlog(object):
                  'auto_reload': 'True', # reload the genshi templates
                  'help_file': None, # help to display
                  'feed_items': 10, # number of RSS/atom items to display
                  }
 
 
     cooked_bodies = {}
 
-    def __init__(self, **kw):
+    def __init__(self, kw, handler_args):
         for key in self.defaults:
             setattr(self, key, kw.get(key, self.defaults[key]))
         self.n_links = int(self.n_links) # could be a string from the .ini
         self.response_functions = { 'GET': self.get,
                                     'POST': self.post,
                                     'PUT': self.put
                                     }
         
         # abstract attributes
         from user import FilespaceUsers
 
         self.users = FilespaceUsers(self.file_dir)
-        self.blog = FileBlog(self.file_dir)
+        self.blog = FileBlog(self, self.file_dir)
         self.cooker = self.restructuredText
         self.feed_items = int(self.feed_items)
 
         # template renderer
         self.auto_reload = self.auto_reload.lower()=='true'
         self.template_directories = self.template_directories.split() # no spaces in directory names, for now
 
         for directory in self.template_directories:
@@ -100,16 +100,27 @@ class BitsyBlog(object):
         if self.header:
             if os.path.exists(self.header):
                 self.header = file(self.header).read()
             self.header = Markup(self.header)
 
         # for BitsyAuth
         self.newuser = self.users.new
 
+        # post handlers
+        self.handlers = [] # handlers for blog post event
+        for entry_point in iter_entry_points('bitsyblog.listeners'):
+          try:
+              handler = entry_point.load()(self, **handler_args.get(entry_point.name, {}))
+              self.handlers.append(handler)
+          except:
+              print 'Cant load entry point %s' entry_point.name 
+              continue
+
+
     ### methods dealing with HTTP
 
     def __call__(self, environ, start_response):
         request = Request(environ)
 
         # genshi data dictionary
         request.environ['data'] = { 'site_name': self.site_name,
                                     'request': request,
@@ -321,17 +332,22 @@ class BitsyBlog(object):
                                     location=self.user_url(request, user, 'post'))
 
         # determine if the post is secret or private
         privacy = request.GET.get('privacy') or request.POST.get('privacy') or 'public'
 
         # write the file
         now = utils.datestamp(datetime.datetime.now())
         location = self.user_url(request, user, now)
-        self.blog.post(user, now, body, privacy)
+        blog_entry = self.blog.post(user, now, body, privacy)
+
+        # fire event handlers
+        # XXX could be done asynchronously
+        for handler in self.handlers:
+            handler(blog_entry)
 
         # point the user at the post
         return exc.HTTPSeeOther("Post blogged by bitsy", location=location)
 
     def put(self, request):
         """
         PUT several blog entries from a file
         """
--- a/bitsyblog/blog.py
+++ b/bitsyblog/blog.py
@@ -42,24 +42,16 @@ class BlogEntry(object):
                 return self.body
         return ''
 
     def datestamp(self):
         return utils.datestamp(self.date)
 
 class Blog(object):
     """abstract class for a users' blog"""
-    def __init__(self):
-        self.handlers = [] # handlers for blog post event
-        for entry_point in iter_entry_points('bitsyblog.listeners'):
-          try:
-              handler = entry_point.load()
-              self.handlers.append(handler)
-          except:
-              continue
 
     def __call__(self, user, permissions=('public',), number=None):
         return self.blog(user, permissions, number=number)
 
     def latest(self, users, number):
         """return the lastest entries"""
         blog = []
         for user in users:
@@ -82,28 +74,25 @@ class Blog(object):
         """
 
     def entries(self, user, permissions, year=None, month=None, day=None):
         """return entries by date"""
 
 
     def post(self, user, date, text, privacy):
         """post a new blog entry"""
-        entry = BlogEntry(date, body, privacy, user):
-        for handler in self.handlers:
-            handler(entry)
+        return BlogEntry(date, text, privacy, user):
 
     def delete(self, user, datestamp):
         """remove a blog entry"""
 
 class FileBlog(Blog):
     """a blog that lives on the filesystem"""
 
     def __init__(self, directory):
-        Blog.__init__(self)
         self.directory = directory
 
     def location(self, user, permission, *path):
         """returns which directory files are in based on permission"""
         return os.path.join(self.directory, user, 'entries', permission, *path)
 
     def body(self, user, datestamp, permission):
         return file(self.location(user, permission, datestamp)).read()
@@ -154,14 +143,15 @@ class FileBlog(Blog):
             entries.extend([ (os.path.split(entry)[-1], permission) 
                              for entry in glob(os.path.join(self.location(user, permission), glob_expr)) ])
         entries.sort(key=lambda x: x[0], reverse=True)
         return [ self.get_entry(user, x[0], x[1]) for x in entries ]
 
     def post(self, user, datestamp, body, privacy):
         blog = file(self.location(user, privacy, datestamp), 'w')
         print >> blog, body
+        return Blog.post(user, datestamp, body, privacy)
 
     def delete(self, user, datestamp):
         for permission in 'public', 'secret', 'private':
             path = self.location(user, permission, datestamp)
             if os.path.exists(path):
                 os.remove(path)
--- a/bitsyblog/factory.py
+++ b/bitsyblog/factory.py
@@ -6,39 +6,52 @@ from paste.httpexceptions import HTTPExc
 # accepted configuration keys, e.g. 'bitsyblog.file_dir'
 config = set(['file_dir', 
               'date_format', 
               'subject', 
               'n_links', 
               'help_file', 
               'header', 
               'template_directories', 
-              'feed_items'])
+              'feed_items',
+              ])
+
+def get_args(app_conf):
+    """return arguments for bitsyblog and its handlers"""
+    key_str = 'bitsyblog.'
+    bitsyblog_args = {}
+    handler_args = {}
+    for key, value in app_conf.items():
+        if key.startswith(key_str):
+            key = key.split(key_str, 1)[-1]
+            if key in config:
+                bitysblog_args[key] = value
+        else:
+            if '.' in key:
+                section, key = key.split('.', 1)
+                handler_args.setdefault(section, {})[key] = value
+    return bitsyblog_args, handler_args
 
 def factory(global_conf, **app_conf):
     """make bitsyauth app and wrap it in middleware"""
-    key_str = 'bitsyblog.%s'
-    args = dict([ (key, app_conf[ key_str % key]) for key in config
-                  if app_conf.has_key(key_str % key) ])
+    bitsyblog_args, handler_args = get_args(app_conf)
     app = BitsyBlog(**args)
     secret = app_conf.get('secret', 'secret')
     return BitsyAuth(HTTPExceptionHandler(app), 
                      global_conf,
                      app.passwords,
                      app.newuser,
                      'bitsyblog', 
                      secret)
 
 
 def bitsierfactory(global_conf, **app_conf):
     """make single-user bitsyblog"""
-    key_str = 'bitsyblog.%s'
-    args = dict([ (key, app_conf[ key_str % key]) for key in config
-                  if app_conf.has_key(key_str % key) ])
-    user = app_conf['bitsyblog.user']
+    bitsyblog_args, handler_args = get_args(app_conf)
+    user = app_conf['bitsyblog.user'] # ensure this exist
     app = BitsierBlog(**args)
     app.user = user
     secret = app_conf.get('secret', 'secret')
     auth = BitsyAuth(HTTPExceptionHandler(app),
                      global_conf,
                      app.passwords,
                      newuser=None,
                      site=app_conf.get('site', 'bitsyblog'),