-
sylvain thenault authoredsylvain thenault authored
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)