Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 729699f083e9ff3fc1337a55572f3a9c02d5f727 0 parents
@ericflo authored
1  .gitignore
@@ -0,0 +1 @@
+*.pyc
1  INSTALL.txt
@@ -0,0 +1 @@
+Nothing to see here, yet.
29 LICENSE.txt
@@ -0,0 +1,29 @@
+Copyright (c) 2008, Eric Florenzano
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of the author nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
1  README.txt
@@ -0,0 +1 @@
+Nothing to see here, yet.
26 couch_lifestream/__init__.py
@@ -0,0 +1,26 @@
+from couchdb import client
+from django.conf import settings
+
+class CouchDBImproperlyConfigured(Exception):
+ pass
+
+try:
+ HOST = settings.COUCHDB_HOST
+except AttributeError:
+ raise CouchDBImproperlyConfigured("Please ensure that COUCHDB_HOST is " + \
+ "set in your settings file.")
+
+DATABASE_NAME = getattr(settings, 'COUCHDB_DATABASE_NAME', 'couch_lifestream')
+COUCHDB_DESIGN_DOCNAME = getattr(settings, 'COUCHDB_DESIGN_DOCNAME',
+ 'couch_lifestream-design')
+
+if not hasattr(settings, 'couchdb_server'):
+ server = client.Server(HOST)
+ settings.couchdb_server = server
+
+if not hasattr(settings, 'couchdb_db'):
+ try:
+ db = server.create(DATABASE_NAME)
+ except client.ResourceConflict:
+ db = server[DATABASE_NAME]
+ settings.couchdb_db = db
21 couch_lifestream/management/__init__.py
@@ -0,0 +1,21 @@
+from django.db.models import signals
+from couch_lifestream import models, db, COUCHDB_DESIGN_DOCNAME
+from couchdb.design import ViewDefinition
+from textwrap import dedent
+from django.conf import settings
+
+item_type_date = ViewDefinition(COUCHDB_DESIGN_DOCNAME, 'item_type_date',
+ dedent("""function(doc) {
+ emit([doc.item_type, doc.couch_lifestream_date], null);
+ }
+"""))
+
+by_date = ViewDefinition(COUCHDB_DESIGN_DOCNAME, 'by_date',
+ dedent("""function(doc) {
+ emit(doc.couch_lifestream_date, null);
+ }
+"""))
+
+def create_couchdb_views(app, created_models, verbosity, **kwargs):
+ ViewDefinition.sync_many(db, [item_type_date, by_date])
+signals.post_syncdb.connect(create_couchdb_views, sender=models)
1  couch_lifestream/management/commands/__init__.py
@@ -0,0 +1 @@
+
54 couch_lifestream/management/commands/fetch_lifestream_items.py
@@ -0,0 +1,54 @@
+import datetime
+import time
+from django.core.management.base import NoArgsCommand
+from django.conf import settings
+from urllib2 import urlopen
+from couch_lifestream import db
+
+try:
+ import simplejson as json
+except ImportError:
+ import json
+
+TWITTER_USERNAME = getattr(settings, 'TWITTER_USERNAME', None)
+
+def fetch_twitter_items():
+ from dateutil.parser import parse
+ print "Fetching Twitter items"
+ fetched = urlopen('http://twitter.com/statuses/user_timeline.json?id=%s' % (
+ TWITTER_USERNAME,)).read()
+ data = json.loads(fetched)
+ map_fun = 'function(doc) { emit(doc.id, null); }'
+ for item in data:
+ item['item_type'] = 'twitter'
+ item['couch_lifestream_date'] = parse(item['created_at']).isoformat()
+ if len(db.query(map_fun, key=item['id'])) == 0:
+ db.create(item)
+ print "Twitter items fetched"
+
+POWNCE_USERNAME = getattr(settings, 'POWNCE_USERNAME', None)
+
+def fetch_pownce_items():
+ print "Fetching Pownce items"
+ fetched = urlopen('http://api.pownce.com/2.0/note_lists/%s.json' % (
+ TWITTER_USERNAME,)).read()
+ data = json.loads(fetched)['notes']
+ map_fun = 'function(doc) { emit(doc.id, null); }'
+ for item in data:
+ item['item_type'] = 'pownce'
+ y, month, d, h, m, s, wd, jd, ds = time.gmtime(item['timestamp'])
+ couch_lifestream_date = datetime.datetime(y, month, d, h, m, s)
+ item['couch_lifestream_date'] = couch_lifestream_date.isoformat()
+ if len(db.query(map_fun, key=item['id'])) == 0:
+ db.create(item)
+ print "Pownce items fetched"
+
+class Command(NoArgsCommand):
+ help = 'Fetch the latest lifestream items and insert them into CouchDB.'
+
+ def handle_noargs(self, **options):
+ if TWITTER_USERNAME is not None:
+ fetch_twitter_items()
+ if POWNCE_USERNAME is not None:
+ fetch_pownce_items()
+ print "Finished loading lifestream items."
1  couch_lifestream/models.py
@@ -0,0 +1 @@
+# Nothing to see here. We're using CouchDB :)
3  couch_lifestream/templates/couch_lifestream/item.html
@@ -0,0 +1,3 @@
+{% load couch_lifestream_tags %}
+
+{% display_lifestream_item item %}
5 couch_lifestream/templates/couch_lifestream/list.html
@@ -0,0 +1,5 @@
+{% load couch_lifestream_tags %}
+
+{% for item in items %}
+ {% display_lifestream_item item %}<br />
+{% endfor %}
1  couch_lifestream/templates/couch_lifestream/pownce_item.html
@@ -0,0 +1 @@
+{{ item }}
1  couch_lifestream/templates/couch_lifestream/twitter_item.html
@@ -0,0 +1 @@
+{{ item }}
1  couch_lifestream/templatetags/__init__.py
@@ -0,0 +1 @@
+
31 couch_lifestream/templatetags/couch_lifestream_tags.py
@@ -0,0 +1,31 @@
+from django import template
+from django.template.loader import render_to_string
+from couch_lifestream import db
+from copy import copy
+
+register = template.Library()
+
+def do_display_lifestream_item(parser, token):
+ try:
+ split = token.split_contents()
+ except ValueError:
+ raise template.TemplateSyntaxError('%r tag must be of format {%% %r ITEM %%}' % (token.contents.split()[0], token.contents.split()[0]))
+ if len(split) != 2:
+ raise template.TemplateSyntaxError('%r tag must be of format {%% %r ITEM %%}' % (token.contents.split()[0], token.contents.split()[0]))
+ return DisplayLifestreamItemNode(split[1])
+
+class DisplayLifestreamItemNode(template.Node):
+ def __init__(self, row):
+ self.row = template.Variable(row)
+
+ def render(self, context):
+ row = self.row.resolve(context)
+ item = db[row.id]
+ context_with_item = copy(context)
+ context_with_item['item'] = item
+ return render_to_string(
+ 'couch_lifestream/%s_item.html' % (item['item_type'],),
+ context_with_item
+ )
+
+register.tag('display_lifestream_item', do_display_lifestream_item)
7 couch_lifestream/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('couch_lifestream.views',
+ url(r'^all/$', 'items', name='clife_all'),
+ url(r'^service/(?P<service>\S+)/$', 'items', name='clife_service'),
+ url(r'^item/(?P<id>\S+)/$', 'item', name='clife_item'),
+)
38 couch_lifestream/views.py
@@ -0,0 +1,38 @@
+import datetime
+from couch_lifestream import db, COUCHDB_DESIGN_DOCNAME
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.http import Http404
+from couchdb import client
+
+def items(request, service=None):
+ kwargs = dict(descending=True)
+ if service is None:
+ item_type_viewname = '%s/by_date' % (COUCHDB_DESIGN_DOCNAME,)
+ lifestream_items = db.view(item_type_viewname, **kwargs)
+ else:
+ item_type_viewname = '%s/item_type_date' % (COUCHDB_DESIGN_DOCNAME,)
+ lifestream_items = db.view(item_type_viewname, **kwargs)[
+ [service, "z"]:[service, None]]
+ context = {
+ 'items': list(lifestream_items),
+ }
+ return render_to_response(
+ 'couch_lifestream/list.html',
+ context,
+ context_instance=RequestContext(request)
+ )
+
+def item(request, id):
+ try:
+ obj = db[id]
+ except client.ResourceNotFound:
+ raise Http404
+ context = {
+ 'item': db[id],
+ }
+ return render_to_response(
+ 'couch_lifestream/item.html',
+ context,
+ context_instance=RequestContext(request)
+ )
Please sign in to comment.
Something went wrong with that request. Please try again.