Skip to content
Snippets Groups Projects
views.py 13.38 KiB
"""Specific views for blogs

:organization: Logilab
:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"

from mx.DateTime import DateTime
from logilab.mtconverter import html_escape

from cubicweb import Unauthorized
from cubicweb.common.uilib import text_cut, safe_cut
from cubicweb.common.uilib import rql_for_eid
from cubicweb.common.view import EntityView, StartupView
from cubicweb.common.utils import UStringIO
from cubicweb.common.selectors import (paginated_rset, sorted_rset,
                                       accept, implement_interface)
from cubicweb.web.views import baseviews
from cubicweb.web.views.boxes import BoxTemplate, BoxHtml
from cubicweb.web.views.calendar import MONTHNAMES
from cubicweb.web.views.navigation import PageNavigation
from cubicweb.web.htmlwidgets import BoxLink, BoxWidget
from cubicweb.interfaces import IFeed, ISIOC


class SIOCView(EntityView):
    id = 'sioc'
    title = _('sioc')
    accepts = ('Blog', 'BlogEntry')
    templatable = False
    __selectors__ = (implement_interface,)
    accepts_interfaces = (ISIOC,)
    content_type = 'text/xml'
    item_vid = 'sioc_item'
    
    def call(self):
        self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
        self.w(u'''<rdf:RDF
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
             xmlns:owl="http://www.w3.org/2002/07/owl#"
             xmlns:foaf="http://xmlns.com/foaf/0.1/"
             xmlns:sioc="http://rdfs.org/sioc/ns#"
             xmlns:sioctype="http://rdfs.org/sioc/types#"
             xmlns:dcterms="http://purl.org/dc/terms/">\n''')        
        for i in xrange(self.rset.rowcount):
            self.cell_call(row=i, col=0)
        self.w(u'</rdf:RDF>\n')
            
    def cell_call(self, row, col):
        self.wview(self.item_vid, self.rset, row=row, col=col)

class SIOCBlogItemView(EntityView):
    id = 'sioc_item'
    accepts = ('Blog',)
    templatable = False
    content_type = 'text/xml'
   
    def cell_call(self, row, col):
        entity = self.complete_entity(row, col)
        self.w(u' <sioc:Weblog rdf:about="%s">\n' % html_escape(entity.absolute_url()))
        self.render_title_date(entity)
        self.w(u'</sioc:Weblog>\n')

    def render_title_date(self, entity):
        self.w(u'<dcterms:title>%s</dcterms:title>'% html_escape(unicode(entity.title)))
        self.w(u'<dcterms:created>%s</dcterms:created>'% entity.creation_date)
        self.w(u'<dcterms:modified>%s</dcterms:modified>' % entity.modification_date)
                  
class SIOCItemView(SIOCBlogItemView):
    accepts = ('BlogEntry',)
 
    def cell_call(self, row, col):
        entity = self.complete_entity(row, col)
        self.w(u' <sioc:Post rdf:about="%s">\n' % html_escape(entity.absolute_url()))
        self.render_title_date(entity)
        if entity.content:
            self.w(u'<sioc:content>%s</sioc:content>''' % html_escape(entity.content))        
        if entity.related('entry_of'):
            rset = entity.related('entry_of')
            entity = rset.get_entity(0, 0)                  
            self.w(u'<sioc:has_contenainer rdf:resource="%s"/>\n' % html_escape(entity.absolute_url()))
        if entity.creator:
            rql = ('Any E WHERE E eid %s'% entity.creator.eid)
            rset = self.req.execute(rql)
            euser = rset.get_entity(0,0)
            self.w(u'<sioc:has_creator>\n')
            self.w(u'<sioc:User rdf:about="%s">\n' % euser.absolute_url())
            self.wview('foaf_usable', rset)
            self.w(u'</sioc:User>\n')
            self.w(u'</sioc:has_creator>\n')
        self.w(u' </sioc:Post>\n')    
   
class BlogPrimaryView(baseviews.PrimaryView):
    accepts = ('Blog',)
    skip_attrs = baseviews.PrimaryView.skip_attrs + ('title',)

    def render_entity_title(self, entity):
        self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title()))

    def render_entity_relations(self, entity, siderelations):
        rset = entity.related('entry_of', 'object')
        strio = UStringIO()
        self.pagination(self.req, rset, strio.write, page_size=10)
        self.wview('list', rset, 'null', title='')
        self.w(strio.getvalue())

    def render_entity_attributes(self, entity, siderelations):
        self.w('<a class="right" href="%s"> <img src="%s" alt="%s"/></a>' % (
            html_escape(entity.rss_feed_url()), self.req._(u'subscribe'),
            self.req.external_resource('RSS_LOGO_16'), self.req._('rss icon')))

class BlogEntryPrimaryView(baseviews.PrimaryView):
    accepts = ('BlogEntry',)
    skip_attrs = baseviews.PrimaryView.skip_attrs + ('title',)
    show_attr_label = False

    def render_entity_title(self, entity):
        self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title()))

    def content_format(self, entity):
        return entity.view('reledit', rtype='content_format')

    def render_entity_relations(self, entity, siderelations):
        rset = entity.related('entry_of', 'subject')
        if rset:
            _ = self.req._
            self.w(_('blogged in '))
            self.wview('secondary', rset, 'null')

class BlogEntryArchiveView(StartupView):
    """control the view of a blog archive"""
    id = 'blog_archive'
    countrql = 'Any COUNT(B) WHERE B is BlogEntry, B creation_date >=  %(firstday)s, B creation_date <= %(lastday)s'

    def represent(self, items, year, month):
        """represent a single month entry"""
        firstday = DateTime(year, month, 1)
        lastday = DateTime(year, month, firstday.days_in_month)
        rql = ('Any B WHERE B is BlogEntry, B creation_date >=  "%s", B creation_date <= "%s"' %
                (firstday.strftime('%Y-%m-%d'), lastday.strftime('%Y-%m-%d')))
        args = {'firstday':firstday, 'lastday':lastday}
        nmb_entries = self.req.execute(self.countrql, args)[0][0]
        label = u'%s %s [%s]' % (_(MONTHNAMES[month-1]), year, nmb_entries)
        vtitle = '%s %s' % (_('BlogEntry_plural'), label)
        url = html_escape(self.build_url(rql=rql, vtitle=vtitle, vid='list'))
        link = u'<a href="%s" title="">%s</a>' % (url, label)
        items.append( u'<li class="">%s</li>\n' % link )

    def call(self, maxentries=None, **kwargs):
        """display a list of entities by calling their <item_vid> view
        """
        rset = self.req.execute('Any CD ORDERBY CD DESC WHERE B is BlogEntry, B creation_date CD')
        blogmonths = []
        items = []
        for (blogdate,) in rset:
            year, month = blogdate.year, blogdate.month
            if (year, month) not in blogmonths:
                blogmonths.append( (year, month) )
        if maxentries is None:
            displayed_months = blogmonths
            needmore = False
        else:
            needmore = len(blogmonths) > maxentries
            displayed_months = blogmonths[:maxentries]
        for year, month in displayed_months:
            self.represent(items, year, month)
        if needmore:
            url = html_escape(u"/?vid=blog_archive")
            link = u'<a href="%s" title="">[see more archives]</a>' % url
            items.append( u'<li class="">%s</li>\n' % link )
        if self.id:
            self.w(u'<div class="boxFrame" id="%s">' % self.id)
        else:
            self.w(u'<div class="boxFrame">')

        if items:
            self.w(u'<div class="boxContent">\n')
            self.w(u'<ul class="boxListing">')
            self.w(''.join(items))
            self.w(u'</ul>\n</div>\n')
        self.w(u'</div>')


class BlogEntryArchiveBox(BoxTemplate):
    """blog side box displaying a Blog Archive"""
    id = 'blog_archives_box'
    title = _('boxes_blog_archives_box')
    order = 35

    def call(self, **kwargs):
        """display blog archive
        """
        _ = self.req._
        box = BoxWidget(_(self.title), id=self.id, islist=False)
        box.append(BoxHtml(self.view('blog_archive', None, maxentries=12)))
        box.render(self.w)

class BlogEntryListBox(BoxTemplate):
    """display a box with latest blogs and rss"""
    id = 'blog_latest_box'
    title = _('blog_latest_box')
    __selectors__ = BoxTemplate.__selectors__
    visible = True # enabled by default
    order = 34

    def call(self, view=None, **kwargs):
        box = BoxWidget(self.req._(self.title), self.id, islist=True)
        rset = self.req.execute('Any X,T,CD ORDERBY CD DESC LIMIT 5 '
                                'WHERE X is BlogEntry, X title T, '
                                'X creation_date CD')
        if not rset:
            return
        # TODO - get the date between brakets after link
        # empty string for title argument to deactivate auto-title
        for i in xrange(rset.rowcount):
            entity = rset.get_entity(i, 0)
            box.append(BoxLink(entity.absolute_url(), html_escape(entity.dc_title())))
        rqlst = rset.syntax_tree()
        rqlst.set_limit(None)
        rql = rqlst.as_string(kwargs=rset.args) # en gros...
        url = self.build_url(vid='boxListing', rql=rql, page_size=10)
        box.append(BoxLink(url,  u'[%s]' % self.req._(u'see more')))
        rss_icon = self.req.external_resource('RSS_LOGO_16')
        # FIXME - could use rss_url defined as a property if available
        rss_label = u'%s <img src="%s" alt="%s"/>' % (
                           self.req._(u'subscribe'), rss_icon, self.req._('rss icon'))
        rss_url = self.build_url(vid='rss', rql=rql)
        box.append(BoxLink(rss_url, html_escape(rss_label)))
        box.render(self.w)      


class OneLineView(EntityView):
    accepts = ('BlogEntry',)
    id = 'sideboxview'

    def cell_call(self, row, col):
        """the view to be used in a side box
        """
        entity = self.entity(row, col)
        self.w(u'<li class="Box"><a href="%s">' % html_escape(entity.absolute_url()))
        self.w(html_escape(self.view('text', self.rset, row=row, col=col)))
        self.w(u'</a></li>')

## list views #################################################################

class BlogEntryListView(baseviews.ListView):
    accepts = ('BlogEntry',)
    
    def call(self, klass=None, title=None, **kwargs):
        """display a list of entities by calling their <item_vid> view
        """
        entity = self.entity(0,0)
        self.req.add_css('cubes.blog.css')
        # XXX: no title if subvid specified to try to avoid cases where we want
        # the original list view...
        if title is None and not ('vtitle' in self.req.form or 'subvid' in kwargs):
            self.w(u'<h1>%s</h1>' % display_name(self.req, 'BlogEntry', form='plural'))
        super(BlogEntryListView, self).call(klass='invisible', **kwargs)
         

class BlogEntryListItemView(baseviews.ListItemView):
    accepts = ('BlogEntry',)
    redirect_vid = 'blog'

    
class BlogEntryBlogView(baseviews.ListItemView):
    id = 'blog'
    accepts = ('BlogEntry',)
    def cell_call(self, row, col):
        entity = self.entity(row, col)
        w = self.w
        _ = self.req._
        w(u'<div class="post">')
        w(u'<h1>%s</h1>' % entity.view('incontext'))
        w(u'%s ' % entity.postinfo_description())
        creator = entity.creator
        if creator:
            vtitle = _('blog entries created by %s %s') % (creator.firstname,
                                                           creator.surname)
            rql = 'Any X ORDERBY D DESC WHERE X is BlogEntry, X created_by Y, '\
                  'Y eid %s, X creation_date D' % creator.eid
            url = self.build_url('view', vid="list", rql=rql, vtitle=vtitle,
                                 page_size = 10)
            w(u'%s <a href="%s">%s %s</a>' % (_('by'), html_escape(url),
                                              creator.firstname,
                                              creator.surname))

        w(u'<div class="entry">')
        body = entity.printable_value('content')
        w(body)
        w(u'</div>')
        w(u'<p class="postmetadata">%s</p>' % entity.view('post-reldata'))
        w(u'</div>')


class BlogEntryPostMetaData(EntityView):
    id = 'post-reldata'
    accepts = ('BlogEntry',)

    def cell_call(self, row, col):
        entity = self.entity(row, col)
        _ = lambda ertype, form='': display_name(self.req, ertype, form)
        reldata = []
        w = reldata.append
        if 'comments' in self.schema and 'BlogEntry' in self.schema.rschema('comments').objects():
            count = self.req.execute('Any COUNT(C) WHERE C comments B, B eid %(x)s',
                                     {'x': entity.eid}, 'x')[0][0]
            if count:
                url = html_escape(entity.absolute_url())
                w(u'<a href="%s">%s %s</a>' % (url, count, _('Comment', 'plural')))
            else:
                w(u'%s %s' % (count, _('Comment')))
        if 'tags' in self.schema and 'BlogEntry' in self.schema.rschema('tags').objects():
            tag_rset = entity.related('tags', 'object')
            if tag_rset:
                w(u'%s %s' % (_('tags', 'object'), self.view('csv', tag_rset)))
        rset = entity.related('entry_of', 'subject')
        if rset:
            w(u'%s %s' % (self.req._('blogged in '),
                          self.view('secondary', rset, 'null')))
        self.w(u' | '.join(reldata))

class BlogNavigation(PageNavigation):
    accepts = ('BlogEntry', )
    __selectors__ = (paginated_rset, sorted_rset, accept)

    def index_display(self, start, stop):
        return u'%s' % (int(start / self.page_size)+1)