diff src/server/blog.py @ 586:3eb3a2c0c011

browser and server side: uses RSM (XEP-0059)
author souliane <souliane@mailoo.org>
date Fri, 28 Nov 2014 00:31:27 +0100
parents e588335b6aa8
children c8cca1a373dd
line wrap: on
line diff
--- a/src/server/blog.py	Thu Oct 23 16:56:36 2014 +0200
+++ b/src/server/blog.py	Fri Nov 28 00:31:27 2014 +0100
@@ -17,7 +17,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from sat.core.i18n import _
+from sat.core.i18n import _, D_
 from sat_frontends.tools.strings import addURLToText
 from sat.core.log import getLogger
 log = getLogger(__name__)
@@ -130,25 +130,52 @@
                     pub_jid = JID(pub_jid_s)
                     d2 = defer.Deferred()
                     item_id = None
-                    try:
-                        max_items = int(request.args['max_items'][0])
-                    except (ValueError, KeyError):
-                        max_items = 10
+                    atom = None
+                    rsm_ = {}
+
                     if len(request.postpath) > 1:
                         if request.postpath[1] == 'atom.xml':  # return the atom feed
-                            d2.addCallbacks(self.render_atom_feed, self.render_error_blog, [request], None, [request, prof_found], None)
-                            self.host.bridge.getLastGroupBlogsAtom(pub_jid.userhost(), max_items, C.SERVICE_PROFILE, d2.callback, d2.errback)
-                            return
-                        try:  # check if the given path is a valid UUID
-                            uuid.UUID(request.postpath[1])
-                            item_id = request.postpath[1]
-                        except ValueError:
-                            pass
+                            atom = True
+                        else:
+                            try:  # check if the given path is a valid UUID
+                                uuid.UUID(request.postpath[1])
+                                item_id = request.postpath[1]
+                            except ValueError:
+                                pass
+
+                    # retrieve RSM request data from URL parameters
+                    try:
+                        max_items = int(request.args['max'][0])
+                    except (ValueError, KeyError):
+                        max_items = C.RSM_MAX_ITEMS if item_id else C.RSM_MAX_COMMENTS
+                    rsm_['max'] = unicode(max_items)
+                    try:
+                        rsm_['index'] = request.args['index'][0]
+                    except (ValueError, KeyError):
+                        try:
+                            rsm_['before'] = request.args['before'][0]
+                        except KeyError:
+                            try:
+                                rsm_['after'] = request.args['after'][0]
+                            except KeyError:
+                                pass
+
+                    if atom is not None:
+                        d2.addCallbacks(self.render_atom_feed, self.render_error_blog, [request], None, [request, prof_found], None)
+                        self.host.bridge.getGroupBlogsAtom(pub_jid.userhost(), rsm_, C.SERVICE_PROFILE, d2.callback, d2.errback)
+                        return
+
                     d2.addCallbacks(self.render_html_blog, self.render_error_blog, [request, prof_found], None, [request, prof_found], None)
-                    if item_id:  # display one message and its comments
-                        self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [item_id], C.SERVICE_PROFILE, d2.callback, d2.errback)
-                    else:  # display the last messages without comment
-                        self.host.bridge.getLastGroupBlogs(pub_jid.userhost(), max_items, C.SERVICE_PROFILE, d2.callback, d2.errback)
+                    if item_id:
+                        if max_items > 0:  # display one message and its comments
+                            self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [item_id], {}, max_items, C.SERVICE_PROFILE, d2.callback, d2.errback)
+                        else:  # display one message, count its comments
+                            self.host.bridge.getGroupBlogs(pub_jid.userhost(), [item_id], {}, True, C.SERVICE_PROFILE, d2.callback, d2.errback)
+                    else:
+                        if max_items == 1:  # display one message and its comments
+                            self.host.bridge.getGroupBlogsWithComments(pub_jid.userhost(), [], rsm_, C.RSM_MAX_COMMENTS, C.SERVICE_PROFILE, d2.callback, d2.errback)
+                        else:  # display the last messages, count their comments
+                            self.host.bridge.getGroupBlogs(pub_jid.userhost(), [], rsm_, True, C.SERVICE_PROFILE, d2.callback, d2.errback)
 
                 d1 = defer.Deferred()
                 JID(self.host.bridge.asyncGetParamA('JabberID', 'Connection', 'value', C.SERVER_SECURITY_LIMIT, prof_found, callback=d1.callback, errback=d1.errback))
@@ -158,7 +185,12 @@
 
     def render_html_blog(self, mblog_data, request, profile):
         """Retrieve the user parameters before actually rendering the static blog
-        @param mblog_data: list of microblog data or list of couple (microblog data, list of microblog data)
+
+        @param mblog_data (list): couple (list, dict) with:
+            - a list of microblog data, or a list of couple containing:
+                - microblog data (main item)
+                - couple (comments data, RSM response data for the comments)
+            - RSM response data for the main items
         @param request: HTTP request
         @param profile
         """
@@ -184,7 +216,12 @@
         """Actually render the static blog. If mblog_data is a list of dict, we are missing
         the comments items so we just display the main items. If mblog_data is a list of couple,
         each couple is associating a main item data with the list of its comments, so we render all.
-        @param mblog_data: list of microblog data or list of couple (microblog data, list of microblog data)
+
+        @param mblog_data (list): couple (list, dict) with:
+            - a list of microblog data, or a list of couple containing:
+                - microblog data (main item)
+                - couple (comments data, RSM response data for the comments)
+            - RSM response data for the main items
         @param options: dict defining the blog's parameters
         @param request: the HTTP request
         @profile
@@ -225,13 +262,74 @@
                    'title': getOption(C.STATIC_BLOG_PARAM_TITLE) or "%s's microblog" % user,
                    'favicon': os.path.normpath(root_url + getOption('avatar')),
                    'banner_elt': getImageOption(C.STATIC_BLOG_PARAM_BANNER, getOption(C.STATIC_BLOG_PARAM_TITLE) or user)})
-        mblog_data = [(entry if isinstance(entry, tuple) else (entry, [])) for entry in mblog_data]
-        mblog_data = sorted(mblog_data, key=lambda entry: (-float(entry[0].get('published', 0))))
-        for entry in mblog_data:
-            self.__render_html_entry(entry[0], base_url, request)
-            comments = sorted(entry[1], key=lambda entry: (float(entry.get('published', 0))))
+        mblog_data, main_rsm = mblog_data
+        display_single = len(mblog_data) == 1
+
+        # build the navigation links
+        count = int(main_rsm['count']) if 'count' in main_rsm else 0
+        if count > 0:
+            index = int(main_rsm['index'])
+            if index > 0:
+                before_link = ("%(base)s?before=%(item_id)s" % {'base': base_url, 'item_id': main_rsm['first']}).encode('utf-8')
+                if display_single:
+                    before_link += '&max=1'
+                    tmp_text = D_("Later message")
+                    class_ = 'later_message'
+                else:
+                    tmp_text = D_("Later messages")
+                    class_ = 'later_messages'
+                before_tag = """<a href="%(link)s" class="%(class)s">%(text)s</a>""" % {'link': before_link, 'class': class_, 'text': tmp_text}
+            else:
+                before_tag = None
+            if index + len(mblog_data) < count:
+                after_link = ("%(base)s?after=%(item_id)s" % {'base': base_url, 'item_id': main_rsm['last']}).encode('utf-8')
+                if display_single:
+                    after_link += '&max=1'
+                    text = D_("Older message")
+                    class_ = 'older_message'
+                else:
+                    text = D_("Older messages")
+                    class_ = 'older_messages'
+                after_tag = """<a href="%(link)s" class="%(class)s">%(text)s</a>""" % {'link': after_link, 'class': class_, 'text': text}
+            else:
+                after_tag = None
+
+        # display navigation header
+        request.write("""<div class="header">""")
+        if before_tag:
+            request.write(before_tag)
+        request.write("&nbsp;")
+        if display_single and after_tag:
+            request.write(after_tag)
+        request.write("""</div>""")
+
+        mblog_data = [(entry if isinstance(entry, tuple) else (entry, ([], {}))) for entry in mblog_data]
+        mblog_data = sorted(mblog_data, key=lambda entry: (-float(entry[0].get('updated', 0))))
+        for main_data, comments_data in mblog_data:
+            self.__render_html_entry(main_data, base_url, request)
+            comments, comments_rsm = comments_data
+
+            # eventually display the link to show all comments
+            comments_count = int(main_data['comments_count'])
+            delta = comments_count - len(comments)
+            if display_single and delta > 0:
+                link = ("%(base)s/%(item_id)s?max=%(max)s" % {'base': base_url,
+                                                              'item_id': main_data['id'],
+                                                              'max': main_data['comments_count']}).encode('utf-8')
+                text = D_("Show %(count)d previous %(comments)s") % {'count': delta,
+                                                                    'comments': D_('comments') if delta > 1 else D_('comment')}
+                request.write("""<a href="%(link)s" class="comments_link">%(text)s</a>""" % {'link': link, 'text': text})
+
+            comments = sorted(comments, key=lambda entry: (float(entry.get('published', 0))))
             for comment in comments:
                 self.__render_html_entry(comment, base_url, request)
+
+        # display navigation footer
+        request.write("""<div class="footer">""")
+        if not display_single and after_tag:
+            request.write(after_tag)
+        request.write("""</div>""")
+
         request.write('</body></html>')
         request.finish()
 
@@ -244,12 +342,6 @@
         timestamp = float(entry.get('published', 0))
         datetime_ = datetime.fromtimestamp(timestamp)
         is_comment = entry['type'] == 'comment'
-        if is_comment:
-            author = (_("comment from %s") % entry['author']).encode('utf-8')
-            item_link = ''
-        else:
-            author = '&nbsp;'
-            item_link = ("%(base)s/%(item_id)s" % {'base': base_url, 'item_id': entry['id']}).encode('utf-8')
 
         def getText(key):
             if ('%s_xhtml' % key) in entry:
@@ -264,12 +356,31 @@
                 return elem
             return """<a href="%(link)s" class="item_link">%(elem)s</a>""" % {'link': item_link, 'elem': elem}
 
-        header = addMainItemLink("""<div class="mblog_header">
-                                      <div class="mblog_metadata">
-                                        <div class="mblog_author">%(author)s</div>
-                                        <div class="mblog_timestamp">%(date)s</div>
-                                      </div>
-                                    </div>""" % {'author': author, 'date': datetime_})
+        if is_comment:
+            author = (_("from %s") % entry['author']).encode('utf-8')
+            item_link = ''
+            footer = ''
+        else:
+            author = '&nbsp;'
+            item_link = ("%(base)s/%(item_id)s" % {'base': base_url, 'item_id': entry['id']}).encode('utf-8')
+            comments_count = int(entry['comments_count'])
+            comments_text = (D_('comments') if comments_count > 1 else D_('comment')).encode('utf-8')
+            footer = addMainItemLink("""<div class="mblog_footer mblog_footer_main">
+                                          <div class="mblog_metadata">
+                                            <div class="mblog_comments">%(count)s %(comments)s</div>
+                                          </div>
+                                        </div>""" % {'count': comments_count,
+                                                     'comments': comments_text})
+
+        header = """<div class="mblog_header %(class)s">
+                      <div class="mblog_metadata">
+                        <div class="mblog_author">%(author)s</div>
+                        <div class="mblog_timestamp">%(date)s</div>
+                      </div>
+                    </div>""" % {'author': author, 'date': datetime_,
+                                 'class': '' if is_comment else 'mblog_header_main'}
+        if not is_comment:
+            header = addMainItemLink(header)
 
         title = addMainItemLink(getText('title'))
         body = getText('content')
@@ -279,11 +390,12 @@
         request.write("""<div class="mblog_entry %(extra_style)s">
                            %(header)s
                            <span class="mblog_content">%(content)s</span>
-                         </div>""" %
-                         {'extra_style': 'mblog_comment' if entry['type'] == 'comment' else '',
-                          'item_link': item_link,
-                          'header': header,
-                          'content': body})
+                           %(footer)s
+                         </div>""" % {'extra_style': 'mblog_comment' if entry['type'] == 'comment' else '',
+                                      'item_link': item_link,
+                                      'header': header,
+                                      'content': body,
+                                      'footer': footer})
 
     def render_atom_feed(self, feed, request):
         request.write(feed.encode('utf-8'))