def latest(self, limit=None, ignore_privileges=False, ignore_blocked=True): """Filter the list of non blocked comments for anonymous users or all comments for admin users. """ query = self # only the approved if blocked are ignored if ignore_blocked: query = query.approved() # otherwise if we don't ignore the privileges we only want # the approved if the user does not have the MODERATE_COMMENTS # privileges. elif not ignore_privileges: req = get_request() if req: user = req.user if not user.has_privilege(MODERATE_COMMENTS | MODERATE_OWN_ENTRIES | MODERATE_OWN_PAGES): query = query.approved() elif user.has_privilege(MODERATE_OWN_ENTRIES | MODERATE_OWN_PAGES): query = query.for_user(user) return query
def make_visible_for_request(self, request=None): """Make the comment visible for the current request.""" if request is None: request = get_request() comments = set(request.session.get('visible_comments', ())) comments.add(self.id) request.session['visible_comments'] = tuple(comments)
def published(self, ignore_privileges=False, user=None): """Return a queryset for only published posts.""" if not user: req = get_request() user = req and req.user if ignore_privileges or not user: # Anonymous. Return only public entries. return self.filter( (Post.status == STATUS_PUBLISHED) & (Post.pub_date <= datetime.utcnow()) ) elif not user.has_privilege(VIEW_PROTECTED): # Authenticated user without protected viewing privilege # Return public and their own private entries return self.filter( ((Post.status == STATUS_PUBLISHED) | ((Post.status == STATUS_PRIVATE) & (Post.author_id == user.id))) & (Post.pub_date <= datetime.utcnow()) ) else: # Authenticated and can view protected. # Return public, protected and their own private return self.filter( ((Post.status == STATUS_PUBLISHED) | (Post.status == STATUS_PROTECTED) | ((Post.status == STATUS_PRIVATE) & (Post.author_id == user.id))) & (Post.pub_date <= datetime.utcnow()) )
def can_read(self, user=None): """Check if the current user or the user provided can read-access this post. If there is no user there must be a request object for this thread defined. """ # published posts are always accessible if self.status == STATUS_PUBLISHED and self.pub_date is not None and \ self.pub_date <= datetime.utcnow(): return True if user is None: user = get_request().user # users that are allowed to look at drafts may pass if user.has_privilege(VIEW_DRAFTS): return True # if this is protected and user can view protected, allow them if self.status == STATUS_PROTECTED and self.pub_date is not None and \ self.pub_date <= datetime.utcnow() and \ user.has_privilege(VIEW_PROTECTED): return True # if we have the privilege to edit other entries or if we are # a blog administrator we can always look at posts. if user.has_privilege(self.EDIT_OTHER_PRIVILEGE): return True # otherwise if the user has the EDIT_OWN_PRIVILEGE and the # author of the post, he may look at it as well if user.id == self.author_id and \ user.has_privilege(self.EDIT_OWN_PRIVILEGE): return True return False
def visible_for_user(self, user=None): """Check if the current user or the user given can see this comment""" if not self.blocked: return True if user is None: user = get_request().user return user.has_privilege(MODERATE_COMMENTS)
def __init__(self, id, message, user=Ellipsis): self.message = parse_zeml(message, 'system') self.id = id self.sent_date = datetime.utcnow() if user is Ellipsis: self.user = get_request().user else: self.user = user
def can_edit(self, user=None): """Checks if the given user (or current user) can edit this post.""" if user is None: user = get_request().user return (user.has_privilege(self.EDIT_OTHER_PRIVILEGE) or (self.author == user and user.has_privilege(self.EDIT_OWN_PRIVILEGE)))
def __init__(self, post, user, initial=None): forms.Form.__init__(self, initial) self.req = get_request() self.post = post self.user = user # if the user is logged in the form is a bit smaller if user.is_somebody: del self.fields['author'], self.fields['email'], self.fields['www']
def visible(self): """Check the current session it can see the comment or check against the current user. To display a comment for a request you can use the `make_visible_for_request` function. This is useful to show a comment to a user that submitted a comment which is not yet moderated. """ request = get_request() if request is None: return True return self.visible_for_user(request.user)
def can_edit(self, user=None): """Checks if the given user (or current user) can edit this post.""" if user is None: user = get_request().user return ( user.has_privilege(self.EDIT_OTHER_PRIVILEGE) or (self.author == user and user.has_privilege(self.EDIT_OWN_PRIVILEGE)) )
def for_user(self, user=None): request = get_request() user = user or request.user if user.has_privilege(MODERATE_COMMENTS): return self elif user.has_privilege(MODERATE_OWN_ENTRIES | MODERATE_OWN_PAGES): return self.filter(Comment.post_id.in_( db.session.query(Post.id).filter(Post.author_id==user.id)) ) return self
def visible(self): """Check the current session it can see the comment or check against the current user. To display a comment for a request you can use the `make_visible_for_request` function. This is useful to show a comment to a user that submited a comment which is not yet moderated. """ request = get_request() if self.id in request.session.get('visible_comments', ()): return True return self.visible_for_user(request.user)
def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): start = _timer() try: return execute(cursor, statement, parameters, context) finally: from zine.application import get_request from zine.utils.debug import find_calling_context request = get_request() if request is not None: request.queries.append((statement, parameters, start, _timer(), find_calling_context()))
def drafts(self, ignore_user=False, user=None): """Return a query that returns all drafts for the current user. or the user provided or no user at all if `ignore_user` is set. """ if user is None and not ignore_user: req = get_request() if req and req.user: user = req.user query = self.filter(Post.status == STATUS_DRAFT) if user is not None: query = query.filter(Post.author_id == user.id) return query
def comment_count(self): """The number of visible comments.""" req = get_request() # if the model was loaded with .lightweight() there are no comments # but a _comment_count we can use. if not db.attribute_loaded(self, 'comments'): return self._comment_count # otherwise the comments are already available and we can savely # filter it. if req.user.is_manager: return len(self.comments) return len([x for x in self.comments if not x.blocked])
def comment_count(self): """The number of visible comments.""" req = get_request() # if the model was loaded with .lightweight() there are no comments # but a _comment_count we can use. if not db.attribute_loaded(self, 'comments'): return self._comment_count # otherwise the comments are already available and we can savely # filter it. if req and req.user.is_manager: return len(self.comments) return len([x for x in self.comments if not x.blocked])
def validate_session_captcha(req, comment): req = get_request() if 'captcha' not in req.session: return captcha = req.session.pop("captcha") if 'captcha_mangled' in req.session: del req.session['captcha_mangled'] if 'captcha' not in req.form: comment.status = COMMENT_BLOCKED_SPAM comment.blocked_msg = SKIPPED_TEST_MSG return if req.form['captcha'] != captcha: comment.status = COMMENT_BLOCKED_SPAM comment.blocked_msg = FAILED_TEST_MSG return
def __init__(self, post=None, initial=None): self.app = get_application() self.post = post if post is not None: initial = forms.fill_dict(initial, title=post.title, text=post.text, status=post.status, pub_date=post.pub_date, slug=post.slug, author=post.author, tags=[x.name for x in post.tags], categories=[x.id for x in post.categories], parser=post.parser, comments_enabled=post.comments_enabled, pings_enabled=post.pings_enabled, ping_links=not post.parser_missing ) else: initial = forms.fill_dict(initial, status=STATUS_DRAFT) # if we have a request, we can use the current user as a default req = get_request() if req and req.user: initial['author'] = req.user initial.setdefault('parser', self.app.cfg['default_parser']) self.author.choices = [x.username for x in User.query.all()] self.parser.choices = self.app.list_parsers() self.parser_missing = post and post.parser_missing if self.parser_missing: self.parser.choices.append((post.parser, _('%s (missing)') % post.parser.title())) self.categories.choices = [(c.id, c.name) for c in Category.query.all()] forms.Form.__init__(self, initial) # if we have have an old post and the parser is not missing and # it was published when the form was created we collect the old # posts so that we don't have to ping them another time. self._old_links = set() if self.post is not None and not self.post.parser_missing and \ self.post.is_published: self._old_links.update(self.post.find_urls())
def visible_for_user(self, user=None): """Check if the current user or the user given can see this comment""" request = get_request() if user is None: user = request.user if self.post.author is user and \ user.has_privilege(MODERATE_OWN_ENTRIES | MODERATE_OWN_PAGES): return True elif user.has_privilege(MODERATE_COMMENTS): # User is able to manage comments. It's visible. return True elif self.id in request.session.get('visible_comments', ()): # Comment was made visible for current request. It's visible return True # Finally, comment is visible if not blocked return not self.blocked
def bind_privileges(container, privileges, user=None): """Binds the privileges to the container. The privileges can be a list of privilege names, the container must be a set. This is called for the HTTP round-trip in the form validation. """ if not user: user = get_request().user app = get_application() notification_types = app.notification_manager.notification_types current_map = dict((x.name, x) for x in container) currently_attached = set(x.name for x in container) new_privileges = set(privileges) # remove out-dated privileges for name in currently_attached.difference(new_privileges): container.remove(current_map[name]) # remove any privilege dependencies that are not attached to other # privileges if current_map[name].dependencies: for privilege in current_map[name].dependencies.iter_privileges(): try: container.remove(privilege) except KeyError: # privilege probably already removed pass # remove notification subscriptions that required the privilege # being deleted. for notification in user.notification_subscriptions: privs = notification_types[notification.notification_id].privileges if current_map[name] in privs.iter_privileges(): db.session.delete(notification) break for privilege in current_map[name].dependencies: if privilege in privs.iter_privileges(): db.session.delete(notification) # add new privileges for name in new_privileges.difference(currently_attached): privilege = app.privileges[name] container.add(privilege) # add dependable privileges if privilege.dependencies: for privilege in privilege.dependencies.iter_privileges(): container.add(privilege)
def get_redirect_target(invalid_targets=(), request=None): """Check the request and get the redirect target if possible. If not this function returns just `None`. The return value of this function is suitable to be passed to `_redirect` """ if request is None: request = get_request() check_target = request.values.get('_redirect_target') or \ request.args.get('next') or \ request.environ.get('HTTP_REFERER') # if there is no information in either the form data # or the wsgi environment about a jump target we have # to use the target url if not check_target: return # otherwise drop the leading slash check_target = check_target.lstrip('/') blog_url = request.app.cfg['blog_url'] blog_parts = urlparse(blog_url) check_parts = urlparse(urljoin(blog_url, check_target)) # if the jump target is on a different server we probably have # a security problem and better try to use the target url. if blog_parts[:2] != check_parts[:2]: return # if the jump url is the same url as the current url we've had # a bad redirect before and use the target url to not create a # infinite redirect. current_parts = urlparse(urljoin(blog_url, request.path)) if check_parts[:5] == current_parts[:5]: return # if the `check_target` is one of the invalid targets we also # fall back. for invalid in invalid_targets: if check_parts[:5] == urlparse(urljoin(blog_url, invalid))[:5]: return return check_target
def latest(self, limit=None, ignore_privileges=False, ignore_blocked=True): """Filter the list of non blocked comments for anonymous users or all comments for admin users. """ query = self # only the approved if blocked are ignored if ignore_blocked: query = query.approved() # otherwise if we don't ignore the privileges we only want # the approved if the user does not have the MODERATE_COMMENTS # privileges. elif not ignore_privileges: req = get_request() if req: user = req.user if not user.has_privilege(MODERATE_COMMENTS): query = query.approved() return query
def redirect(url, code=302, allow_external_redirect=False, force_scheme_change=False): """Return a redirect response. Like Werkzeug's redirect but this one checks for external redirects too. If a redirect to an external target was requested `BadRequest` is raised unless `allow_external_redirect` was explicitly set to `True`. Leading slashes are ignored which makes it unsuitable to redirect to URLs returned from `url_for` and others. Use `redirect_to` to redirect to arbitrary endpoints or `_redirect` to redirect to unchecked resources outside the URL root. By default the redirect will not change the URL scheme of the current request (if there is one). This behavior can be changed by setting the force_scheme_change to False. """ # leading slashes are ignored, if we redirect to "/foo" or "foo" # does not matter, in both cases we want to be below our blog root. url = url.lstrip('/') if not allow_external_redirect: #: check if the url is on the same server #: and make it an external one try: url = check_external_url(get_application(), url) except ValueError: raise BadRequest() # keep the current URL schema if we have an active request if we # should. If https enforcement is set we suppose that the blog_url # is already set to an https value. request = get_request() if request and not force_scheme_change and \ not request.app.cfg['force_https']: url = request.environ['wsgi.url_scheme'] + ':' + url.split(':', 1)[1] return _redirect(url, code)
def published(self, ignore_privileges=None, user=None): """Return a queryset for only published posts.""" if not user: req = get_request() user = req and req.user if not user: # Anonymous. Return only public entries. return self.filter((Post.status == STATUS_PUBLISHED) & (Post.pub_date <= datetime.utcnow())) elif not user.has_privilege(VIEW_PROTECTED): # Authenticated user without protected viewing privilege # Return public and their own private entries return self.filter(((Post.status == STATUS_PUBLISHED) | ( (Post.status == STATUS_PRIVATE) & (Post.author_id == user.id))) & (Post.pub_date <= datetime.utcnow())) else: # Authenticated and can view protected. # Return public, protected and their own private return self.filter(((Post.status == STATUS_PUBLISHED) | (Post.status == STATUS_PROTECTED) | ( (Post.status == STATUS_PRIVATE) & (Post.author_id == user.id))) & (Post.pub_date <= datetime.utcnow()))
def __init__(self, comment, initial=None): self.req = get_request() _CommentBoundForm.__init__(self, comment, initial)
def assert_privilege(expr): """Like the `require_privilege` decorator but for asserting.""" if not get_request().user.has_privilege(expr): raise Forbidden()
def mark_as_spam(self): emit_event('before-comment-mark-spam', self.comment) self.comment.status = COMMENT_BLOCKED_SPAM self.comment.blocked_msg = _("Comment reported as spam by %s" % get_request().user.display_name)
def block_selection(self): for comment in self.iter_selection(): emit_event('before-comment-blocked', comment) comment.status = COMMENT_BLOCKED_USER comment.blocked_msg = _("Comment blocked by %s" % get_request().user.display_name)
def set_session_captcha(post): req = get_request() req.session['captcha'] = random.choice(choices) req.session['captcha_mangled'] = req.session['captcha'].replace("o", "0").replace("a", "A").replace("i", "1").replace("e", "3")
def types(self, user=None): if not user: user = get_request().user for notification in self.notification_types.itervalues(): if user.has_privilege(notification.privileges): yield notification
def mark_selection_as_spam(self): for comment in self.iter_selection(): emit_event('before-comment-mark-spam', comment) comment.status = COMMENT_BLOCKED_SPAM comment.blocked_msg = _("Comment marked as spam by %s" % get_request().user.display_name)