def validator(form, value): items = value.split() if len(items) > 1: raise ValidationError(_(u'You have to enter a valid net address.')) items = items[0].split(':') if len(items) not in (1, 2): raise ValidationError(_(u'You have to enter a valid net address.')) elif len(items) == 2 and not items[1].isdigit(): raise ValidationError(_(u'The port has to be numeric'))
def validator(form, value): if '<' in value or '>' in value: raise ValidationError(_(u'Invalid character, < or > are not allowed.')) if value == '/': raise ValidationError(_(u'URL prefix must not be a sole slash.')) if value: if value[:1] != '/': raise ValidationError(_(u'URL prefix must start with a slash.')) if value[-1:] == '/': raise ValidationError(_(u'URL prefix must not end with a slash.'))
def validator(form, value): if '<' in value or '>' in value: raise ValidationError( _(u'Invalid character, < or > are not allowed.')) if value == '/': raise ValidationError(_(u'URL prefix must not be a sole slash.')) if value: if value[:1] != '/': raise ValidationError( _(u'URL prefix must start with a slash.')) if value[-1:] == '/': raise ValidationError( _(u'URL prefix must not end with a slash.'))
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 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 validator(form, value): if '<' in value or '>' in value or '\\' in value: raise ValidationError(_(u'Invalid character, <, > or \\ are not ' 'allowed.')) if value: if value.startswith('/'): raise ValidationError(_(u'URL format cannot start with a slash.')) if value.find('//') >= 0: raise ValidationError(_(u'URL cannot contain //.')) if value.find('/../') >= 0 or value.startswith('../'): raise ValidationError(_(u'URL cannot contain a reference to' 'parent path.')) for match in _placeholder_re.finditer(value): if match.group(1) not in _slug_parts: raise ValidationError(_(u'Unknown format code %s.') % match.group())
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 flash(msg, type='info'): """Add a message to the message flash buffer. The default message type is "info", other possible values are "add", "remove", "error", "ok" and "configure". The message type affects the icon and visual appearance. The flashes messages appear only in the admin interface! """ assert type in \ ('info', 'add', 'remove', 'error', 'ok', 'configure', 'warning') if type == 'error': msg = (u'<strong>%s:</strong> ' % _('Error')) + msg if type == 'warning': msg = (u'<strong>%s:</strong> ' % _('Warning')) + msg local.request.session.setdefault('admin/flashed_messages', []).\ append((type, msg))
def __init__(self, message_or_exception): if isinstance(message_or_exception, basestring): message = message_or_exception error = None else: message = _(u'Could not save configuration file: %s') % \ str(message_or_exception).decode('utf-8', 'ignore') error = message_or_exception InternalError.__init__(self, message) self.original_exception = error
def configure(self, request): form = FeedImportForm() if request.method == 'POST' and form.validate(request.form): feed = request.files.get('feed') if form.data['download_url']: try: feed = open_url(form.data['download_url']).stream except Exception, e: log.exception(_('Error downloading feed')) flash(_(u'Error downloading from URL: %s') % e, 'error') if not feed: return redirect_to('import/feed') try: blog = parse_feed(feed) except Exception, e: log.exception(_(u'Error parsing uploaded file')) flash(_(u'Error parsing feed: %s') % e, 'error')
def validator(form, value): if '<' in value or '>' in value or '\\' in value: raise ValidationError( _(u'Invalid character, <, > or \\ are not ' 'allowed.')) if value: if value.startswith('/'): raise ValidationError( _(u'URL format cannot start with a slash.')) if value.find('//') >= 0: raise ValidationError(_(u'URL cannot contain //.')) if value.find('/../') >= 0 or value.startswith('../'): raise ValidationError( _(u'URL cannot contain a reference to' 'parent path.')) for match in _placeholder_re.finditer(value): if match.group(1) not in _slug_parts: raise ValidationError( _(u'Unknown format code %s.') % match.group())
def configure(self, request): form = WordPressImportForm() if request.method == "POST" and form.validate(request.form): dump = request.files.get("dump") if form.data["download_url"]: try: dump = open_url(form.data["download_url"]).stream except Exception, e: log.exception(_("Error downloading feed")) flash(_(u"Error downloading from URL: %s") % e, "error") if not dump: return redirect_to("import/wordpress") try: blog = parse_feed(dump) except Exception, e: raise log.exception(_(u"Error parsing uploaded file")) flash(_(u"Error parsing uploaded file: %s") % e, "error")
def configure(self, request): form = WordPressImportForm() if request.method == 'POST' and form.validate(request.form): dump = request.files.get('dump') if form.data['download_url']: try: dump = open_url(form.data['download_url']).stream except Exception, e: log.exception(_('Error downloading feed')) flash(_(u'Error downloading from URL: %s') % e, 'error') if not dump: return redirect_to('import/wordpress') try: blog = parse_feed(dump) except Exception, e: raise log.exception(_(u'Error parsing uploaded file')) flash(_(u'Error parsing uploaded file: %s') % e, 'error')
def parse_feed(fd): tree = etree.parse(fd).getroot() if tree.tag == 'rss': parser_class = RSSParser elif tree.tag == atom.feed: parser_class = AtomParser else: raise FeedImportError(_('Unknown feed uploaded.')) parser = parser_class(tree) parser.parse() return parser.blog
def process_result_value(self, value, dialect): from rezine.utils.zeml import load_parser_data try: return load_parser_data(value) except ValueError: # Parser data invalid. Database corruption? from rezine.i18n import _ from rezine.utils import log log.exception(_(u'Error when loading parsed data from database. ' u'Maybe the database was manually edited and got ' u'corrupted? The system returned an empty value.')) return {}
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 process_result_value(self, value, dialect): from rezine.utils.zeml import load_parser_data try: return load_parser_data(value) except ValueError: # Parser data invalid. Database corruption? from rezine.i18n import _ from rezine.utils import log log.exception( _(u'Error when loading parsed data from database. ' u'Maybe the database was manually edited and got ' u'corrupted? The system returned an empty value.')) return {}
def dispatch_content_type(req): """Show the post for a specific content type.""" slug = req.path[1:] # feed for the post if slug.endswith('/feed.atom'): slug = slug[:-10] want_feed = True else: want_feed = False post = Post.query.filter_by(slug=slug).first() if post is None: # if the post does not exist, check if a post with a trailing slash # exists. If it does, redirect to that post. This is allows users # to emulate folders and to get relative links working. if not slug.endswith('/'): real_post = Post.query.filter_by(slug=slug + '/').first() if real_post is None: raise NotFound() # if we want the feed, we don't want a redirect elif want_feed: post = real_post else: return redirect_to(real_post) else: raise NotFound() # make sure the current user can access that page. if not post.can_read(): raise Forbidden() # feed requested? jump to the feed page if want_feed: return atom_feed(req, post=post) # create the comment form form = NewCommentForm(post, req.user) if post.comments_enabled or post.comments: add_link('alternate', post.comment_feed_url, 'application/atom+xml', _(u'Comments Feed')) # now dispatch to the correct view handler = req.app.content_type_handlers.get(post.content_type) if handler is None: log.warn('No handler for the content type %r found.' % post.content_type) raise NotFound() return handler(req, post, form)
def make_setup_error(exc_info=None): """Create a new SetupError for the last exception and log it.""" if exc_info is None: exc_info = sys.exc_info() # log the exception log.exception(_(u'Plugin setup error'), 'pluginsystem', exc_info) exc_type, exc_value, tb = exc_info # if the exception is already a SetupError we only # have to return it unchanged. if isinstance(exc_value, SetupError): return exc_value # otherwise create an error message for it and return a new # exception. error, (filename, line) = summarize_exception(exc_info) return SetupError(_(u'Exception happend on setup: ' u'%(error)s (%(file)s, line %(line)d)') % { 'error': escape(error), 'file': filename, 'line': line })
def profile(request): form = EditProfileForm(request.user) if request.method == 'POST': if request.form.get('cancel'): return form.redirect('account/index') elif request.form.get('delete'): return redirect_to('account/delete') elif form.validate(request.form): form.save_changes() db.commit() flash(_(u'Your profile was updated successfully.'), 'info') return form.redirect('account/index') return render_account_response('account/edit_profile.html', 'profile', form=form.as_widget())
def make_setup_error(exc_info=None): """Create a new SetupError for the last exception and log it.""" if exc_info is None: exc_info = sys.exc_info() # log the exception log.exception(_(u'Plugin setup error'), 'pluginsystem', exc_info) exc_type, exc_value, tb = exc_info # if the exception is already a SetupError we only # have to return it unchanged. if isinstance(exc_value, SetupError): return exc_value # otherwise create an error message for it and return a new # exception. error, (filename, line) = summarize_exception(exc_info) return SetupError( _(u'Exception happend on setup: ' u'%(error)s (%(file)s, line %(line)d)') % { 'error': escape(error), 'file': filename, 'line': line })
class RSTParser(BaseParser): """A reStructured Text parser.""" name = _(u'Rezine-rST') settings = dict(file_insertion_enabled=0, raw_enabled=0, output_encoding='unicode', input_encoding='unicode', initial_header_level=4) docutils_publish = staticmethod(docutils.core.publish_parts) def parse(self, input_data, reason): parts = self.docutils_publish(input_data, writer_name='html', settings_overrides=self.settings) return parse_html(parts['html_body'])
def notification_settings(request): """Allow the user to change his notification settings.""" form = make_notification_form(request.user) if request.method == 'POST' and form.validate(request.form): form.apply() db.commit() flash(_('Notification settings changed.'), 'configure') return form.redirect('account/notification_settings') return render_account_response('account/notification_settings.html', 'notifications', form=form.as_widget(), systems=sorted( request.app.notification_manager.systems.values(), key=lambda x: x.name.lower() ), notification_types=sorted( request.app.notification_manager.types(request.user), key=lambda x: x.description.lower() ) )
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 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 summarize_exception(exc_info): def _to_unicode(x): try: return unicode(x) except UnicodeError: return str(x).encode('utf-8', 'replace') exc_type, exc_value, tb = exc_info if isinstance(exc_type, basestring): prefix = _to_unicode(exc_type) else: prefix = _to_unicode(exc_type.__name__) message = _to_unicode(exc_value) filename = tb.tb_frame.f_globals.get('__file__') if filename is None: filename = _(u'unkown file') else: filename = _to_unicode(filename) if filename.endswith('.pyc'): filename = filename[:-1] return u'%s: %s' % (prefix, message), (filename, tb.tb_lineno)
def validator(form, value): if not value.strip(): raise ValidationError(_(u'The text must not be empty.'))
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 rezine.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 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 validator(form, value): if len(value) > 200: raise ValidationError(_(u'The slug is too long')) elif value.startswith('/'): raise ValidationError(_(u'The slug must not start with a slash'))
def __init__(self, tree): raise FeedImportError(_('Importing of RSS feeds is currently ' 'not possible.'))
def _perform_import(app, blog, d): # import models here because they have the same names as our # importer objects this module exports from rezine.models import User, Tag, Category, Post, Comment author_mapping = {} tag_mapping = {} category_mapping = {} def prepare_author(author): """Adds an author to the author mapping and returns it.""" if author.id not in author_mapping: author_rewrite = d['authors'][author.id] if author_rewrite != '__rezine_create_user': user = User.query.get(int(author_rewrite)) else: query = User.query.filter_by(username=author.username) user = query.first() if user is None: user = User(author.username, None, author.email, author.real_name, author.description, author.www, author.is_author) if author.pw_hash: user.pw_hash = author.pw_hash user.own_privileges.update(author.privileges) author_mapping[author.id] = user return author_mapping[author.id] def prepare_tag(tag): """Get a tag for a tag.""" t = tag_mapping.get(tag.slug) if t is not None: return t t = Tag.query.filter_by(slug=tag.slug).first() if t is not None: tag_mapping[tag.slug] = t return t t = Tag.query.filter_by(name=tag.name).first() if t is not None: tag_mapping[tag.slug] = t return t t = tag_mapping[tag.id] = Tag(tag.name, tag.slug) return t def prepare_category(category): """Get a category for a category.""" c = category_mapping.get(category.slug) if c is not None: return c c = Category.query.filter_by(slug=category.slug).first() if c is not None: category_mapping[category.slug] = c return c c = Category.query.filter_by(name=category.name).first() if c is not None: category_mapping[category.slug] = c return c c = category_mapping[category.id] = Category(category.name, category.description, category.slug) return c # start debug output yield u'<ul>' # update blog configuration if user wants that if d['title']: app.cfg.change_single('blog_title', blog.title) yield u'<li>%s</li>\n' % _('set blog title from dump') if d['description']: app.cfg.change_single('blog_tagline', blog.description) yield u'<li>%s</li>\n' % _('set blog tagline from dump') # convert the posts now for old_post in blog.posts: # in theory that will never happen because there are no # checkboxes for already imported posts on the form, but # who knows what users manage to do and also skip posts # we don't want converted if old_post.already_imported or not d['posts'][old_post.id]: continue slug = old_post.slug while Post.query.autoflush(False).filter_by(slug=slug) \ .limit(1).count(): slug = increment_string(slug) post = Post(old_post.title, prepare_author(old_post.author), old_post.text, slug, old_post.pub_date, old_post.updated, old_post.comments_enabled, old_post.pings_enabled, parser=old_post.parser, uid=old_post.uid, content_type=old_post.content_type, status=old_post.status, extra=old_post.extra) if old_post.parser_data is not None: post.parser_data.clear() post.parser_data.update(old_post.parser_data) yield u'<li><strong>%s</strong>' % escape(post.title) for tag in old_post.tags: post.tags.append(prepare_tag(tag)) yield u'.' for category in old_post.categories: post.categories.append(prepare_category(category)) yield u'.' # now the comments if user wants them. if d['comments'][old_post.id]: to_create = set(old_post.comments) created = {} def _create_comment(comment): parent = None if comment.parent is not None: if comment.parent in created: parent = created[comment.parent] else: parent = _create_comment(comment.parent) to_create.discard(comment.parent) if isinstance(comment.author, Author): author = prepare_author(comment.author) else: author = comment.author rv = Comment(post, author, comment.body, comment.author_email, comment.author_url, parent, comment.pub_date, comment.remote_addr, comment.parser, comment.is_pingback, comment.status) if comment.blocked_msg: rv.blocked_msg = comment.blocked_msg created[comment] = rv return rv while to_create: _create_comment(to_create.pop()) yield u'.' yield u' <em>%s</em></li>\n' % _('done') # send to the database yield u'<li>%s' % _('Committing transaction...') db.commit() # write config if we have if d['load_config']: yield u'<li>%s' % _('Updating configuration...') t = app.cfg.edit() for key, value in blog.config.iteritems(): if key in t and key not in ignored_config_keys: t.set_from_string(key, value) t.commit() yield u' <em>%s</em></li></ul>' % _('done')
try: feed = open_url(form.data['download_url']).stream except Exception, e: log.exception(_('Error downloading feed')) flash(_(u'Error downloading from URL: %s') % e, 'error') if not feed: return redirect_to('import/feed') try: blog = parse_feed(feed) except Exception, e: log.exception(_(u'Error parsing uploaded file')) flash(_(u'Error parsing feed: %s') % e, 'error') else: self.enqueue_dump(blog) flash(_(u'Added imported items to queue.')) return redirect_to('admin/import') return self.render_admin_page('admin/import_feed.html', form=form.as_widget()) class Extension(object): """Extensions are instanciated for each parsing process.""" feed_types = frozenset() def __init__(self, app, parser, root): self.app = app self.parser = parser self.root = root
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 rezine.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 render_account_response(template_name, _active_menu_item=None, **values): """Works pretty much like the normal `render_response` function but it emits some events to collect navigation items and injects that into the template context. This also gets the flashes messages from the user session and injects them into the template context after the plugins have provided theirs in the `before-account-response-rendered` event. The second parameter can be the active menu item if wanted. For example ``'account.notifications'`` would show the notifications button in the account submenu. If the menu is a standalone menu like the dashboard (no child items) you can also just use ``'dashboard'`` to highlight that. """ request = get_request() # set up the core navigation bar navigation_bar = [ ('dashboard', url_for('account/index'), _(u'Dashboard'), []), ('profile', url_for('account/profile'), _(u'Profile'), []), ('notifications', url_for('account/notification_settings'), _(u'Notifications'), []) ] # add the about items to the navigation bar system_items = [ ('about', url_for('account/about_rezine'), _(u'About')) ] if request.user.is_admin: # Current documentation is addressed for admins system_items.append(('help', url_for('account/help'), _(u'Help'))) navigation_bar.append(('system', system_items[0][1], _(u'System'), system_items)) #! allow plugins to extend the navigation bar emit_event('modify-account-navigation-bar', request, navigation_bar) # find out which is the correct menu and submenu bar active_menu = active_submenu = None if _active_menu_item is not None: p = _active_menu_item.split('.') if len(p) == 1: active_menu = p[0] else: active_menu, active_submenu = p for id, url, title, subnavigation_bar in navigation_bar: if id == active_menu: break else: subnavigation_bar = [] #! used to flash messages, add links to stylesheets, modify the admin #! context etc. emit_event('before-account-response-rendered', request, values) # the admin variables is pushed into the context after the event was # sent so that plugins can flash their messages. If we would emit the # event afterwards all flashes messages would appear in the request # after the current request. values['account'] = { 'user_can_enter_admin_panel': request.user.has_privilege(ENTER_ADMIN_PANEL), 'navbar': [{ 'id': id, 'url': url, 'title': title, 'active': active_menu == id } for id, url, title, children in navigation_bar], 'ctxnavbar': [{ 'id': id, 'url': url, 'title': title, 'active': active_submenu == id } for id, url, title in subnavigation_bar], 'messages': [{ 'type': type, 'msg': msg } for type, msg in request.session.pop('account/flashed_messages', [])], 'active_pane': _active_menu_item } return render_response(template_name, **values)
name = "wordpress" title = "WordPress" description = lazy_gettext(u'Handles import of WordPress "extended RSS" ' u" feeds.") def configure(self, request): form = WordPressImportForm() if request.method == "POST" and form.validate(request.form): dump = request.files.get("dump") if form.data["download_url"]: try: dump = open_url(form.data["download_url"]).stream except Exception, e: log.exception(_("Error downloading feed")) flash(_(u"Error downloading from URL: %s") % e, "error") if not dump: return redirect_to("import/wordpress") try: blog = parse_feed(dump) except Exception, e: raise log.exception(_(u"Error parsing uploaded file")) flash(_(u"Error parsing uploaded file: %s") % e, "error") else: self.enqueue_dump(blog) flash(_(u"Added imported items to queue.")) return redirect_to("admin/import") return self.render_admin_page("admin/import_wordpress.html", form=form.as_widget())
description = lazy_gettext(u'Handles import of WordPress "extended RSS" ' u' feeds.') def configure(self, request): form = WordPressImportForm() if request.method == 'POST' and form.validate(request.form): dump = request.files.get('dump') if form.data['download_url']: try: dump = open_url(form.data['download_url']).stream except Exception, e: log.exception(_('Error downloading feed')) flash(_(u'Error downloading from URL: %s') % e, 'error') if not dump: return redirect_to('import/wordpress') try: blog = parse_feed(dump) except Exception, e: raise log.exception(_(u'Error parsing uploaded file')) flash(_(u'Error parsing uploaded file: %s') % e, 'error') else: self.enqueue_dump(blog) flash(_(u'Added imported items to queue.')) return redirect_to('admin/import') return self.render_admin_page('admin/import_wordpress.html', form=form.as_widget())