Mercurial > libervia-web
comparison src/server/blog.py @ 704:5319110a862c
server_side: static blog uses the default template
author | souliane <souliane@mailoo.org> |
---|---|
date | Thu, 04 Jun 2015 12:39:27 +0200 |
parents | d94feb0d849e |
children | 531eacb82e9f |
comparison
equal
deleted
inserted
replaced
703:1a19ee7d8d8a | 704:5319110a862c |
---|---|
25 from twisted.internet import defer | 25 from twisted.internet import defer |
26 from twisted.web import server | 26 from twisted.web import server |
27 from twisted.web.resource import Resource | 27 from twisted.web.resource import Resource |
28 from twisted.words.protocols.jabber.jid import JID | 28 from twisted.words.protocols.jabber.jid import JID |
29 from datetime import datetime | 29 from datetime import datetime |
30 from sys import path | |
31 import importlib | |
30 import uuid | 32 import uuid |
31 import re | 33 import re |
32 import os | 34 import os |
33 | 35 |
34 from libervia.server.html_tools import sanitizeHtml, convertNewLinesToXHTML | 36 from libervia.server.html_tools import sanitizeHtml, convertNewLinesToXHTML |
35 from libervia.server.constants import Const as C | 37 from libervia.server.constants import Const as C |
36 | 38 |
37 | 39 |
38 class MicroBlog(Resource): | 40 class TemplateProcessor(object): |
41 | |
42 THEME = 'default' | |
43 | |
44 def __init__(self, host): | |
45 self.host = host | |
46 | |
47 # add Libervia's themes directory to the python path | |
48 path.append(os.path.dirname(self.host.themes_dir)) | |
49 | |
50 def useTemplate(self, request, tpl, data=None): | |
51 root_url = '../' * len(request.postpath) | |
52 theme_url = os.path.join(root_url, 'themes', self.THEME) | |
53 | |
54 # import the theme module | |
55 themes = os.path.basename(os.path.dirname(os.path.dirname(self.host.themes_dir))) | |
56 theme = importlib.import_module("%s.templates" % self.THEME, themes) | |
57 data_ = {'theme': theme_url, | |
58 'images': os.path.join(theme_url, 'images'), | |
59 'styles': os.path.join(theme_url, 'styles'), | |
60 } | |
61 if data: | |
62 data_.update(data) | |
63 return (getattr(theme, tpl.upper()).format(**data_)).encode('utf-8') | |
64 | |
65 | |
66 class MicroBlog(Resource, TemplateProcessor): | |
39 isLeaf = True | 67 isLeaf = True |
40 | |
41 ERROR_TEMPLATE = """ | |
42 <html> | |
43 <head profile="http://www.w3.org/2005/10/profile"> | |
44 <link rel="icon" type="image/png" href="%(root)ssat_logo_16.png"> | |
45 <title>MICROBLOG ERROR</title> | |
46 </head> | |
47 <body> | |
48 <h1 style='text-align: center; color: red;'>%(message)s</h1> | |
49 </body> | |
50 </html> | |
51 """ | |
52 | 68 |
53 def __init__(self, host): | 69 def __init__(self, host): |
54 self.host = host | 70 self.host = host |
55 Resource.__init__(self) | 71 Resource.__init__(self) |
72 TemplateProcessor.__init__(self, host) | |
56 self.host.bridge.register('entityDataUpdated', self.entityDataUpdatedCb) | 73 self.host.bridge.register('entityDataUpdated', self.entityDataUpdatedCb) |
57 self.host.bridge.register('actionResult', self.actionResultCb) # FIXME: actionResult is to be removed | 74 self.host.bridge.register('actionResult', self.actionResultCb) # FIXME: actionResult is to be removed |
58 self.avatars_cache = {} | 75 self.avatars_cache = {} |
59 self.waiting_deferreds = {} | 76 self.waiting_deferreds = {} |
60 | 77 |
114 self.waiting_deferreds[jid_s] = (request_id, defer.Deferred()) | 131 self.waiting_deferreds[jid_s] = (request_id, defer.Deferred()) |
115 return self.waiting_deferreds[jid_s][1] | 132 return self.waiting_deferreds[jid_s][1] |
116 | 133 |
117 def render_GET(self, request): | 134 def render_GET(self, request): |
118 if not request.postpath: | 135 if not request.postpath: |
119 return MicroBlog.ERROR_TEMPLATE % {'root': '', | 136 return self.useTemplate(request, "error", {'message': "You must indicate a nickname"}) |
120 'message': "You must indicate a nickname"} | 137 |
138 prof_requested = request.postpath[0] | |
139 #TODO: char check: only use alphanumerical chars + some extra(_,-,...) here | |
140 prof_found = self.host.bridge.getProfileName(prof_requested) | |
141 if not prof_found or prof_found == C.SERVICE_PROFILE: | |
142 return self.useTemplate(request, "error", {'message': "Invalid nickname"}) | |
143 | |
144 d = defer.Deferred() | |
145 JID(self.host.bridge.asyncGetParamA('JabberID', 'Connection', 'value', C.SERVER_SECURITY_LIMIT, prof_found, callback=d.callback, errback=d.errback)) | |
146 d.addCallbacks(lambda pub_jid_s: self.gotJID(pub_jid_s, request, prof_found)) | |
147 return server.NOT_DONE_YET | |
148 | |
149 def gotJID(self, pub_jid_s, request, profile): | |
150 pub_jid = JID(pub_jid_s) | |
151 d = defer.Deferred() | |
152 item_id = None | |
153 atom = None | |
154 | |
155 if len(request.postpath) > 1: | |
156 if request.postpath[1] == 'atom.xml': # return the atom feed | |
157 atom = True | |
158 else: | |
159 try: # check if the given path is a valid UUID | |
160 uuid.UUID(request.postpath[1]) | |
161 item_id = request.postpath[1] | |
162 except ValueError: | |
163 pass | |
164 | |
165 rsm_ = self.parseURLParams(request, item_id) | |
166 max_items = int(rsm_['max']) | |
167 | |
168 if atom is not None: | |
169 d.addCallbacks(self.render_atom_feed, self.render_error_blog, [request], None, [request, profile], None) | |
170 self.host.bridge.getGroupBlogsAtom(pub_jid.userhost(), rsm_, C.SERVICE_PROFILE, d.callback, d.errback) | |
171 return | |
172 | |
173 d.addCallbacks(self.render_html_blog, self.render_error_blog, [request, profile], None, [request, profile], None) | |
174 if item_id: | |
175 if max_items > 0: # display one message and its comments | |
176 self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [item_id], {}, max_items, C.SERVICE_PROFILE, d.callback, d.errback) | |
177 else: # display one message, count its comments | |
178 self.host.bridge.getGroupBlogs(pub_jid.userhost(), [item_id], {}, True, C.SERVICE_PROFILE, d.callback, d.errback) | |
121 else: | 179 else: |
122 prof_requested = request.postpath[0] | 180 if max_items == 1: # display one message and its comments |
123 #TODO: char check: only use alphanumerical chars + some extra(_,-,...) here | 181 self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [], rsm_, C.RSM_MAX_COMMENTS, C.SERVICE_PROFILE, d.callback, d.errback) |
124 prof_found = self.host.bridge.getProfileName(prof_requested) | 182 else: # display the last messages, count their comments |
125 if not prof_found or prof_found == C.SERVICE_PROFILE: | 183 self.host.bridge.getGroupBlogs(pub_jid.userhost(), [], rsm_, True, C.SERVICE_PROFILE, d.callback, d.errback) |
126 return MicroBlog.ERROR_TEMPLATE % {'root': '../' * len(request.postpath), | 184 |
127 'message': "Invalid nickname"} | 185 def parseURLParams(self, request, item_id): |
128 else: | 186 # retrieve RSM request data from URL parameters |
129 def got_jid(pub_jid_s): | 187 rsm_ = {} |
130 pub_jid = JID(pub_jid_s) | 188 try: |
131 d2 = defer.Deferred() | 189 rsm_['max'] = request.args['max'][0] |
132 item_id = None | 190 except (ValueError, KeyError): |
133 atom = None | 191 rsm_['max'] = unicode(C.RSM_MAX_ITEMS if item_id else C.RSM_MAX_COMMENTS) |
134 rsm_ = {} | 192 try: |
135 | 193 rsm_['index'] = request.args['index'][0] |
136 if len(request.postpath) > 1: | 194 except (ValueError, KeyError): |
137 if request.postpath[1] == 'atom.xml': # return the atom feed | 195 try: |
138 atom = True | 196 rsm_['before'] = request.args['before'][0] |
139 else: | 197 except KeyError: |
140 try: # check if the given path is a valid UUID | 198 try: |
141 uuid.UUID(request.postpath[1]) | 199 rsm_['after'] = request.args['after'][0] |
142 item_id = request.postpath[1] | 200 except KeyError: |
143 except ValueError: | 201 pass |
144 pass | 202 return rsm_ |
145 | |
146 # retrieve RSM request data from URL parameters | |
147 try: | |
148 max_items = int(request.args['max'][0]) | |
149 except (ValueError, KeyError): | |
150 max_items = C.RSM_MAX_ITEMS if item_id else C.RSM_MAX_COMMENTS | |
151 rsm_['max'] = unicode(max_items) | |
152 try: | |
153 rsm_['index'] = request.args['index'][0] | |
154 except (ValueError, KeyError): | |
155 try: | |
156 rsm_['before'] = request.args['before'][0] | |
157 except KeyError: | |
158 try: | |
159 rsm_['after'] = request.args['after'][0] | |
160 except KeyError: | |
161 pass | |
162 | |
163 if atom is not None: | |
164 d2.addCallbacks(self.render_atom_feed, self.render_error_blog, [request], None, [request, prof_found], None) | |
165 self.host.bridge.getGroupBlogsAtom(pub_jid.userhost(), rsm_, C.SERVICE_PROFILE, d2.callback, d2.errback) | |
166 return | |
167 | |
168 d2.addCallbacks(self.render_html_blog, self.render_error_blog, [request, prof_found], None, [request, prof_found], None) | |
169 if item_id: | |
170 if max_items > 0: # display one message and its comments | |
171 self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [item_id], {}, max_items, C.SERVICE_PROFILE, d2.callback, d2.errback) | |
172 else: # display one message, count its comments | |
173 self.host.bridge.getGroupBlogs(pub_jid.userhost(), [item_id], {}, True, C.SERVICE_PROFILE, d2.callback, d2.errback) | |
174 else: | |
175 if max_items == 1: # display one message and its comments | |
176 self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [], rsm_, C.RSM_MAX_COMMENTS, C.SERVICE_PROFILE, d2.callback, d2.errback) | |
177 else: # display the last messages, count their comments | |
178 self.host.bridge.getGroupBlogs(pub_jid.userhost(), [], rsm_, True, C.SERVICE_PROFILE, d2.callback, d2.errback) | |
179 | |
180 d1 = defer.Deferred() | |
181 JID(self.host.bridge.asyncGetParamA('JabberID', 'Connection', 'value', C.SERVER_SECURITY_LIMIT, prof_found, callback=d1.callback, errback=d1.errback)) | |
182 d1.addCallbacks(got_jid) | |
183 | |
184 return server.NOT_DONE_YET | |
185 | 203 |
186 def render_html_blog(self, mblog_data, request, profile): | 204 def render_html_blog(self, mblog_data, request, profile): |
187 """Retrieve the user parameters before actually rendering the static blog | 205 """Retrieve the user parameters before actually rendering the static blog |
188 | 206 |
189 @param mblog_data (list): couple (list, dict) with: | 207 @param mblog_data (list): couple (list, dict) with: |
243 url = url | 261 url = url |
244 suffix = "<br/>" | 262 suffix = "<br/>" |
245 else: | 263 else: |
246 url = default | 264 url = default |
247 suffix = "" | 265 suffix = "" |
248 return "<img src='%(url)s' alt='%(alt)s'/>%(suffix)s" % {'alt': alt, 'url': url, 'suffix': suffix} | 266 return self.useTemplate(request, "banner", {'alt': alt, 'url': url, 'suffix': suffix}) |
249 | 267 |
250 avatar = os.path.normpath(root_url + getOption('avatar')) | 268 avatar = os.path.normpath(root_url + getOption('avatar')) |
251 title = getOption(C.STATIC_BLOG_PARAM_TITLE) or user | 269 title = getOption(C.STATIC_BLOG_PARAM_TITLE) or user |
252 request.write(""" | 270 data = {'base_url': base_url, |
253 <html> | 271 'user': user, |
254 <head> | 272 'keywords': getOption(C.STATIC_BLOG_PARAM_KEYWORDS), |
255 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | 273 'description': getOption(C.STATIC_BLOG_PARAM_DESCRIPTION), |
256 <meta name="keywords" content="%(keywords)s"> | 274 'title': getOption(C.STATIC_BLOG_PARAM_TITLE) or "%s's microblog" % user, |
257 <meta name="description" content="%(description)s"> | 275 'favicon': avatar, |
258 <link rel="alternate" type="application/atom+xml" href="%(base)s/atom.xml"/> | 276 'banner_elt': getImageOption(C.STATIC_BLOG_PARAM_BANNER, avatar, title), |
259 <link rel="stylesheet" type="text/css" href="%(root)scss/blog.css" /> | 277 'title_elt': title, |
260 <link rel="icon" type="image/png" href="%(favicon)s"> | 278 } |
261 <title>%(title)s</title> | 279 |
262 </head> | |
263 <body> | |
264 <div class="mblog_title"><a href="%(base)s">%(banner_elt)s%(title_elt)s</a></div> | |
265 """ % {'base': base_url, | |
266 'root': root_url, | |
267 'user': user, | |
268 'keywords': getOption(C.STATIC_BLOG_PARAM_KEYWORDS), | |
269 'description': getOption(C.STATIC_BLOG_PARAM_DESCRIPTION), | |
270 'title': getOption(C.STATIC_BLOG_PARAM_TITLE) or "%s's microblog" % user, | |
271 'favicon': avatar, | |
272 'banner_elt': getImageOption(C.STATIC_BLOG_PARAM_BANNER, avatar, title), | |
273 'title_elt': title, | |
274 }) | |
275 mblog_data, main_rsm = mblog_data | 280 mblog_data, main_rsm = mblog_data |
276 display_single = len(mblog_data) == 1 | |
277 | |
278 # build the navigation links | |
279 count = int(main_rsm['count']) if 'count' in main_rsm else 0 | |
280 if count > 0: | |
281 index = int(main_rsm['index']) | |
282 if index > 0: | |
283 before_link = ("%(base)s?before=%(item_id)s" % {'base': base_url, 'item_id': main_rsm['first']}).encode('utf-8') | |
284 if display_single: | |
285 before_link += '&max=1' | |
286 tmp_text = D_("later message") | |
287 class_ = 'later_message' | |
288 else: | |
289 tmp_text = D_("later messages") | |
290 class_ = 'later_messages' | |
291 before_tag = """<a href="%(link)s" class="%(class)s">%(text)s</a>""" % {'link': before_link, 'class': class_, 'text': tmp_text} | |
292 else: | |
293 before_tag = None | |
294 if index + len(mblog_data) < count: | |
295 after_link = ("%(base)s?after=%(item_id)s" % {'base': base_url, 'item_id': main_rsm['last']}).encode('utf-8') | |
296 if display_single: | |
297 after_link += '&max=1' | |
298 text = D_("older message") | |
299 class_ = 'older_message' | |
300 else: | |
301 text = D_("older messages") | |
302 class_ = 'older_messages' | |
303 after_tag = """<a href="%(link)s" class="%(class)s">%(text)s</a>""" % {'link': after_link, 'class': class_, 'text': text} | |
304 else: | |
305 after_tag = None | |
306 | |
307 # display navigation header | |
308 request.write("""<div class="header">""") | |
309 request.write("""<div class="header_content">""") | |
310 if before_tag: | |
311 request.write(before_tag) | |
312 if display_single and after_tag: | |
313 request.write(after_tag) | |
314 request.write("""</div></div>""") | |
315 | |
316 mblog_data = [(entry if isinstance(entry, tuple) else (entry, ([], {}))) for entry in mblog_data] | 281 mblog_data = [(entry if isinstance(entry, tuple) else (entry, ([], {}))) for entry in mblog_data] |
317 mblog_data = sorted(mblog_data, key=lambda entry: (-float(entry[0].get('updated', 0)))) | 282 mblog_data = sorted(mblog_data, key=lambda entry: (-float(entry[0].get('updated', 0)))) |
318 for main_data, comments_data in mblog_data: | 283 |
319 self.__render_html_entry(main_data, base_url, request) | 284 data.update(self.getNavigationLinks(request, mblog_data, main_rsm, base_url)) |
285 request.write(self.useTemplate(request, 'header', data)) | |
286 | |
287 BlogMessages(self.host, request, base_url, mblog_data).render() | |
288 | |
289 request.write(self.useTemplate(request, "footer", data)) | |
290 request.finish() | |
291 | |
292 def getNavigationLinks(self, request, mblog_data, rsm_data, base_url): | |
293 """Build the navigation links. | |
294 | |
295 @param mblog_data (dict): the microblogs that are displayed on the page | |
296 @param rsm_data (dict): rsm data | |
297 @param base_url (unicode): the base URL for this user's blog | |
298 @return: dict | |
299 """ | |
300 data = {} | |
301 for key in ('later_message', 'later_messages', 'older_message', 'older_messages'): | |
302 count = int(rsm_data.get('count', 0)) | |
303 display_single = len(mblog_data) == 1 | |
304 data[key] = '' # key must exist when using the template | |
305 if count <= 0 or (display_single == key.endswith('s')): | |
306 continue | |
307 | |
308 index = int(rsm_data['index']) | |
309 | |
310 link_data = {'base_url': base_url, 'suffix': ''} | |
311 | |
312 if key.startswith('later_message'): | |
313 if index <= 0: | |
314 continue | |
315 link_data['item_id'] = rsm_data['first'] | |
316 link_data['post_arg'] = 'before' | |
317 else: | |
318 if index + len(mblog_data) >= count: | |
319 continue | |
320 link_data['item_id'] = rsm_data['last'] | |
321 link_data['post_arg'] = 'after' | |
322 | |
323 if display_single: | |
324 link_data['suffix'] = '&max=1' | |
325 | |
326 link = "%(base_url)s?%(post_arg)s=%(item_id)s%(suffix)s" % link_data | |
327 | |
328 link_data = {'link': link, 'class': key, 'text': key.replace('_', ' ')} | |
329 data[key] = (self.useTemplate(request, 'nav_link', link_data)).encode('utf-8') | |
330 | |
331 return data | |
332 | |
333 def render_atom_feed(self, feed, request): | |
334 request.write(feed.encode('utf-8')) | |
335 request.finish() | |
336 | |
337 def render_error_blog(self, error, request, profile): | |
338 request.write(self.useTemplate(request, "error", {'message': "Can't access requested data"})) | |
339 request.finish() | |
340 | |
341 | |
342 class BlogMessages(TemplateProcessor): | |
343 | |
344 def __init__(self, host, request, base_url, mblog_data): | |
345 TemplateProcessor.__init__(self, host) | |
346 self.request = request | |
347 self.base_url = base_url | |
348 self.mblog_data = mblog_data | |
349 | |
350 def render(self): | |
351 for entry, comments_data in self.mblog_data: | |
320 comments, comments_rsm = comments_data | 352 comments, comments_rsm = comments_data |
321 | |
322 # eventually display the link to show all comments | |
323 comments_count = int(main_data['comments_count']) | |
324 delta = comments_count - len(comments) | |
325 if display_single and delta > 0: | |
326 link = ("%(base)s/%(item_id)s?max=%(max)s" % {'base': base_url, | |
327 'item_id': main_data['id'], | |
328 'max': main_data['comments_count']}).encode('utf-8') | |
329 text = D_("Show %(count)d previous %(comments)s") % {'count': delta, | |
330 'comments': D_('comments') if delta > 1 else D_('comment')} | |
331 request.write("""<a href="%(link)s" class="comments_link">%(text)s</a>""" % {'link': link, 'text': text}) | |
332 | |
333 comments = sorted(comments, key=lambda entry: (float(entry.get('published', 0)))) | 353 comments = sorted(comments, key=lambda entry: (float(entry.get('published', 0)))) |
334 for comment in comments: | 354 self.render_html(entry, comments) |
335 self.__render_html_entry(comment, base_url, request) | 355 |
336 | 356 def getText(self, entry, key): |
337 # display navigation footer | 357 if ('%s_xhtml' % key) in entry: |
338 request.write("""<div class="footer">""") | 358 return entry['%s_xhtml' % key].encode('utf-8') |
339 request.write("""<div class="footer_content">""") | 359 elif key in entry: |
340 if not display_single and after_tag: | 360 processor = addURLToText if key.startswith('content') else sanitizeHtml |
341 request.write(after_tag) | 361 return convertNewLinesToXHTML(processor(entry[key])).encode('utf-8') |
342 request.write("""</div></div>""") | 362 return None |
343 | 363 |
344 request.write('</body></html>') | 364 def render_html(self, entry, comments=None): |
345 request.finish() | |
346 | |
347 def __render_html_entry(self, entry, base_url, request): | |
348 """Render one microblog entry. | 365 """Render one microblog entry. |
349 @param entry: the microblog entry | 366 @param entry: the microblog entry |
350 @param base_url: the base url of the blog | 367 @param base_url: the base url of the blog |
351 @param request: the HTTP request | 368 @param request: the HTTP request |
352 """ | 369 """ |
353 timestamp = float(entry.get('published', 0)) | 370 timestamp = float(entry.get('published', 0)) |
354 datetime_ = datetime.fromtimestamp(timestamp) | |
355 is_comment = entry['type'] == 'comment' | 371 is_comment = entry['type'] == 'comment' |
356 | 372 |
357 def getText(key): | 373 data = {'date': datetime.fromtimestamp(timestamp), |
358 if ('%s_xhtml' % key) in entry: | 374 'comments_link': '', |
359 return entry['%s_xhtml' % key].encode('utf-8') | 375 'previous_comments': '', |
360 elif key in entry: | 376 } |
361 processor = addURLToText if key.startswith('content') else sanitizeHtml | |
362 return convertNewLinesToXHTML(processor(entry[key])).encode('utf-8') | |
363 return '' | |
364 | |
365 def addMainItemLink(elem): | |
366 if not item_link or not elem: | |
367 return elem | |
368 return """<a href="%(link)s" class="item_link">%(elem)s</a>""" % {'link': item_link, 'elem': elem} | |
369 | 377 |
370 if is_comment: | 378 if is_comment: |
371 author = (_("from %s") % entry['author']).encode('utf-8') | 379 author = (_("from %s") % entry['author']).encode('utf-8') |
372 item_link = '' | |
373 footer = '' | |
374 else: | 380 else: |
375 author = ' ' | 381 author = ' ' |
376 item_link = ("%(base)s/%(item_id)s" % {'base': base_url, 'item_id': entry['id']}).encode('utf-8') | 382 message_link = ("%s/%s" % (self.base_url, entry['id'])).encode('utf-8') |
383 | |
384 count_text = lambda count: D_('comments') if count > 1 else D_('comment') | |
385 | |
377 comments_count = int(entry['comments_count']) | 386 comments_count = int(entry['comments_count']) |
378 comments_text = (D_('comments') if comments_count > 1 else D_('comment')).encode('utf-8') | 387 delta = comments_count - len(comments) |
379 footer = addMainItemLink("""<div class="mblog_footer mblog_footer_main"> | 388 if len(self.mblog_data) == 1 and delta > 0: |
380 <div class="mblog_metadata"> | 389 data['comments_link'] = ("%s?max=%s" % (message_link, entry['comments_count'])) |
381 <div class="mblog_comments">%(count)s %(comments)s</div> | 390 data['previous_comments'] = D_("Show %(count)d previous %(comments)s") % \ |
382 </div> | 391 {'count': delta, 'comments': count_text(delta)} |
383 </div>""" % {'count': comments_count, | 392 |
384 'comments': comments_text}) | 393 data.update({'comments_count': comments_count, |
385 | 394 'comments_text': count_text(comments_count), |
386 header = """<div class="mblog_header %(class)s"> | 395 'message_link': message_link, |
387 <div class="mblog_metadata"> | 396 'message_title': self.getText(entry, 'title'), |
388 <div class="mblog_author">%(author)s</div> | 397 }) |
389 <div class="mblog_timestamp">%(date)s</div> | 398 |
390 </div> | 399 data.update({'author': author, |
391 </div>""" % {'author': author, 'date': datetime_, | 400 'extra_style': 'mblog_comment' if entry['type'] == 'comment' else '', |
392 'class': '' if is_comment else 'mblog_header_main'} | 401 'content': self.getText(entry, 'content'), |
393 if not is_comment: | 402 }) |
394 header = addMainItemLink(header) | 403 |
395 | 404 tpl = "%s%s" % ("" if data.get('message_title', None) else "micro_", "comment" if is_comment else "message") |
396 title = addMainItemLink(getText('title')) | 405 self.request.write(self.useTemplate(self.request, tpl, data)) |
397 body = getText('content') | 406 |
398 if title: # insert the title within the body | 407 if comments: |
399 body = """<h1>%(title)s</h1>\n%(body)s""" % {'title': title, 'body': body} | 408 for comment in comments: |
400 | 409 self.render_html(comment) |
401 request.write("""<div class="mblog_entry %(extra_style)s"> | 410 |
402 %(header)s | |
403 <span class="mblog_content">%(content)s</span> | |
404 %(footer)s | |
405 </div>""" % {'extra_style': 'mblog_comment' if entry['type'] == 'comment' else '', | |
406 'item_link': item_link, | |
407 'header': header, | |
408 'content': body, | |
409 'footer': footer}) | |
410 | |
411 def render_atom_feed(self, feed, request): | |
412 request.write(feed.encode('utf-8')) | |
413 request.finish() | |
414 | |
415 def render_error_blog(self, error, request, profile): | |
416 request.write(MicroBlog.ERROR_TEMPLATE % {'root': '../' * len(request.postpath), | |
417 'message': "Can't access requested data"}) | |
418 request.finish() |