def generate_rsd(app): """Generate the RSD definition for this application apis.""" from zine.application import url_for document = __import__('xml.dom.minidom', None, None, ['']).Document() root = document.appendChild(document.createElement('rsd')) root.setAttribute('version', '1.0') root.setAttribute('xmlns', 'http://archipelago.phrasewise.com/rsd') service = root.appendChild(document.createElement('service')) attributes = [('engineName', 'Zine'), ('engineLink', 'http://zine.pocoo.org/'), ('homePageLink', url_for('blog/index', _external=True))] for attr, value in attributes: service.appendChild(document.createElement(attr)) \ .appendChild(document.createTextNode(value)) apis = service.appendChild(document.createElement('apis')) for name, (blog_id, preferred, endpoint) in app.apis.iteritems(): element = apis.appendChild(document.createElement('api')) element.setAttribute('name', name) element.setAttribute('blogID', str(blog_id)) element.setAttribute('preferred', preferred and 'true' or 'false') element.setAttribute('apiLink', url_for(endpoint, _external=True)) return document.toxml('utf-8')
def show_category(req, slug, page=1): """Show all posts categoryged with a given category slug. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination `category` the category object for this page. :Template name: ``show_category.html`` :URL endpoint: ``blog/show_category`` """ category = Category.query.filter_by(slug=slug).first(True) per_page = req.app.theme.settings['category.per_page'] data = category.posts.theme_lightweight('category') \ .published().get_list(page=page, per_page=per_page, endpoint='blog/show_category', url_args=dict(slug=slug)) add_link('alternate', url_for('blog/atom_feed', category=slug), 'application/atom+xml', _(u'All posts in category %s') % category.name) return render_response('show_category.html', category=category, **data)
def show_author(req, username, page=1): """Show the user profile of an author / editor or administrator. Available template variables: `posts`: a list of post objects this author wrote and are visible on this page. `pagination`: a pagination object to render a pagination `user` The user object for this author :Template name: ``show_author.html`` :URL endpoint: ``blog/show_author`` """ user = User.query.filter_by(username=username).first() if user is None or not user.is_author: raise NotFound() per_page = req.app.theme.settings['author.per_page'] data = user.posts.theme_lightweight('author').published() \ .get_list(page=page, per_page=per_page, endpoint='blog/show_author', url_args=dict(username=user.username)) add_link('alternate', url_for('blog/atom_feed', author=user.username), 'application/atom+xml', _(u'All posts written by %s') % user.display_name) return render_response('show_author.html', user=user, **data)
def show_category(req, slug, page=1): """Show all posts categoryged with a given category slug. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination `category` the category object for this page :Template name: ``show_category.html`` :URL endpoint: ``blog/show_category`` """ category = Category.query.filter_by(slug=slug).first(True) per_page = req.app.theme.settings['category.per_page'] data = category.posts.theme_lightweight('category') \ .published().get_list(page=page, per_page=per_page, endpoint='blog/show_category', url_args=dict(slug=slug)) add_link('alternate', url_for('blog/atom_feed', category=slug), 'application/atom+xml', _(u'All posts in category %s') % category.name) return render_response('show_category.html', category=category, **data)
def archive(req, year=None, month=None, day=None, page=1): """Render the monthly archives. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination `year` / `month` / `day`: integers or None, useful to entitle the page :Template name: ``archive.html`` :URL endpoint: ``blog/archive`` """ if not year: return render_response('archive.html', month_list=True, **Post.query.published().for_index() .get_archive_summary()) url_args = dict(year=year, month=month, day=day) per_page = req.app.theme.settings['archive.per_page'] data = Post.query.theme_lightweight('archive_overview') \ .published().for_index().date_filter(year, month, day) \ .get_list(page=page, endpoint='blog/archive', url_args=url_args, per_page=per_page) add_link('alternate', url_for('blog/atom_feed', **url_args), 'application/atom+xml', _(u'Recent Posts Feed')) return render_response('archive.html', year=year, month=month, day=day, date=date(year, month or 1, day or 1), month_list=False, **data)
def show_author(req, username, page=1): """Show the user profile of an author / editor or administrator. Available template variables: `posts`: a list of post objects this author wrote and are visible on this page `pagination`: a pagination object to render a pagination `user` the user object for this author :Template name: ``show_author.html`` :URL endpoint: ``blog/show_author`` """ user = User.query.filter_by(username=username).first() if user is None or not user.is_author: raise NotFound() per_page = req.app.theme.settings['author.per_page'] data = user.posts.theme_lightweight('author').published() \ .get_list(page=page, per_page=per_page, endpoint='blog/show_author', url_args=dict(username=user.username)) add_link('alternate', url_for('blog/atom_feed', author=user.username), 'application/atom+xml', _(u'All posts written by %s') % user.display_name) return render_response('show_author.html', user=user, **data)
def show_tag(req, slug, page=1): """Show all posts categoryged with a given tag slug. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination `tag` the tag object for this page :Template name: ``show_tag.html`` :URL endpoint: ``blog/show_tag`` """ tag = Tag.query.filter_by(slug=slug).first(True) per_page = req.app.theme.settings['tag.per_page'] data = tag.posts.theme_lightweight('tag') \ .published().get_list(page=page, endpoint='blog/show_tag', per_page=per_page, url_args=dict(slug=slug)) add_link('alternate', url_for('blog/atom_feed', tag=slug), 'application/atom+xml', _(u'All posts tagged %s') % tag.name) return render_response('show_tag.html', tag=tag, **data)
def archive(req, year=None, month=None, day=None, page=1): """Render the monthly archives. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination `year` / `month` / `day`: integers or None, useful to entitle the page. :Template name: ``archive.html`` :URL endpoint: ``blog/archive`` """ if not year: return render_response('archive.html', month_list=True, **Post.query.published().for_index() .get_archive_summary()) url_args = dict(year=year, month=month, day=day) per_page = req.app.theme.settings['archive.per_page'] data = Post.query.theme_lightweight('archive_overview') \ .published().for_index().date_filter(year, month, day) \ .get_list(page=page, endpoint='blog/archive', url_args=url_args, per_page=per_page) add_link('alternate', url_for('blog/atom_feed', **url_args), 'application/atom+xml', _(u'Recent Posts Feed')) return render_response('archive.html', year=year, month=month, day=day, date=date(year, month or 1, day or 1), month_list=False, **data)
def redirect_back(*args, **kwargs): """Redirect back to the page we are comming from or the URL rule given. """ target = get_redirect_target() if target is None: target = url_for(*args, **kwargs) # call werkzeug's redirect directly and not the redirect() function # from this module because it will strip leading slashes this function # returns and thus generate wrong redirects. return _redirect(target)
def list_documented_plugins(app): """Return a list of all documented plugins.""" plugins = [] for plugin in app.plugins.itervalues(): if plugin.is_documented: plugins.append( '<li><a href="%s">%s</a></li>' % (url_for('admin/help', page='plugins/%s/' % plugin.name), escape(plugin.display_name))) if not plugins: return u'<ul><li>%s</li></ul>' % _('no documented plugins installed.') return '<ul>%s</ul>' % '\n'.join(plugins)
def list_documented_plugins(app): """Return a list of all documented plugins.""" plugins = [] for plugin in app.plugins.itervalues(): if plugin.is_documented: plugins.append('<li><a href="%s">%s</a></li>' % ( url_for('admin/help', page='plugins/%s/' % plugin.name), escape(plugin.display_name) )) if not plugins: return u'<ul><li>%s</li></ul>' % _('no documented plugins installed.') return '<ul>%s</ul>' % '\n'.join(plugins)
def find_urls(self): """Iterate over all urls in the text. This will only work if the parser for this post is available, otherwise an exception is raised. The URLs returned are absolute URLs. """ from zine.parsers import parse if self.parser_missing: raise TypeError('parser is missing, urls cannot be looked up.') found = set() this_url = url_for(self, _external=True) tree = parse(self.text, self.parser, 'linksearch') for node in tree.query('a[href]'): href = urljoin(this_url, node.attributes['href']) if href not in found: found.add(href) yield href
def render_query_table(queries): """Renders a nice table of all queries in the page.""" total = 0 stylesheet = url_for('core/shared', filename='debug.css') result = [ u'<style type="text/css">@import url(%s)</style>' % stylesheet, u'<div class="_database_debug_table"><ul>' ] for statement, parameters, start, end, calling_context in queries: total += (end - start) result.append(u'<li><pre>%s</pre><div class="detail"><em>%s</em> | ' u'<strong>took %.3f ms</strong></div></li>' % (statement, escape(calling_context), (end - start) * 1000)) result.append(u'<li><strong>%d queries in %.2f ms</strong></ul></div>' % (len(queries), total * 1000)) return u'\n'.join(result)
def render_query_table(queries): """Renders a nice table of all queries in the page.""" total = 0 stylesheet = url_for('core/shared', filename='debug.css') result = [u'<style type="text/css">@import url(%s)</style>' % stylesheet, u'<div class="_database_debug_table"><ul>'] for statement, parameters, start, end, calling_context in queries: total += (end - start) result.append(u'<li><pre>%s</pre><div class="detail"><em>%s</em> | ' u'<strong>took %.3f ms</strong></div></li>' % ( statement, escape(calling_context), (end - start) * 1000 )) result.append(u'<li><strong>%d queries in %.2f ms</strong></ul></div>' % ( len(queries), total * 1000 )) return u'\n'.join(result)
def index(req, page=1): """Render the most recent posts. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination :Template name: ``index.html`` :URL endpoint: ``blog/index`` """ data = Post.query.published().for_index().get_list(endpoint='blog/index', page=page) add_link('alternate', url_for('blog/atom_feed'), 'application/atom+xml', _(u'Recent Posts Feed')) return render_response('index.html', **data)
def index(req, page=1): """Render the most recent posts. Available template variables: `posts`: a list of post objects we want to display `pagination`: a pagination object to render a pagination :Template name: ``index.html`` :URL endpoint: ``blog/index`` """ data = Post.query.theme_lightweight('index').published() \ .for_index().get_list(endpoint='blog/index', page=page) add_link('alternate', url_for('blog/atom_feed'), 'application/atom+xml', _(u'Recent Posts Feed')) return render_response('index.html', **data)
def get_url_values(self): return url_for(self.post) + '#comment-%d' % self.id
def redirect_to(*args, **kwargs): """Temporarily redirect to an URL rule.""" # call werkzeug's redirect directly and not the redirect() function # from this module because it will strip leading slashes this function # returns and thus generate wrong redirects. return _redirect(url_for(*args, **kwargs))
def populate_feed(req, feed, author=None, year=None, month=None, day=None, category=None, tag=None, post=None): """Renders an atom feed requested. :URL endpoint: ``blog/atom_feed`` """ # the feed only contains published items query = Post.query.lightweight(lazy=('comments',)).published() # feed for a category if category is not None: category = Category.query.filter_by(slug=category).first(True) query = query.filter(Post.categories.contains(category)) # feed for a tag if tag is not None: tag = Tag.query.filter_by(slug=tag).first(True) query = query.filter(Post.tags.contains(tag)) # feed for an author if author is not None: author = User.query.filter_by(username=author).first(True) query = query.filter(Post.author == author) # feed for dates if year is not None: query = query.for_index().date_filter(year, month, day) # if no post slug is given we filter the posts by the cretereons # provided and pass them to the feed builder. This will only return # a feed for posts with a content type listed in `index_content_types` if post is None: for post in query.for_index().order_by(Post.pub_date.desc()) \ .limit(15).all(): alt_title = '%s @ %s' % (post.author.display_name, post.pub_date) feed.add_item(post.title or alt_title, url_for(post, _external=True), unicode(post.body), author_name=post.author.display_name, pubdate=post.pub_date, unique_id=post.uid) # otherwise we create a feed for all the comments of a post. # the function is called this way by `dispatch_content_type`. else: comment_num = 1 for comment in post.comments: if not comment.visible: continue uid = build_tag_uri(req.app, comment.pub_date, 'comment', comment.id) title = _(u'Comment %(num)d on %(post)s') % { 'num': comment_num, 'post': post.title } author = {'name': comment.author} if comment.www: author['uri'] = comment.www feed.add_item(title, url_for(comment, _external=True), unicode(comment.body), author_name=author, pubdate=comment.pub_date, unique_id=uid) comment_num += 1 return feed.writeString('utf-8')
def generate(self, **options): """This method generates the pagination. It accepts some keyword arguments that override the theme pagination settings. These arguments have the same name as the theme setting variables without the `pagination.` prefix. """ from zine.application import url_for, get_application, \ DEFAULT_THEME_SETTINGS if self._skip_theme_defaults: settings = DEFAULT_THEME_SETTINGS else: settings = get_application().theme.settings def _getopt(name): value = options.pop(name, None) if value is not None: return value return settings['pagination.' + name] normal = _getopt('normal') active = _getopt('active') commata = _getopt('commata') ellipsis = _getopt('ellipsis') threshold = _getopt('threshold') left_threshold = _getopt('left_threshold') right_threshold = _getopt('right_threshold') prev_link = _getopt('prev_link') next_link = _getopt('next_link') gray_prev_link = _getopt('gray_prev_link') gray_next_link = _getopt('gray_next_link') simple = _getopt('simple') if options: raise TypeError('generate() got an unexpected keyword ' 'argument %r' % iter(options).next()) was_ellipsis = False result = [] prev = None next = None get_link = lambda x: url_for(self.endpoint, page=x, per_page=self.per_page, post_id=self.post_id, **self.url_args) if simple: result.append(active % { 'url': get_link(self.page), 'page': self.page }) if self.page > 1: prev = self.page - 1 if self.page < self.pages: next = self.page + 1 else: for num in xrange(1, self.pages + 1): if num == self.page: was_ellipsis = False if num - 1 == self.page: next = num if num + 1 == self.page: prev = num if num <= left_threshold or \ num > self.pages - right_threshold or \ abs(self.page - num) < threshold: if result and result[-1] != ellipsis: result.append(commata) link = get_link(num) template = num == self.page and active or normal result.append(template % { 'url': link, 'page': num }) elif not was_ellipsis: was_ellipsis = True result.append(ellipsis) if next_link: if next is not None: result.append(u' <a href="%s" class="next">%s</a>' % (get_link(next), _(u'Next »'))) elif gray_next_link: result.append(u' <span class="disabled next">%s</span>' % _(u'Next »')) if prev_link: if prev is not None: result.insert(0, u'<a href="%s" class="prev">%s</a> ' % (get_link(prev), _(u'« Previous'))) elif gray_prev_link: result.insert(0, u'<span class="disabled prev">%s</span> ' % _(u'« Previous')) return u''.join(result)
def atom_feed(req, author=None, year=None, month=None, day=None, category=None, tag=None, post=None): """Renders an atom feed requested. :URL endpoint: ``blog/atom_feed`` """ feed = AtomFeed(req.app.cfg['blog_title'], feed_url=req.url, url=req.app.cfg['blog_url'], subtitle=req.app.cfg['blog_tagline']) # the feed only contains published items query = Post.query.published() # feed for a category if category is not None: category = Category.query.filter_by(slug=category).first(True) query = query.filter(Post.categories.contains(category)) # feed for a tag if tag is not None: tag = Tag.query.filter_by(slug=tag).first(True) query = query.filter(Post.tags.contains(tag)) # feed for an author if author is not None: author = User.query.filter_by(username=author).first(True) query = query.filter(Post.author == author) # feed for dates if year is not None: query = query.for_index().date_filter(year, month, day) # if no post slug is given we filter the posts by the cretereons # provided and pass them to the feed builder. This will only return # a feed for posts with a content type listed in `index_content_types` if post is None: for post in query.for_index().order_by(Post.pub_date.desc()) \ .limit(15).all(): links = [link.as_dict() for link in post.links] feed.add(post.title or '%s @ %s' % (post.author.display_name, post.pub_date), unicode(post.body), content_type='html', author=post.author.display_name, links=links, url=url_for(post, _external=True), id=post.uid, updated=post.last_update, published=post.pub_date) # otherwise we create a feed for all the comments of a post. # the function is called this way by `dispatch_content_type`. else: comment_num = 1 for comment in post.comments: if not comment.visible: continue uid = build_tag_uri(req.app, comment.pub_date, 'comment', comment.id) title = _(u'Comment %(num)d on %(post)s') % { 'num': comment_num, 'post': post.title } author = {'name': comment.author} if comment.www: author['uri'] = comment.www feed.add(title, unicode(comment.body), content_type='html', author=author, url=url_for(comment, _external=True), id=uid, updated=comment.pub_date) comment_num += 1 return feed.get_response()