mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-27 15:58:06 -05:00
updates to JSON api and responses to /api POST interface:
* timestamps returned both as local time and as UTC (created_utc) * comment bodies are returned both in markdown and excaped sanitized html (using the same filter as reddit.com listings) * new POST parameter api_type=json returns simplified JSON responses for api interaction * /api/login returns a valid modhash and cookie when api_type=json
This commit is contained in:
@@ -79,7 +79,7 @@ class ApiController(RedditController):
|
||||
Controller which deals with almost all AJAX site interaction.
|
||||
"""
|
||||
|
||||
def response_func(self, **kw):
|
||||
def response_func(self, kw):
|
||||
data = dumps(kw)
|
||||
if request.method == "GET" and request.GET.get("callback"):
|
||||
return "%s(%s)" % (websafe_json(request.GET.get("callback")),
|
||||
@@ -97,10 +97,8 @@ class ApiController(RedditController):
|
||||
"""
|
||||
Get's a listing of links which have the provided url.
|
||||
"""
|
||||
listing = None
|
||||
if link and errors.ALREADY_SUB in c.errors:
|
||||
listing = link_listing_by_url(request.params.get('url'),
|
||||
count = count)
|
||||
listing = link_listing_by_url(request.params.get('url'),
|
||||
count = count)
|
||||
return BoringPage(_("API"), content = listing).render()
|
||||
|
||||
@validatedForm(VCaptcha(),
|
||||
@@ -261,6 +259,8 @@ class ApiController(RedditController):
|
||||
user cookie and send back a redirect.
|
||||
"""
|
||||
self.login(user, rem = rem)
|
||||
form._send_data(modhash = user.modhash())
|
||||
form._send_data(cookie = user.make_cookie())
|
||||
dest = dest or request.referer or '/'
|
||||
form.redirect(dest)
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ from pylons.i18n import _
|
||||
from copy import copy
|
||||
|
||||
error_list = dict((
|
||||
('USER_REQUIRED', _("please login to do that")),
|
||||
('NO_URL', _('url required')),
|
||||
('BAD_URL', _('you should check that url')),
|
||||
('NO_TITLE', _('title required')),
|
||||
|
||||
@@ -37,7 +37,7 @@ def to_referer(func, **params):
|
||||
|
||||
|
||||
class PostController(ApiController):
|
||||
def response_func(self, **kw):
|
||||
def response_func(self, kw):
|
||||
return Storage(**kw)
|
||||
|
||||
#TODO: feature disabled for now
|
||||
|
||||
@@ -26,7 +26,7 @@ from r2.lib import utils, captcha
|
||||
from r2.lib.filters import unkeep_space, websafe, _force_unicode
|
||||
from r2.lib.db.operators import asc, desc
|
||||
from r2.lib.template_helpers import add_sr
|
||||
from r2.lib.jsonresponse import json_respond, JQueryResponse
|
||||
from r2.lib.jsonresponse import json_respond, JQueryResponse, JsonResponse
|
||||
from r2.lib.jsontemplates import api_type
|
||||
|
||||
from r2.models import *
|
||||
@@ -110,68 +110,64 @@ def validate(*simple_vals, **param_vals):
|
||||
return newfn
|
||||
return val
|
||||
|
||||
def noresponse(*simple_vals, **param_vals):
|
||||
|
||||
def api_validate(response_function):
|
||||
"""
|
||||
AJAXy decorator which takes the place of validate when no response
|
||||
is expected from the controller method.
|
||||
Factory for making validators for API calls, since API calls come
|
||||
in two flavors: responsive and unresponsive. The machinary
|
||||
associated with both is similar, and the error handling identical,
|
||||
so this function abstracts away the kw validation and creation of
|
||||
a Json-y responder object.
|
||||
"""
|
||||
def val(fn):
|
||||
def newfn(self, *a, **env):
|
||||
c.render_style = api_type('html')
|
||||
c.response_content_type = 'application/json; charset=UTF-8'
|
||||
jquery = JQueryResponse()
|
||||
def _api_validate(*simple_vals, **param_vals):
|
||||
def val(fn):
|
||||
def newfn(self, *a, **env):
|
||||
c.render_style = api_type('html')
|
||||
c.response_content_type = 'application/json; charset=UTF-8'
|
||||
# generate a response object
|
||||
if request.params.get('api_type') == "json":
|
||||
responder = JsonResponse()
|
||||
else:
|
||||
responder = JQueryResponse()
|
||||
try:
|
||||
kw = _make_validated_kw(fn, simple_vals, param_vals, env)
|
||||
return response_function(self, fn, responder,
|
||||
simple_vals, param_vals, *a, **kw)
|
||||
except UserRequiredException:
|
||||
responder.send_failure(errors.USER_REQUIRED)
|
||||
return self.response_func(dict(iter(responder)))
|
||||
return newfn
|
||||
return val
|
||||
return _api_validate
|
||||
|
||||
|
||||
try:
|
||||
kw = _make_validated_kw(fn, simple_vals, param_vals, env)
|
||||
fn(self, *a, **kw)
|
||||
return ''
|
||||
except UserRequiredException:
|
||||
jquery = JQueryResponse()
|
||||
jquery.refresh()
|
||||
return self.response_func(**dict(list(jquery)))
|
||||
return newfn
|
||||
return val
|
||||
@api_validate
|
||||
def noresponse(self, self_method, responder, simple_vals, param_vals, *a, **kw):
|
||||
self_method(self, *a, **kw)
|
||||
return self.response_func({})
|
||||
|
||||
|
||||
def validatedForm(*simple_vals, **param_vals):
|
||||
"""
|
||||
AJAX response validator for general form handling. In addition to
|
||||
validating simple_vals and param_vals in the same way as validate,
|
||||
a jquery object and a jquery form object are allocated and passed
|
||||
into the method which is decorated.
|
||||
"""
|
||||
def val(fn):
|
||||
def newfn(self, *a, **env):
|
||||
# set the content type for the response
|
||||
c.render_style = api_type('html')
|
||||
c.response_content_type = 'application/json; charset=UTF-8'
|
||||
@api_validate
|
||||
def validatedForm(self, self_method, responder, simple_vals, param_vals,
|
||||
*a, **kw):
|
||||
# generate a form object
|
||||
form = responder(request.POST.get('id', "body"))
|
||||
|
||||
# generate a response object
|
||||
jquery = JQueryResponse()
|
||||
# generate a form object
|
||||
form = jquery(request.POST.get('id', "body"))
|
||||
# clear out the status line as a courtesy
|
||||
form.set_html(".status", "")
|
||||
# clear out the status line as a courtesy
|
||||
form.set_html(".status", "")
|
||||
|
||||
try:
|
||||
# do the actual work
|
||||
val = self_method(self, form, responder, *a, **kw)
|
||||
|
||||
kw = _make_validated_kw(fn, simple_vals, param_vals, env)
|
||||
val = fn(self, form, jquery, *a, **kw)
|
||||
# auto-refresh the captcha if there are errors.
|
||||
if (c.errors.errors and
|
||||
any(isinstance(v, VCaptcha) for v in simple_vals)):
|
||||
form.new_captcha()
|
||||
|
||||
if val: return val
|
||||
return self.response_func(dict(iter(responder)))
|
||||
|
||||
# auto-refresh the captcha if there are errors.
|
||||
if (c.errors.errors and
|
||||
any(isinstance(v, VCaptcha) for v in simple_vals)):
|
||||
form.new_captcha()
|
||||
|
||||
if val: return val
|
||||
return self.response_func(**dict(list(jquery)))
|
||||
|
||||
except UserRequiredException:
|
||||
jquery = JQueryResponse()
|
||||
jquery.refresh()
|
||||
return self.response_func(**dict(list(jquery)))
|
||||
return newfn
|
||||
return val
|
||||
|
||||
#### validators ####
|
||||
class nop(Validator):
|
||||
|
||||
@@ -27,63 +27,76 @@ from r2.lib.template_helpers import replace_render
|
||||
from r2.lib.jsontemplates import get_api_subtype
|
||||
from r2.lib.base import BaseController
|
||||
import simplejson
|
||||
from pylons import c
|
||||
|
||||
def json_respond(x):
|
||||
from pylons import c
|
||||
if get_api_subtype():
|
||||
res = JsonResponse()
|
||||
res.object = tup(x)
|
||||
res = dict(res)
|
||||
else:
|
||||
res = x or ''
|
||||
return websafe_json(simplejson.dumps(res))
|
||||
return websafe_json(simplejson.dumps(x or ''))
|
||||
|
||||
class JQueryResponse(object):
|
||||
class JsonResponse(object):
|
||||
"""
|
||||
class which mimics the jQuery in javascript for allowing Dom
|
||||
manipulations on the client side.
|
||||
|
||||
An instantiated JQueryResponse acts just like the "$" function on
|
||||
the JS layer with the exception of the ability to run arbitrary
|
||||
code on the client. Selectors and method functions evaluate to
|
||||
new JQueryResponse objects, and the transformations are cataloged
|
||||
by the original object which can be iterated and sent across the
|
||||
wire.
|
||||
Simple Api response handler, returning a list of errors generated
|
||||
in the api func's validators, as well as blobs of data set by the
|
||||
api func.
|
||||
"""
|
||||
def __init__(self, factory = None):
|
||||
def __init__(self):
|
||||
self._clear()
|
||||
|
||||
def _clear(self):
|
||||
self._has_errors = set([])
|
||||
self._new_captcha = False
|
||||
if factory:
|
||||
self.factory = factory
|
||||
self.ops = None
|
||||
self.objs = None
|
||||
else:
|
||||
self.factory = self
|
||||
self.objs = {self: 0}
|
||||
self.ops = []
|
||||
self._data = {}
|
||||
|
||||
def send_failure(self, error):
|
||||
c.errors.add(error)
|
||||
self._clear()
|
||||
self._has_errors.add(error)
|
||||
|
||||
def __call__(self, *a):
|
||||
return self.factory.transform(self, "call", a)
|
||||
return self
|
||||
|
||||
def __getattr__(self, key):
|
||||
if not key.startswith("__"):
|
||||
return self.factory.transform(self, "attr", key)
|
||||
|
||||
def transform(self, obj, op, args):
|
||||
new = self.__class__(self)
|
||||
newi = self.objs[new] = len(self.objs)
|
||||
self.ops.append([self.objs[obj], newi, op, args])
|
||||
return new
|
||||
return self
|
||||
|
||||
def __iter__(self):
|
||||
yield ("jquery", self.ops)
|
||||
res = {}
|
||||
if self._data:
|
||||
res['data'] = self._data
|
||||
res['errors'] = [(e, c.errors[e].message) for e in self._has_errors]
|
||||
yield ("json", res)
|
||||
|
||||
def _mark_error(self, e):
|
||||
pass
|
||||
|
||||
def _unmark_error(self, e):
|
||||
pass
|
||||
|
||||
def has_error(self):
|
||||
return bool(self._has_errors)
|
||||
|
||||
# thing methods
|
||||
#--------------
|
||||
|
||||
def has_errors(self, input, *errors, **kw):
|
||||
rval = False
|
||||
for e in errors:
|
||||
if e in c.errors:
|
||||
# get list of params checked to generate this error
|
||||
# if they exist, make sure they match input checked
|
||||
fields = c.errors[e].fields
|
||||
if not input or not fields or input in fields:
|
||||
self._has_errors.add(e)
|
||||
rval = True
|
||||
self._mark_error(e)
|
||||
else:
|
||||
self._unmark_error(e)
|
||||
|
||||
if rval and input:
|
||||
self.focus_input(input)
|
||||
return rval
|
||||
|
||||
def clear_errors(self, *errors):
|
||||
for e in errors:
|
||||
if e in self._has_errors:
|
||||
self._has_errors.remove(e)
|
||||
self._unmark_error(e)
|
||||
|
||||
def _things(self, things, action, *a, **kw):
|
||||
"""
|
||||
function for inserting/replacing things in listings.
|
||||
@@ -104,8 +117,8 @@ class JQueryResponse(object):
|
||||
if d.has_key('data'):
|
||||
d['data'].update(kw)
|
||||
|
||||
new = self.__getattr__(action)
|
||||
return new(data, *a)
|
||||
self._data['things'] = data
|
||||
return data
|
||||
|
||||
def insert_things(self, things, append = False, **kw):
|
||||
return self._things(things, "insert_things", append, **kw)
|
||||
@@ -115,6 +128,67 @@ class JQueryResponse(object):
|
||||
return self._things(things, "replace_things",
|
||||
keep_children, reveal, stubs, **kw)
|
||||
|
||||
def _send_data(self, **kw):
|
||||
self._data.update(kw)
|
||||
|
||||
|
||||
class JQueryResponse(JsonResponse):
|
||||
"""
|
||||
class which mimics the jQuery in javascript for allowing Dom
|
||||
manipulations on the client side.
|
||||
|
||||
An instantiated JQueryResponse acts just like the "$" function on
|
||||
the JS layer with the exception of the ability to run arbitrary
|
||||
code on the client. Selectors and method functions evaluate to
|
||||
new JQueryResponse objects, and the transformations are cataloged
|
||||
by the original object which can be iterated and sent across the
|
||||
wire.
|
||||
"""
|
||||
def __init__(self, top_node = None):
|
||||
if top_node:
|
||||
self.top_node = top_node
|
||||
else:
|
||||
self.top_node = self
|
||||
JsonResponse.__init__(self)
|
||||
self._clear()
|
||||
|
||||
def _clear(self):
|
||||
if self.top_node == self:
|
||||
self.objs = {self: 0}
|
||||
self.ops = []
|
||||
else:
|
||||
self.objs = None
|
||||
self.ops = None
|
||||
JsonResponse._clear(self)
|
||||
|
||||
def send_failure(self, error):
|
||||
JsonResponse.send_failure(self, error)
|
||||
self.refresh()
|
||||
|
||||
def __call__(self, *a):
|
||||
return self.top_node.transform(self, "call", a)
|
||||
|
||||
def __getattr__(self, key):
|
||||
if not key.startswith("__"):
|
||||
return self.top_node.transform(self, "attr", key)
|
||||
|
||||
def transform(self, obj, op, args):
|
||||
new = self.__class__(self)
|
||||
newi = self.objs[new] = len(self.objs)
|
||||
self.ops.append([self.objs[obj], newi, op, args])
|
||||
return new
|
||||
|
||||
def __iter__(self):
|
||||
yield ("jquery", self.ops)
|
||||
|
||||
# thing methods
|
||||
#--------------
|
||||
|
||||
def _things(self, things, action, *a, **kw):
|
||||
data = JsonResponse._things(self, things, action, *a, **kw)
|
||||
new = self.__getattr__(action)
|
||||
return new(data, *a)
|
||||
|
||||
def insert_table_rows(self, rows, index = -1):
|
||||
new = self.__getattr__("insert_table_rows")
|
||||
return new([row.render() for row in tup(rows)], index)
|
||||
@@ -122,31 +196,11 @@ class JQueryResponse(object):
|
||||
|
||||
# convenience methods:
|
||||
# --------------------
|
||||
def has_errors(self, input, *errors, **kw):
|
||||
from pylons import c
|
||||
rval = False
|
||||
for e in errors:
|
||||
if e in c.errors:
|
||||
# get list of params checked to generate this error
|
||||
# if they exist, make sure they match input checked
|
||||
fields = c.errors[e].fields
|
||||
if input and fields and input not in fields:
|
||||
continue
|
||||
self._has_errors.add(e)
|
||||
rval = True
|
||||
self.find("." + e).show().html(c.errors[e].message).end()
|
||||
else:
|
||||
self.find("." + e).html("").end()
|
||||
if rval and input:
|
||||
self.focus_input(input)
|
||||
return rval
|
||||
def _mark_error(self, e):
|
||||
self.find("." + e).show().html(c.errors[e].message).end()
|
||||
|
||||
def clear_errors(self, *errors):
|
||||
from pylons import c
|
||||
for e in errors:
|
||||
if e in self._has_errors:
|
||||
self._has_errors.remove(e)
|
||||
self.find("." + e).hide().html("").end()
|
||||
def _unmark_error(self, e):
|
||||
self.find("." + e).html("").end()
|
||||
|
||||
def new_captcha(self):
|
||||
if not self._new_captcha:
|
||||
|
||||
@@ -22,16 +22,17 @@
|
||||
from utils import to36, tup, iters
|
||||
from wrapped import Wrapped
|
||||
from mako.template import Template
|
||||
from r2.lib.filters import spaceCompress, safemarkdown
|
||||
import time, pytz
|
||||
from pylons import c
|
||||
|
||||
def api_type(subtype = ''):
|
||||
return 'api-' + subtype if subtype else 'api'
|
||||
|
||||
def is_api(subtype = ''):
|
||||
from pylons import c
|
||||
return c.render_style and c.render_style.startswith(api_type(subtype))
|
||||
|
||||
def get_api_subtype():
|
||||
from pylons import c
|
||||
if is_api() and c.render_style.startswith('api-'):
|
||||
return c.render_style[4:]
|
||||
|
||||
@@ -42,7 +43,6 @@ def make_fullname(typ, _id):
|
||||
return '%s_%s' % (make_typename(typ), to36(_id))
|
||||
|
||||
def mass_part_render(thing, **kw):
|
||||
from r2.lib.filters import spaceCompress
|
||||
return dict([(k, spaceCompress(thing.part_render(v)).strip(' ')) \
|
||||
for k, v in kw.iteritems()])
|
||||
|
||||
@@ -69,7 +69,6 @@ class TableRowTemplate(JsonTemplate):
|
||||
|
||||
class UserItemJsonTemplate(TableRowTemplate):
|
||||
def cells(self, thing):
|
||||
from r2.lib.filters import spaceCompress
|
||||
cells = []
|
||||
for cell in thing.cells:
|
||||
r = Wrapped.part_render(thing, 'cell_type', cell)
|
||||
@@ -84,7 +83,16 @@ class UserItemJsonTemplate(TableRowTemplate):
|
||||
|
||||
|
||||
class ThingJsonTemplate(JsonTemplate):
|
||||
__data_attrs__ = dict()
|
||||
_data_attrs_ = dict(id = "_id36",
|
||||
name = "_fullname",
|
||||
created = "created",
|
||||
created_utc = "created_utc")
|
||||
|
||||
@classmethod
|
||||
def data_attrs(cls, **kw):
|
||||
d = cls._data_attrs_.copy()
|
||||
d.update(kw)
|
||||
return d
|
||||
|
||||
def points(self, wrapped):
|
||||
"""
|
||||
@@ -121,9 +129,7 @@ class ThingJsonTemplate(JsonTemplate):
|
||||
* content : rendered representation of the thing by
|
||||
calling replace_render on it using the style of get_api_subtype().
|
||||
"""
|
||||
from r2.lib.filters import spaceCompress
|
||||
from r2.lib.template_helpers import replace_render
|
||||
from pylons import c
|
||||
listing = thing.listing if hasattr(thing, "listing") else None
|
||||
return dict(id = thing._fullname,
|
||||
#vl = self.points(thing),
|
||||
@@ -147,7 +153,7 @@ class ThingJsonTemplate(JsonTemplate):
|
||||
return x
|
||||
|
||||
return dict((k, strip_data(self.thing_attr(thing, v)))
|
||||
for k, v in self.__data_attrs__.iteritems())
|
||||
for k, v in self._data_attrs_.iteritems())
|
||||
|
||||
def thing_attr(self, thing, attr):
|
||||
"""
|
||||
@@ -156,15 +162,15 @@ class ThingJsonTemplate(JsonTemplate):
|
||||
which has to be gotten from the author_id attribute on most
|
||||
things).
|
||||
"""
|
||||
import time
|
||||
if attr == "author":
|
||||
return thing.author.name
|
||||
elif attr == "created":
|
||||
return time.mktime(thing._date.timetuple())
|
||||
elif attr == "created_utc":
|
||||
return time.mktime(thing._date.astimezone(pytz.UTC).timetuple())
|
||||
return getattr(thing, attr) if hasattr(thing, attr) else None
|
||||
|
||||
def data(self, thing):
|
||||
from pylons import c
|
||||
if get_api_subtype():
|
||||
return self.rendered_data(thing)
|
||||
else:
|
||||
@@ -174,33 +180,27 @@ class ThingJsonTemplate(JsonTemplate):
|
||||
return dict(kind = self.kind(thing), data = self.data(thing))
|
||||
|
||||
class SubredditJsonTemplate(ThingJsonTemplate):
|
||||
__data_attrs__ = dict(id = "_id36",
|
||||
name = "_fullname",
|
||||
subscribers = "score",
|
||||
title = "title",
|
||||
url = "path",
|
||||
description = "description",
|
||||
created = "created")
|
||||
_data_attrs_ = ThingJsonTemplate.data_attrs(subscribers = "score",
|
||||
title = "title",
|
||||
url = "path",
|
||||
description = "description")
|
||||
|
||||
class LinkJsonTemplate(ThingJsonTemplate):
|
||||
__data_attrs__ = dict(id = "_id36",
|
||||
name = "_fullname",
|
||||
ups = "upvotes",
|
||||
downs = "downvotes",
|
||||
score = "score",
|
||||
saved = "saved",
|
||||
clicked = "clicked",
|
||||
hidden = "hidden",
|
||||
likes = "likes",
|
||||
domain = "domain",
|
||||
title = "title",
|
||||
url = "url",
|
||||
author = "author",
|
||||
num_comments = "num_comments",
|
||||
created = "created",
|
||||
subreddit = "subreddit",
|
||||
subreddit_id = "subreddit_id")
|
||||
|
||||
_data_attrs_ = ThingJsonTemplate.data_attrs(ups = "upvotes",
|
||||
downs = "downvotes",
|
||||
score = "score",
|
||||
saved = "saved",
|
||||
clicked = "clicked",
|
||||
hidden = "hidden",
|
||||
likes = "likes",
|
||||
domain = "domain",
|
||||
title = "title",
|
||||
url = "url",
|
||||
author = "author",
|
||||
num_comments = "num_comments",
|
||||
subreddit = "subreddit",
|
||||
subreddit_id = "subreddit_id")
|
||||
|
||||
def thing_attr(self, thing, attr):
|
||||
if attr == 'subreddit':
|
||||
return thing.subreddit.name
|
||||
@@ -216,18 +216,16 @@ class LinkJsonTemplate(ThingJsonTemplate):
|
||||
|
||||
|
||||
class CommentJsonTemplate(ThingJsonTemplate):
|
||||
__data_attrs__ = dict(id = "_id36",
|
||||
name = "_fullname",
|
||||
ups = "upvotes",
|
||||
downs = "downvotes",
|
||||
replies = "child",
|
||||
body = "body",
|
||||
likes = "likes",
|
||||
author = "author",
|
||||
created = "created",
|
||||
link_id = "link_id",
|
||||
parent_id = "parent_id",
|
||||
)
|
||||
_data_attrs_ = ThingJsonTemplate.data_attrs(ups = "upvotes",
|
||||
downs = "downvotes",
|
||||
replies = "child",
|
||||
body = "body",
|
||||
body_html = "body_html",
|
||||
likes = "likes",
|
||||
author = "author",
|
||||
link_id = "link_id",
|
||||
parent_id = "parent_id",
|
||||
)
|
||||
|
||||
def thing_attr(self, thing, attr):
|
||||
from r2.models import Comment, Link
|
||||
@@ -238,6 +236,8 @@ class CommentJsonTemplate(ThingJsonTemplate):
|
||||
return make_fullname(Comment, thing.parent_id)
|
||||
except AttributeError:
|
||||
return make_fullname(Link, thing.link_id)
|
||||
elif attr == "body_html":
|
||||
return safemarkdown(thing.body)
|
||||
return ThingJsonTemplate.thing_attr(self, thing, attr)
|
||||
|
||||
def kind(self, wrapped):
|
||||
@@ -260,8 +260,8 @@ class CommentJsonTemplate(ThingJsonTemplate):
|
||||
return d
|
||||
|
||||
class MoreCommentJsonTemplate(CommentJsonTemplate):
|
||||
__data_attrs__ = dict(id = "_id36",
|
||||
name = "_fullname")
|
||||
_data_attrs_ = dict(id = "_id36",
|
||||
name = "_fullname")
|
||||
def points(self, wrapped):
|
||||
return []
|
||||
|
||||
@@ -269,18 +269,25 @@ class MoreCommentJsonTemplate(CommentJsonTemplate):
|
||||
return "more"
|
||||
|
||||
class MessageJsonTemplate(ThingJsonTemplate):
|
||||
__data_attrs__ = dict(id = "_id36",
|
||||
name = "_fullname",
|
||||
new = "new",
|
||||
subject = "subject",
|
||||
body = "body",
|
||||
author = "author",
|
||||
dest = "dest",
|
||||
created = "created")
|
||||
_data_attrs_ = ThingJsonTemplate.data_attrs(new = "new",
|
||||
subject = "subject",
|
||||
body = "body",
|
||||
body_html = "body_html",
|
||||
author = "author",
|
||||
dest = "dest",
|
||||
was_comment = "was_comment",
|
||||
created = "created")
|
||||
|
||||
def thing_attr(self, thing, attr):
|
||||
if attr == "dest":
|
||||
if attr == "was_comment":
|
||||
return hasattr(thing, "was_comment")
|
||||
elif attr == "context":
|
||||
return ("" if not hasattr(thing, "was_comment")
|
||||
else thing.permalink + "?context=3")
|
||||
elif attr == "dest":
|
||||
return thing.to.name
|
||||
elif attr == "body_html":
|
||||
return safemarkdown(thing.body)
|
||||
return ThingJsonTemplate.thing_attr(self, thing, attr)
|
||||
|
||||
def rendered_data(self, wrapped):
|
||||
@@ -313,15 +320,13 @@ class NullJsonTemplate(JsonTemplate):
|
||||
return None
|
||||
|
||||
class ListingJsonTemplate(ThingJsonTemplate):
|
||||
__data_attrs__ = dict(children = "things")
|
||||
_data_attrs_ = dict(children = "things")
|
||||
|
||||
def points(self, w):
|
||||
return []
|
||||
|
||||
def rendered_data(self, thing):
|
||||
from r2.lib.filters import spaceCompress
|
||||
from r2.lib.template_helpers import replace_render
|
||||
|
||||
res = []
|
||||
for a in thing.things:
|
||||
a.listing = thing
|
||||
|
||||
Reference in New Issue
Block a user