Skip to content

Commit

Permalink
Supports output=rssjson.
Browse files Browse the repository at this point in the history
  • Loading branch information
taehoon-kang committed Mar 13, 2012
1 parent 69b5c8a commit 33361d3
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 108 deletions.
4 changes: 2 additions & 2 deletions action/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

class ArticleList(Action):
LIST_PER_PAGE = 20
@rss(action.rss.CategoryArticleList)

@rss(action.feed.CategoryArticleList)
def get(self, category_name):
page = int(self.request.get('page', 1))
offset = (page - 1) * self.LIST_PER_PAGE
Expand Down
47 changes: 47 additions & 0 deletions action/feed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'''
@see https://developers.google.com/feed/v1/jsondevguide
'''
from lib.controller import Action
import models

class CategoryArticleList(Action):
def get(self, category_name):
def get_entry(item):
media_group_contents = []
if item['image']:
media_group_contents.append({'url': item['image'], 'medium': 'image', 'type': '', 'height':'', 'width': ''})
if item['video']:
media_group_contents.append({'url': item['video'], 'medium': 'video', 'type': '', 'height':'', 'width': ''})

entry = {
'title':item['title'],
'link':'%s/%s?page=%s' % (link, item['id'], page),
'contentSnippet': item['excerpt'],
'content': item['excerpt'],
'publishedDate':item['created'],
'author': item['author']['nickname'],
'categories': category.path,
'mediaGroups': [{'contents': media_group_contents}],
}

return entry

page = int(self.request.get('page', 1))
limit = int(self.request.get('limit', 20))
offset = (page - 1) * limit
category = models.Category.get_by_name(category_name)
if not category:
return None
link = '%s/#!/%s' % (self.request.host_url, category_name)
return {
'feedUrl': self.request.uri,
'title': category_name,
'link': link,
'type': 'rss20',
'description': category.description,
'entries': [get_entry(item) for item in models.Article.get_list(category=category, offset=offset, limit=limit)]
}

class ArticleCommentList(Action):
def get(self, category_name):
pass
56 changes: 0 additions & 56 deletions action/rss.py

This file was deleted.

4 changes: 2 additions & 2 deletions action/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import action
import settings

try:
try:
import json
except ImportError:
import simplejson as json
Expand Down Expand Up @@ -81,7 +81,7 @@ def get(self, article_id):
return Action.Result.DEFAULT

class Comment(Action):
@rss(action.rss.ArticleCommentList)
@rss(action.feed.ArticleCommentList)
def get(self, article_id):
offset = int(self.request.get('offset'))
self.comment_list = models.Comment.get_list(article=models.Article.get_by_id(int(article_id)), offset=offset)
Expand Down
Binary file removed bootstrap.pyc
Binary file not shown.
11 changes: 8 additions & 3 deletions lib/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def _execute(self, method_name, *args):

output = self.request.get('output')

if output == 'json' or (result == Action.Result.DEFAULT and self.__action.is_ajax) or result is Action.Result.JSON:
if output == 'json' or (output != 'html' and result == Action.Result.DEFAULT and self.__action.is_ajax) or result is Action.Result.JSON:
context = self.__action._get_context()
for key in NON_AJAX_CONTEXT_KEYS:
if hasattr(self.__action, key):
Expand All @@ -128,10 +128,14 @@ def _execute(self, method_name, *args):
def handle_exception(self, e, debug):
self.response.set_status(500, e)
if debug:
import sys
sys.stderr.write(e)
if not self.__action.is_ajax:
raise e
else:
sys.stderr.write(e)

def _find_template(self, result_name):
if not isinstance(result_name, str):
return None
if result_name.startswith('/'):
return result_name[1:]
result = [self.__action.__module__.replace('%s.' % ACTION_PACKAGE, '')]
Expand Down Expand Up @@ -283,4 +287,5 @@ class Result(object):
HTML = 'html'
INPUT = 'input'
RSS = 'rss'
RSSJSON = 'rssjson'
JSON = '__json__'
37 changes: 32 additions & 5 deletions lib/decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from action import rss as rss_module
from google.appengine.api import users
from lib import PyRSS2Gen
from lib.controller import Action
import json
import datetime
import logging


Expand Down Expand Up @@ -32,13 +34,38 @@ def new(*args):

def rss(rss_action_class):
def wrap(action_method):
def get_enclosure(item):
if not item.has_key('mediaGroups') or len(item['mediaGroups']) == 0 or not item['mediaGroups'][0].has_key('contents') or len(item['mediaGroups'][0]['contents']) == 0:
return None
enclosure = item['mediaGroups'][0]['contents'][0]
return PyRSS2Gen.Enclosure(url = enclosure['url'], length = 10000, type = enclosure['medium'])

def wrapped_f(*args):
action_class = args[0]
if action_class.request.get('output') == Action.Result.RSS:
output = action_class.request.get('output')
if output == Action.Result.RSS or output == Action.Result.RSSJSON:
result = getattr(rss_action_class(action_class.request, action_class.response, action_class._get_context()), 'get')(*args[1:])
if hasattr(result, 'write_xml'):
action_class.response.headers['Content-type'] = 'text/xml'
result.write_xml(action_class.response.out, 'utf-8')
if result:
if output == Action.Result.RSS:
feed = PyRSS2Gen.RSS2(
title = result['title'],
link = result['link'],
description = result['description'],
lastBuildDate = datetime.datetime.utcnow(),
items = [PyRSS2Gen.RSSItem(
title=item['title'],
link=item['link'],
description=item['contentSnippet'],
pubDate=item['publishedDate'],
author=item['author'],
categories=item['categories'],
enclosure=get_enclosure(item)
) for item in result['entries']],
)
action_class.response.headers['Content-type'] = 'text/xml'
feed.write_xml(action_class.response.out, 'utf-8')
elif output == Action.Result.RSSJSON:
action_class.response.out.write(json.dumps(result, default=lambda obj: obj.strftime('%a, %d %b %Y %H:%M:%S 0000') if isinstance(obj, datetime.datetime) else None))
else:
action_class.response.set_status(404)
else:
Expand Down
3 changes: 0 additions & 3 deletions lib/json_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@
encode(input): Direct method to encode GQL objects as JSON.
"""




class GqlEncoder(json.JSONEncoder):
"""Extends JSONEncoder to add support for GQL results and properties.
Expand Down
2 changes: 1 addition & 1 deletion models.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def get_article_list(cls, user=None, limit=20, offset=0, orderby='created'):
q = Article.all()
q.filter('author = ', User.get_current() if user is None else user)
q.order('-%s' % orderby)
return [{'id': item.key().id(), 'category': item.category.name, 'title': item.title, 'excerpt': item.excerpt, 'comment_count': item.comment_count, 'like_count': item.like_count, 'hate_count': item.hate_count, 'created': item.created, 'last_updated': item.last_updated} for item in q.fetch(limit, offset)]
return [{'id': item.key().id(), 'category': item.category.name, 'title': item.title, 'excerpt': item.excerpt, 'comment_count': item.comment_count, 'like_count': item.like_count, 'hate_count': item.hate_count, 'created': item.created, 'last_updated': item.last_updated, 'image': item.image, 'video': item.video} for item in q.fetch(limit, offset)]

@classmethod
def get_comment_list(cls, user=None, limit=20, offset=0, orderby='created'):
Expand Down
Binary file removed models.pyc
Binary file not shown.
Binary file removed settings.pyc
Binary file not shown.
55 changes: 49 additions & 6 deletions static/css/openalive.css
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ time {
white-space: nowrap
}

#article-list .comment-count {
.comment-count {
font-weight: bold
}

Expand Down Expand Up @@ -175,7 +175,7 @@ time {
}

#comment-load-more {
background: none;
background: none;
}

#best-comments li {
Expand All @@ -201,7 +201,7 @@ time {
}

#best-comments .comment-content time,#comments .comment-content time {
color: gray;
color: #999;
}

#comments .comment-btns {
Expand Down Expand Up @@ -242,7 +242,7 @@ time {
}

#article-item-meta time {
color: gray
color: #999
}

#article-item-author-avatar {
Expand Down Expand Up @@ -379,6 +379,7 @@ iframe {
}

#tag-cloud li a:link {
white-space: nowrap;
margin: 0 10px;
color: #0063DC;
text-decoration: none;
Expand Down Expand Up @@ -417,7 +418,7 @@ iframe {
padding: 0;
}

#container .breadcrumb li i, #nav li i {
#container .breadcrumb li i,#nav li i {
margin-right: 2px;
vertical-align: middle;
}
Expand All @@ -428,6 +429,48 @@ iframe {
float: left;
margin: 4px 0
}

.thumbnails .thumbnail time {
color: gray
color: #999
}

#user-changes li,#user-comments li,#user-articles li {
padding: 4px;
clear: both;
margin-bottom: 1em;
border-bottom: 1px solid #eee
}

#user-changes li time,#user-comments li time,#user-articles li time {
color: #999;
margin-left: 5px
}

#user-changes li .nickname {
font-weight: bold
}

#user-articles li .excerpt img {
max-width: 85px;
margin: 5px 10px 5px 0;
float: left;
}

#user-comments li p,#user-articles li .excerpt {
padding-top: 10px;
display: inline-block;
}

#user-articles li .excerpt a {
color: #333
}

#user-comments li h4,#user-articles li h4 {
display: inline;
}

#user-changes .load-more,#user-comments .load-more, #user-articles .load-more {
padding: 0;
margin: 0;
border: none;
}
Loading

0 comments on commit 33361d3

Please sign in to comment.