Пример #1
0
def edit_post(request, id):
    post, revision = _load_post_and_revision(request, id)
    if not request.user.can_edit(post):
        raise Forbidden()

    if post.is_question:
        form = QuestionForm(post.topic, revision=revision)
    else:
        form = ReplyForm(post=post, revision=revision)

    if request.method == 'POST' and form.validate():
        form.save_changes()
        session.commit()
        request.flash(_('The post was edited.'))
        return redirect(url_for(post))

    def _format_entry(author, date, extra=u''):
        return _(u'%s (%s)') % (author, format_datetime(date)) + extra
    post_revisions = [(revision is None, '', _format_entry(
            (post.editor or post.author).display_name, post.updated,
            u' [%s]' % _(u'Current revision')))] + \
        [(revision == entry, entry.id, _format_entry(
            entry.editor.display_name, entry.date))
         for entry in post.revisions.order_by(PostRevision.date.desc())]

    return render_template('kb/edit_post.html',
                           form=form.as_widget(),
                           post=post,
                           all_revisions=post_revisions)
Пример #2
0
def get_serializer(request):
    """Returns the serializer for the given API request."""
    format = request.args.get('format')
    if format is not None:
        rv = _serializer_map.get(format)
        if rv is None:
            raise BadRequest(_(u'Unknown format "%s"') % escape(format))
        return rv

    # webkit sends useless accept headers. They accept XML over
    # HTML or have no preference at all. We spotted them, so they
    # are obviously not regular API users, just ignore the accept
    # header and return the debug serializer.
    if request.user_agent.browser in ('chrome', 'safari'):
        return _serializer_map['debug']

    best_match = (None, 0)
    for mimetype, serializer in _serializer_for_mimetypes.iteritems():
        quality = request.accept_mimetypes[mimetype]
        if quality > best_match[1]:
            best_match = (serializer, quality)

    if best_match[0] is None:
        raise BadRequest(_(u'Could not detect format.  You have to specify '
                           u'the format as query argument or in the accept '
                           u'HTTP header.'))

    # special case.  If the best match is not html and the quality of
    # text/html is the same as the best match, we prefer HTML.
    if best_match[0] != 'text/html' and \
       best_match[1] == request.accept_mimetypes['text/html']:
        return _serializer_map['debug']

    return _serializer_map[best_match[0]]
Пример #3
0
def restore_post(request, id):
    post, revision = _load_post_and_revision(request, id)

    # sanity checks
    if revision is None:
        if not request.user.is_moderator:
            raise Forbidden()
        elif not post.is_deleted:
            return redirect(url_for(post))
    elif not request.user.can_edit(post):
        raise Forbidden()

    form = EmptyForm()
    if request.method == 'POST' and form.validate():
        if 'yes' in request.form:
            if revision is None:
                request.flash(_(u'The post was restored'))
                post.restore()
            else:
                request.flash(_(u'The revision was restored'))
                revision.restore()
            session.commit()
        return form.redirect(post)

    return render_template('kb/restore_post.html',
                           form=form.as_widget(),
                           post=post,
                           revision=revision)
Пример #4
0
Файл: kb.py Проект: Plurk/Solace
def restore_post(request, id):
    post, revision = _load_post_and_revision(request, id)

    # sanity checks
    if revision is None:
        if not request.user.is_moderator:
            raise Forbidden()
        elif not post.is_deleted:
            return redirect(url_for(post))
    elif not request.user.can_edit(post):
        raise Forbidden()

    form = EmptyForm()
    if request.method == 'POST' and form.validate():
        if 'yes' in request.form:
            if revision is None:
                request.flash(_(u'The post was restored'))
                post.restore()
            else:
                request.flash(_(u'The revision was restored'))
                revision.restore()
            session.commit()
        return form.redirect(post)

    return render_template('kb/restore_post.html', form=form.as_widget(),
                           post=post, revision=revision)
Пример #5
0
Файл: kb.py Проект: Plurk/Solace
def edit_post(request, id):
    post, revision = _load_post_and_revision(request, id)
    if not request.user.can_edit(post):
        raise Forbidden()

    if post.is_question:
        form = QuestionForm(post.topic, revision=revision)
    else:
        form = ReplyForm(post=post, revision=revision)

    if request.method == 'POST' and form.validate():
        form.save_changes()
        session.commit()
        request.flash(_('The post was edited.'))
        return redirect(url_for(post))

    def _format_entry(author, date, extra=u''):
        return _(u'%s (%s)') % (author, format_datetime(date)) + extra
    post_revisions = [(revision is None, '', _format_entry(
            (post.editor or post.author).display_name, post.updated,
            u' [%s]' % _(u'Current revision')))] + \
        [(revision == entry, entry.id, _format_entry(
            entry.editor.display_name, entry.date))
         for entry in post.revisions.order_by(PostRevision.date.desc())]

    return render_template('kb/edit_post.html', form=form.as_widget(),
                           post=post, all_revisions=post_revisions)
Пример #6
0
def get_serializer(request):
    """Returns the serializer for the given API request."""
    format = request.args.get('format')
    if format is not None:
        rv = _serializer_map.get(format)
        if rv is None:
            raise BadRequest(_(u'Unknown format "%s"') % escape(format))
        return rv

    # webkit sends useless accept headers. They accept XML over
    # HTML or have no preference at all. We spotted them, so they
    # are obviously not regular API users, just ignore the accept
    # header and return the debug serializer.
    if request.user_agent.browser in ('chrome', 'safari'):
        return _serializer_map['debug']

    best_match = (None, 0)
    for mimetype, serializer in _serializer_for_mimetypes.iteritems():
        quality = request.accept_mimetypes[mimetype]
        if quality > best_match[1]:
            best_match = (serializer, quality)

    if best_match[0] is None:
        raise BadRequest(
            _(u'Could not detect format.  You have to specify '
              u'the format as query argument or in the accept '
              u'HTTP header.'))

    # special case.  If the best match is not html and the quality of
    # text/html is the same as the best match, we prefer HTML.
    if best_match[0] != 'text/html' and \
       best_match[1] == request.accept_mimetypes['text/html']:
        return _serializer_map['debug']

    return _serializer_map[best_match[0]]
Пример #7
0
def vote(request, post):
    """Votes on a post."""
    # TODO: this is currently also fired as GET if JavaScript is
    # not available.  Not very nice.
    post = Post.query.get(post)
    if post is None:
        raise NotFound()

    # you cannot cast votes on deleted shit
    if post.is_deleted:
        message = _(u"You cannot vote on deleted posts.")
        if request.is_xhr:
            return json_response(message=message, error=True)
        request.flash(message, error=True)
        return redirect(url_for(post))

    # otherwise
    val = request.args.get("val", 0, type=int)
    if val == 0:
        request.user.unvote(post)
    elif val == 1:
        # users cannot upvote on their own stuff
        if post.author == request.user:
            message = _(u"You cannot upvote your own post.")
            if request.is_xhr:
                return json_response(message=message, error=True)
            request.flash(message, error=True)
            return redirect(url_for(post))
        # also some reputation is needed
        if not request.user.is_admin and request.user.reputation < settings.REPUTATION_MAP["UPVOTE"]:
            message = _(u"In order to upvote you " u"need at least %d reputation") % settings.REPUTATION_MAP["UPVOTE"]
            if request.is_xhr:
                return json_response(message=message, error=True)
            request.flash(message, error=True)
            return redirect(url_for(post))
        request.user.upvote(post)
    elif val == -1:
        # users need some reputation to downvote.  Keep in mind that
        # you *can* downvote yourself.
        if not request.user.is_admin and request.user.reputation < settings.REPUTATION_MAP["DOWNVOTE"]:
            message = (
                _(u"In order to downvote you " u"need at least %d reputation") % settings.REPUTATION_MAP["DOWNVOTE"]
            )
            if request.is_xhr:
                return json_response(message=message, error=True)
            request.flash(message, error=True)
            return redirect(url_for(post))
        request.user.downvote(post)
    else:
        raise BadRequest()
    session.commit()

    # standard requests are answered with a redirect back
    if not request.is_xhr:
        return redirect(url_for(post))

    # others get a re-rendered vote box
    box = get_macro("kb/_boxes.html", "render_vote_box")
    return json_response(html=box(post, request.user))
Пример #8
0
 def validate_username(self, value):
     user = User.query.filter_by(username=value).first()
     if user is None:
         raise forms.ValidationError(_(u'No such user.'))
     if self.request is not None and \
        self.request.user == user:
         raise forms.ValidationError(_(u'You cannot ban yourself.'))
     self.user = user
Пример #9
0
 def validate_username(self, value):
     user = User.query.filter_by(username=value).first()
     if user is None:
         raise forms.ValidationError(_(u'No such user.'))
     if self.request is not None and \
        self.request.user == user:
         raise forms.ValidationError(_(u'You cannot ban yourself.'))
     self.user = user
Пример #10
0
 def context_validate(self, data):
     has_username = bool(data['username'])
     has_email = bool(data['email'])
     if not has_username and not has_email:
         raise forms.ValidationError(_(u'Either username or e-mail address '
                                       u' is required.'))
     if has_username and has_email:
         raise forms.ValidationError(_(u'You have to provide either a username '
                                       u'or an e-mail address, not both.'))
Пример #11
0
 def complete_login(self, request):
     consumer = Consumer(request.session, SolaceOpenIDStore())
     openid_response = consumer.complete(request.args.to_dict(),
                                         url_for('core.login', _external=True))
     if openid_response.status == SUCCESS:
         return self.create_or_login(request, openid_response.identity_url)
     elif openid_response.status == CANCEL:
         raise LoginUnsucessful(_(u'The request was cancelled'))
     else:
         raise LoginUnsucessful(_(u'OpenID authentication error'))
Пример #12
0
 def complete_login(self, request):
     consumer = Consumer(request.session, SolaceOpenIDStore())
     openid_response = consumer.complete(
         request.args.to_dict(), url_for('core.login', _external=True))
     if openid_response.status == SUCCESS:
         return self.create_or_login(request, openid_response.identity_url)
     elif openid_response.status == CANCEL:
         raise LoginUnsucessful(_(u'The request was cancelled'))
     else:
         raise LoginUnsucessful(_(u'OpenID authentication error'))
Пример #13
0
def is_valid_username(form, value):
    """Checks if the value is a valid username."""
    if len(value) > 40:
        raise forms.ValidationError(_(u'The username is too long.'))
    if '/' in value:
        raise forms.ValidationError(_(u'The username may not contain '
                                      u'slashes.'))
    if value[:1] == '.' or value[-1:] == '.':
        raise forms.ValidationError(_(u'The username may not begin or '
                                      u'end with a dot.'))
Пример #14
0
def get_recaptcha_html(error=None):
    """Returns the recaptcha input HTML."""
    server = settings.RECAPTCHA_USE_SSL and API_SERVER or SSL_API_SERVER
    options = dict(k=settings.RECAPTCHA_PUBLIC_KEY)
    if error is not None:
        options['error'] = unicode(error)
    query = url_encode(options)
    return Markup(u'''
    <script type="text/javascript">var RecaptchaOptions = %(options)s;</script>
    <script type="text/javascript" src="%(script_url)s"></script>
    <noscript>
      <div><iframe src="%(frame_url)s" height="300" width="500"></iframe></div>
      <div><textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
      <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></div>
    </noscript>
    ''') % dict(script_url='%schallenge?%s' % (server, query),
                frame_url='%snoscript?%s' % (server, query),
                options=dumps({
                    'theme': 'clean',
                    'custom_translations': {
                        'visual_challenge': _("Get a visual challenge"),
                        'audio_challenge': _("Get an audio challenge"),
                        'refresh_btn': _("Get a new challenge"),
                        'instructions_visual': _("Type the two words:"),
                        'instructions_audio': _("Type what you hear:"),
                        'help_btn': _("Help"),
                        'play_again': _("Play sound again"),
                        'cant_hear_this': _("Download sound as MP3"),
                        'incorrect_try_again': _("Incorrect. Try again.")
                    }
                }))
Пример #15
0
def get_recaptcha_html(error=None):
    """Returns the recaptcha input HTML."""
    server = settings.RECAPTCHA_USE_SSL and API_SERVER or SSL_API_SERVER
    options = dict(k=settings.RECAPTCHA_PUBLIC_KEY)
    if error is not None:
        options["error"] = unicode(error)
    query = url_encode(options)
    return u"""
    <script type="text/javascript">var RecaptchaOptions = %(options)s;</script>
    <script type="text/javascript" src="%(script_url)s"></script>
    <noscript>
      <div><iframe src="%(frame_url)s" height="300" width="500"></iframe></div>
      <div><textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
      <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></div>
    </noscript>
    """ % dict(
        script_url="%schallenge?%s" % (server, query),
        frame_url="%snoscript?%s" % (server, query),
        options=dumps(
            {
                "theme": "clean",
                "custom_translations": {
                    "visual_challenge": _("Get a visual challenge"),
                    "audio_challenge": _("Get an audio challenge"),
                    "refresh_btn": _("Get a new challenge"),
                    "instructions_visual": _("Type the two words:"),
                    "instructions_audio": _("Type what you hear:"),
                    "help_btn": _("Help"),
                    "play_again": _("Play sound again"),
                    "cant_hear_this": _("Download sound as MP3"),
                    "incorrect_try_again": _("Incorrect. Try again."),
                },
            }
        ),
    )
Пример #16
0
 def context_validate(self, data):
     has_username = bool(data['username'])
     has_email = bool(data['email'])
     if not has_username and not has_email:
         raise forms.ValidationError(
             _(u'Either username or e-mail address '
               u' is required.'))
     if has_username and has_email:
         raise forms.ValidationError(
             _(u'You have to provide either a username '
               u'or an e-mail address, not both.'))
Пример #17
0
def topic_feed(request, id, slug=None):
    """A feed for the answers to a question."""
    topic = Topic.query.eagerposts().get(id)

    # if the topic id does not exist or the topic is from a different
    # language, we abort with 404 early
    if topic is None or topic.locale != request.view_lang:
        raise NotFound()

    # make sure the slug is okay, otherwise redirect to the real one
    # to ensure URLs are unique.
    if slug is None or topic.slug != slug:
        return redirect(url_for(topic, action="feed"))

    # deleted posts cannot be seen by people without privilegs
    if topic.is_deleted and not (request.user and request.user.is_moderator):
        raise Forbidden()

    feed = AtomFeed(
        u"%s — %s" % (topic.title, settings.WEBSITE_TITLE),
        subtitle=settings.WEBSITE_TAGLINE,
        feed_url=request.url,
        url=request.url_root,
    )

    feed.add(
        topic.title,
        topic.question.rendered_text,
        content_type="html",
        author=topic.question.author.display_name,
        url=url_for(topic, _external=True),
        id=topic.guid,
        updated=topic.question.updated,
        published=topic.question.created,
    )

    for reply in topic.replies:
        if reply.is_deleted and not (request.user and request.user.is_moderator):
            continue
        title = _(u"Answer by %s") % reply.author.display_name
        if reply.is_deleted:
            title += u" " + _("(deleted)")
        feed.add(
            title,
            reply.rendered_text,
            content_type="html",
            author=reply.author.display_name,
            url=url_for(reply, _external=True),
            id=reply.guid,
            updated=reply.updated,
            created=reply.created,
        )

    return feed.get_response()
Пример #18
0
 def perform_login(self, request, username, password):
     user = User.query.filter_by(username=username).first()
     if user is None:
         raise LoginUnsucessful(_(u'No user named %s') % username)
     if not user.is_active:
         raise LoginUnsucessful(_(u'The user is not yet activated.'))
     if not user.check_password(password):
         raise LoginUnsucessful(_(u'Invalid password'))
     if user.is_banned:
         raise LoginUnsucessful(_(u'The user got banned from the system.'))
     self.set_user(request, user)
Пример #19
0
 def perform_login(self, request, username, password):
     user = User.query.filter_by(username=username).first()
     if user is None:
         raise LoginUnsucessful(_(u'No user named %s') % username)
     if not user.is_active:
         raise LoginUnsucessful(_(u'The user is not yet activated.'))
     if not user.check_password(password):
         raise LoginUnsucessful(_(u'Invalid password'))
     if user.is_banned:
         raise LoginUnsucessful(_(u'The user got banned from the system.'))
     self.set_user(request, user)
Пример #20
0
 def reset_password(self, request, user):
     if settings.REGISTRATION_REQUIRES_ACTIVATION:
         user.is_active = False
         confirmation_url = url_for('core.activate_user', email=user.email,
                                    key=user.activation_key, _external=True)
         send_email(_(u'Registration Confirmation'),
                    render_template('mails/activate_user.txt', user=user,
                                    confirmation_url=confirmation_url),
                    user.email)
         request.flash(_(u'A mail was sent to %s with a link to finish the '
                         u'registration.') % user.email)
     else:
         request.flash(_(u'You\'re registered.  You can login now.'))
Пример #21
0
def unban_user(request, user):
    """Unbans a given user."""
    user = User.query.filter_by(username=user).first()
    if user is None:
        raise NotFound()
    next = request.next_url or url_for('admin.bans')
    if not user.is_banned:
        request.flash(_(u'The user is not banned.'))
        return redirect(next)
    admin_utils.unban_user(user)
    request.flash(_(u'The user “%s” was successfully unbanned and notified.') %
                  user.username)
    return redirect(next)
Пример #22
0
Файл: kb.py Проект: Plurk/Solace
def accept(request, post):
    """Accept a post as an answer."""
    # TODO: this is currently also fired as GET if JavaScript is
    # not available.  Not very nice.
    post = Post.query.get(post)
    if post is None:
        raise NotFound()

    # just for sanity.  It makes no sense to accept the question
    # as answer.  The UI does not allow that, so the user must have
    # tampered with the data here.
    if post.is_question:
        raise BadRequest()

    # likewise you cannot accept a deleted post as answer
    if post.is_deleted:
        message = _(u'You cannot accept deleted posts as answers')
        if request.is_xhr:
            return json_response(message=message, error=True)
        request.flash(message, error=True)
        return redirect(url_for(post))

    topic = post.topic

    # if the post is already the accepted answer, we unaccept the
    # post as answer.
    if post.is_answer:
        if not request.user.can_unaccept_as_answer(post):
            message = _(u'You cannot unaccept this reply as an answer.')
            if request.is_xhr:
                return json_response(message=message, error=True)
            request.flash(message, error=True)
            return redirect(url_for(post))
        topic.accept_answer(None, request.user)
        session.commit()
        if request.is_xhr:
            return json_response(accepted=False)
        return redirect(url_for(post))

    # otherwise we try to accept the post as answer.
    if not request.user.can_accept_as_answer(post):
        message = _(u'You cannot accept this reply as answer.')
        if request.is_xhr:
            return json_response(message=message, error=True)
        request.flash(message, error=True)
        return redirect(url_for(post))
    topic.accept_answer(post, request.user)
    session.commit()
    if request.is_xhr:
        return json_response(accepted=True)
    return redirect(url_for(post))
Пример #23
0
def accept(request, post):
    """Accept a post as an answer."""
    # TODO: this is currently also fired as GET if JavaScript is
    # not available.  Not very nice.
    post = Post.query.get(post)
    if post is None:
        raise NotFound()

    # just for sanity.  It makes no sense to accept the question
    # as answer.  The UI does not allow that, so the user must have
    # tampered with the data here.
    if post.is_question:
        raise BadRequest()

    # likewise you cannot accept a deleted post as answer
    if post.is_deleted:
        message = _(u'You cannot accept deleted posts as answers')
        if request.is_xhr:
            return json_response(message=message, error=True)
        request.flash(message, error=True)
        return redirect(url_for(post))

    topic = post.topic

    # if the post is already the accepted answer, we unaccept the
    # post as answer.
    if post.is_answer:
        if not request.user.can_unaccept_as_answer(post):
            message = _(u'You cannot unaccept this reply as an answer.')
            if request.is_xhr:
                return json_response(message=message, error=True)
            request.flash(message, error=True)
            return redirect(url_for(post))
        topic.accept_answer(None, request.user)
        session.commit()
        if request.is_xhr:
            return json_response(accepted=False)
        return redirect(url_for(post))

    # otherwise we try to accept the post as answer.
    if not request.user.can_accept_as_answer(post):
        message = _(u'You cannot accept this reply as answer.')
        if request.is_xhr:
            return json_response(message=message, error=True)
        request.flash(message, error=True)
        return redirect(url_for(post))
    topic.accept_answer(post, request.user)
    session.commit()
    if request.is_xhr:
        return json_response(accepted=True)
    return redirect(url_for(post))
Пример #24
0
def activate_user(request, email, key):
    """Activates the user."""
    # the email is not unique on the database, we try all matching users.
    # Most likely it's only one, otherwise we activate the first matching.
    user = User.query.filter_by(email=email, activation_key=key).first()
    if user is not None:
        user.is_active = True
        session.commit()
        request.flash(_(u'Your account was activated.  You can '
                        u'log in now.'))
        return redirect(url_for('core.login'))
    request.flash(_(u'User activation failed.  The user is either already '
                    u'activated or you followed a wrong link.'), error=True)
    return redirect(url_for('kb.overview'))
Пример #25
0
def reset_password(request, email=None, key=None):
    """Resets the password if possible."""
    auth = get_auth_system()
    if not auth.can_reset_password:
        raise NotFound()

    form = ResetPasswordForm()
    new_password = None

    # if the user is logged in, he goes straight back to the overview
    # page.  Why would a user that is logged in (and does not anywhere
    # see a link to that page) reset the password?  Of course that does
    # not give us anything security wise because he just has to logout.
    if request.is_logged_in:
        return redirect(url_for('kb.overview'))

    # we came back from the link in the mail, try to reset the password
    if email is not None:
        for user in User.query.filter_by(email=email).all():
            if user.password_reset_key == key:
                break
        else:
            request.flash(_(u'The password-reset key expired or the link '
                            u'was invalid.'),
                          error=True)
            return redirect(url_for('core.reset_password'))
        new_password = user.set_random_password()
        session.commit()

    # otherwise validate the form
    elif request.method == 'POST' and form.validate(request.form):
        user = form.user
        reset_url = url_for('core.reset_password',
                            email=user.email,
                            key=user.password_reset_key,
                            _external=True)
        send_email(
            _(u'Reset Password'),
            render_template('mails/reset_password.txt',
                            user=user,
                            reset_url=reset_url), user.email)
        request.flash(
            _(u'A mail with a link to reset the password '
              u'was sent to “%s”') % user.email)
        return redirect(url_for('kb.overview'))

    return render_template('core/reset_password.html',
                           form=form.as_widget(),
                           new_password=new_password)
Пример #26
0
def topic_feed(request, id, slug=None):
    """A feed for the answers to a question."""
    topic = Topic.query.eagerposts().get(id)

    # if the topic id does not exist or the topic is from a different
    # language, we abort with 404 early
    if topic is None or topic.locale != request.view_lang:
        raise NotFound()

    # make sure the slug is okay, otherwise redirect to the real one
    # to ensure URLs are unique.
    if slug is None or topic.slug != slug:
        return redirect(url_for(topic, action='feed'))

    # deleted posts cannot be seen by people without privilegs
    if topic.is_deleted and not (request.user and request.user.is_moderator):
        raise Forbidden()

    feed = AtomFeed(u'%s — %s' % (topic.title, settings.WEBSITE_TITLE),
                    subtitle=settings.WEBSITE_TAGLINE,
                    feed_url=request.url,
                    url=request.url_root)

    feed.add(topic.title,
             topic.question.rendered_text,
             content_type='html',
             author=topic.question.author.display_name,
             url=url_for(topic, _external=True),
             id=topic.guid,
             updated=topic.question.updated,
             published=topic.question.created)

    for reply in topic.replies:
        if reply.is_deleted and not (request.user
                                     and request.user.is_moderator):
            continue
        title = _(u'Answer by %s') % reply.author.display_name
        if reply.is_deleted:
            title += u' ' + _('(deleted)')
        feed.add(title,
                 reply.rendered_text,
                 content_type='html',
                 author=reply.author.display_name,
                 url=url_for(reply, _external=True),
                 id=reply.guid,
                 updated=reply.updated,
                 created=reply.created)

    return feed.get_response()
Пример #27
0
def submit_comment(request, post):
    """Used by the form on `get_comments` to submit the form data to
    the database.  Returns partial data for the remote side.
    """
    if not request.is_xhr:
        raise BadRequest()
    post = Post.query.get(post)
    if post is None:
        raise NotFound()

    # not even moderators can submit comments for deleted posts.
    if post.is_deleted:
        message = _(u'You cannot submit comments for deleted posts')
        return json_response(success=False, form_errors=[message])

    form = _get_comment_form(post)
    if form.validate():
        comment = form.create_comment()
        session.commit()
        comment_box = get_macro('kb/_boxes.html', 'render_comment')
        comment_link = get_macro('kb/_boxes.html', 'render_comment_link')
        return json_response(html=comment_box(comment),
                             link=comment_link(post),
                             success=True)
    return json_response(success=False,
                         form_errors=form.as_widget().all_errors)
Пример #28
0
 def decorated(request, **kwargs):
     if not request.is_logged_in:
         if request.is_xhr:
             return not_logged_in_json_response()
         request.flash(_(u'You have to login in order to visit this page.'))
         return redirect(url_for('core.login', next=request.url))
     return f(request, **kwargs)
Пример #29
0
 def decorated(request, **kwargs):
     if not request.user.is_admin:
         message = _(u'You cannot access this resource.')
         if request.is_xhr:
             return json_response(message=message, error=True)
         raise Forbidden(message)
     return f(request, **kwargs)
Пример #30
0
def topic(request, id, slug=None):
    """Shows a topic."""
    topic = Topic.query.eagerposts().get(id)

    # if the topic id does not exist or the topic is from a different
    # language, we abort with 404 early
    if topic is None or topic.locale != request.view_lang:
        raise NotFound()

    # make sure the slug is okay, otherwise redirect to the real one
    # to ensure URLs are unique.
    if slug is None or topic.slug != slug:
        return redirect(url_for(topic))

    # deleted posts cannot be seen by people without privilegs
    if topic.is_deleted and not (request.user and request.user.is_moderator):
        raise Forbidden()

    # a form for the replies.
    form = ReplyForm(topic)

    if request.method == 'POST' and form.validate():
        reply = form.create_reply()
        session.commit()
        request.flash(_(u'Your reply was posted.'))
        return redirect(url_for(reply))

    # pull in the votes in a single query for all the posts related to the
    # topic so that we only have to fire the database once.
    if request.is_logged_in:
        request.user.pull_votes(topic.posts)

    return render_template('kb/topic.html',
                           topic=topic,
                           reply_form=form.as_widget())
Пример #31
0
def ban_user(request, user):
    """Bans a given user."""
    user = User.query.filter_by(username=user).first()
    if user is None:
        raise NotFound()
    next = request.next_url or url_for('admin.bans')
    if user.is_banned:
        request.flash(_(u'The user is already banned.'))
        return redirect(next)
    if user == request.user:
        request.flash(_(u'You cannot ban yourself.'), error=True)
        return redirect(next)
    admin_utils.ban_user(user)
    request.flash(_(u'The user “%s” was successfully banned and notified.') %
                  user.username)
    return redirect(next)
Пример #32
0
 def decorated(request, **kwargs):
     if not request.is_logged_in:
         if request.is_xhr:
             return not_logged_in_json_response()
         request.flash(_(u'You have to login in order to visit this page.'))
         return redirect(url_for('core.login', next=request.url))
     return f(request, **kwargs)
Пример #33
0
Файл: kb.py Проект: Plurk/Solace
def _topic_feed(request, title, query, order_by):
    # non moderators cannot see deleted posts, so we filter them out first
    # for moderators we mark the posts up as deleted so that
    # they can be kept apart from non-deleted ones.
    if not request.user or not request.user.is_moderator:
        query = query.filter_by(is_deleted=False)
    query = query.order_by(_topic_order[order_by])
    query = query.options(eagerload('author'), eagerload('question'))
    query = query.limit(max(0, min(50, request.args.get('num', 10, type=int))))

    feed = AtomFeed(u'%s — %s' % (title, settings.WEBSITE_TITLE),
                    subtitle=settings.WEBSITE_TAGLINE,
                    feed_url=request.url,
                    url=request.url_root)

    for topic in query.all():
        title = topic.title
        if topic.is_deleted:
            title += u' ' + _(u'(deleted)')
        feed.add(title, topic.question.rendered_text, content_type='html',
                 author=topic.author.display_name,
                 url=url_for(topic, _external=True),
                 id=topic.guid, updated=topic.last_change, published=topic.date)

    return feed.get_response()
Пример #34
0
def is_valid_username(form, value):
    """Checks if the value is a valid username."""
    if len(value) > 40:
        raise forms.ValidationError(_(u'The username is too long.'))
    if '/' in value:
        raise forms.ValidationError(
            _(u'The username may not contain '
              u'slashes.'))
    if value[:1] == '.' or value[-1:] == '.':
        raise forms.ValidationError(
            _(u'The username may not begin or '
              u'end with a dot.'))
    if ' ' in value:
        raise forms.ValidationError(
            _(u'The username may not contain '
              u'spaces.'))
Пример #35
0
def activate_user(request, email, key):
    """Activates the user."""
    # the email is not unique on the database, we try all matching users.
    # Most likely it's only one, otherwise we activate the first matching.
    user = User.query.filter_by(email=email, activation_key=key).first()
    if user is not None:
        user.is_active = True
        session.commit()
        request.flash(
            _(u'Your account was activated.  You can '
              u'log in now.'))
        return redirect(url_for('core.login'))
    request.flash(_(u'User activation failed.  The user is either already '
                    u'activated or you followed a wrong link.'),
                  error=True)
    return redirect(url_for('kb.overview'))
Пример #36
0
Файл: kb.py Проект: Plurk/Solace
def topic(request, id, slug=None):
    """Shows a topic."""
    topic = Topic.query.eagerposts().get(id)

    # if the topic id does not exist or the topic is from a different
    # language, we abort with 404 early
    if topic is None or topic.locale != request.view_lang:
        raise NotFound()

    # make sure the slug is okay, otherwise redirect to the real one
    # to ensure URLs are unique.
    if slug is None or topic.slug != slug:
        return redirect(url_for(topic))

    # deleted posts cannot be seen by people without privilegs
    if topic.is_deleted and not (request.user and request.user.is_moderator):
        raise Forbidden()

    # a form for the replies.
    form = ReplyForm(topic)

    if request.method == 'POST' and form.validate():
        reply = form.create_reply()
        session.commit()
        request.flash(_(u'Your reply was posted.'))
        return redirect(url_for(reply))

    # pull in the votes in a single query for all the posts related to the
    # topic so that we only have to fire the database once.
    if request.is_logged_in:
        request.user.pull_votes(topic.posts)

    return render_template('kb/topic.html', topic=topic,
                           reply_form=form.as_widget())
Пример #37
0
    def generate(self):
        """This method generates the pagination."""
        was_ellipsis = False
        result = []
        next = None

        for num in xrange(1, self.pages + 1):
            if num == self.page:
                was_ellipsis = False
            if num - 1 == self.page:
                next = num
            if num <= self.left_threshold or \
               num > self.pages - self.right_threshold or \
               abs(self.page - num) < self.threshold:
                if result and not was_ellipsis:
                    result.append(self.commata)
                link = self.link_func(num)
                template = num == self.page and self.active or self.normal
                result.append(template % {'url': link, 'page': num})
            elif not was_ellipsis:
                was_ellipsis = True
                result.append(self.ellipsis)

        if next is not None:
            result.append(u'<span class="sep"> </span>'
                          u'<a href="%s" class="next">%s</a>' %
                          (self.link_func(next), _(u'Next »')))

        return u''.join(result)
Пример #38
0
def _topic_feed(request, title, query, order_by):
    # non moderators cannot see deleted posts, so we filter them out first
    # for moderators we mark the posts up as deleted so that
    # they can be kept apart from non-deleted ones.
    if not request.user or not request.user.is_moderator:
        query = query.filter_by(is_deleted=False)
    query = query.order_by(_topic_order[order_by])
    query = query.options(eagerload('author'), eagerload('question'))
    query = query.limit(max(0, min(50, request.args.get('num', 10, type=int))))

    feed = AtomFeed(u'%s — %s' % (title, settings.WEBSITE_TITLE),
                    subtitle=settings.WEBSITE_TAGLINE,
                    feed_url=request.url,
                    url=request.url_root)

    for topic in query.all():
        title = topic.title
        if topic.is_deleted:
            title += u' ' + _(u'(deleted)')
        feed.add(title,
                 topic.question.rendered_text,
                 content_type='html',
                 author=topic.author.display_name,
                 url=url_for(topic, _external=True),
                 id=topic.guid,
                 updated=topic.last_change,
                 published=topic.date)

    return feed.get_response()
Пример #39
0
 def decorated(request, **kwargs):
     if not request.user.is_admin:
         message = _(u'You cannot access this resource.')
         if request.is_xhr:
             return json_response(message=message, error=True)
         raise Forbidden(message)
     return f(request, **kwargs)
Пример #40
0
Файл: kb.py Проект: Plurk/Solace
def submit_comment(request, post):
    """Used by the form on `get_comments` to submit the form data to
    the database.  Returns partial data for the remote side.
    """
    if not request.is_xhr:
        raise BadRequest()
    post = Post.query.get(post)
    if post is None:
        raise NotFound()

    # not even moderators can submit comments for deleted posts.
    if post.is_deleted:
        message = _(u'You cannot submit comments for deleted posts')
        return json_response(success=False, form_errors=[message])

    form = _get_comment_form(post)
    if form.validate():
        comment = form.create_comment()
        session.commit()
        comment_box = get_macro('kb/_boxes.html', 'render_comment')
        comment_link = get_macro('kb/_boxes.html', 'render_comment_link')
        return json_response(html=comment_box(comment),
                             link=comment_link(post),
                             success=True)
    return json_response(success=False, form_errors=form.as_widget().all_errors)
Пример #41
0
    def generate(self):
        """This method generates the pagination."""
        was_ellipsis = False
        result = []
        next = None

        for num in xrange(1, self.pages + 1):
            if num == self.page:
                was_ellipsis = False
            if num - 1 == self.page:
                next = num
            if num <= self.left_threshold or \
               num > self.pages - self.right_threshold or \
               abs(self.page - num) < self.threshold:
                if result and not was_ellipsis:
                    result.append(self.commata)
                link = self.link_func(num)
                template = num == self.page and self.active or self.normal
                result.append(template % {
                    'url':      link,
                    'page':     num
                })
            elif not was_ellipsis:
                was_ellipsis = True
                result.append(self.ellipsis)

        if next is not None:
            result.append(u'<span class="sep"> </span>'
                          u'<a href="%s" class="next">%s</a>' %
                          (self.link_func(next), _(u'Next »')))

        return u''.join(result)
Пример #42
0
def logout(request):
    """Logs the user out."""
    if request.is_logged_in:
        rv = get_auth_system().logout(request)
        if rv is not None:
            return rv
        request.flash(_(u'You were logged out.'))
    return redirect(request.next_url or url_for('kb.overview'))
Пример #43
0
def logout(request):
    """Logs the user out."""
    if request.is_logged_in:
        rv = get_auth_system().logout(request)
        if rv is not None:
            return rv
        request.flash(_(u'You were logged out.'))
    return redirect(request.next_url or url_for('kb.overview'))
Пример #44
0
 def validate_email(self, email):
     if not email:
         return
     user = User.query.filter_by(email=email).first()
     if user is None:
         raise forms.ValidationError(_(u'No user with that e-mail address found.'))
     self._check_active(user)
     self.user = user
Пример #45
0
 def validate_username(self, username):
     if not username:
         return
     user = User.query.filter_by(username=username).first()
     if user is None:
         raise forms.ValidationError(_(u'No user named “%s” found.') % username)
     self._check_active(user)
     self.user = user
Пример #46
0
def datetimeformat_filter(obj, html=True, prefixed=True):
    rv = format_datetime(obj)
    if prefixed:
        rv = _(u'on %s') % rv
    if html:
        rv = u'<span class="datetime" title="%s">%s</span>' % (
            obj.strftime('%Y-%m-%dT%H:%M:%SZ'), escape(rv))
    return Markup(rv)
Пример #47
0
 def reset_password(self, request, user):
     if settings.REGISTRATION_REQUIRES_ACTIVATION:
         user.is_active = False
         confirmation_url = url_for('core.activate_user',
                                    email=user.email,
                                    key=user.activation_key,
                                    _external=True)
         send_email(
             _(u'Registration Confirmation'),
             render_template('mails/activate_user.txt',
                             user=user,
                             confirmation_url=confirmation_url), user.email)
         request.flash(
             _(u'A mail was sent to %s with a link to finish the '
               u'registration.') % user.email)
     else:
         request.flash(_(u'You\'re registered.  You can login now.'))
Пример #48
0
def prepare_api_request(request):
    """Prepares the request for API usage."""
    request.in_api = True
    lang = request.args.get('lang')
    if lang is not None:
        if not has_section(lang):
            raise BadRequest(_(u'Unknown language'))
        request.locale = lang

    locale = request.args.get('locale')
    if locale is not None:
        try:
            locale = Locale.parse(locale)
            if not has_locale(locale):
                raise UnknownLocaleError()
        except UnknownLocaleError:
            raise BadRquest(_(u'Unknown locale'))
        request.view_lang = locale
Пример #49
0
 def validate_username(self, username):
     if not username:
         return
     user = User.query.filter_by(username=username).first()
     if user is None:
         raise forms.ValidationError(
             _(u'No user named “%s” found.') % username)
     self._check_active(user)
     self.user = user
Пример #50
0
def by_tag_feed(request, name, order_by):
    """The feed for a tag."""
    tag = Tag.query.filter((Tag.name == name)
                           & (Tag.locale == request.view_lang)).first()
    if tag is None:
        raise NotFound()
    return _topic_feed(request,
                       _(u'Questions Tagged “%s”') % tag.name, tag.topics,
                       order_by)
Пример #51
0
def prepare_api_request(request):
    """Prepares the request for API usage."""
    request.in_api = True
    lang = request.args.get('lang')
    if lang is not None:
        if not has_section(lang):
            raise BadRequest(_(u'Unknown language'))
        request.locale = lang

    locale = request.args.get('locale')
    if locale is not None:
        try:
            locale = Locale.parse(locale)
            if not has_locale(locale):
                raise UnknownLocaleError()
        except UnknownLocaleError:
            raise BadRquest(_(u'Unknown locale'))
        request.view_lang = locale
Пример #52
0
 def validate_email(self, email):
     if not email:
         return
     user = User.query.filter_by(email=email).first()
     if user is None:
         raise forms.ValidationError(
             _(u'No user with that e-mail address found.'))
     self._check_active(user)
     self.user = user
Пример #53
0
def datetimeformat_filter(obj, html=True, prefixed=True):
    rv = format_datetime(obj)
    if prefixed:
        rv = _(u'on %s') % rv
    if html:
        rv = u'<span class="datetime" title="%s">%s</span>' % (
            obj.strftime('%Y-%m-%dT%H:%M:%SZ'),
            escape(rv)
        )
    return rv
Пример #54
0
 def perform_login(self, request, openid_identifier):
     try:
         consumer = Consumer(request.session, SolaceOpenIDStore())
         auth_request = consumer.begin(openid_identifier)
     except discover.DiscoveryFailure:
         raise LoginUnsucessful(_(u'The OpenID was invalid'))
     trust_root = request.host_url
     redirect_to = url_for('core.login', openid_complete='yes',
                           next=request.next_url, _external=True)
     return redirect(auth_request.redirectURL(trust_root, redirect_to))
Пример #55
0
Файл: kb.py Проект: Plurk/Solace
def by_tag_feed(request, name, order_by):
    """The feed for a tag."""
    tag = Tag.query.filter(
        (Tag.name == name) &
        (Tag.locale == request.view_lang)
    ).first()
    if tag is None:
        raise NotFound()
    return _topic_feed(request, _(u'Questions Tagged “%s”') % tag.name,
                       tag.topics, order_by)
Пример #56
0
def reset_password(request, email=None, key=None):
    """Resets the password if possible."""
    auth = get_auth_system()
    if not auth.can_reset_password:
        raise NotFound()

    form = ResetPasswordForm()
    new_password = None

    # if the user is logged in, he goes straight back to the overview
    # page.  Why would a user that is logged in (and does not anywhere
    # see a link to that page) reset the password?  Of course that does
    # not give us anything security wise because he just has to logout.
    if request.is_logged_in:
        return redirect(url_for('kb.overview'))

    # we came back from the link in the mail, try to reset the password
    if email is not None:
        for user in User.query.filter_by(email=email).all():
            if user.password_reset_key == key:
                break
        else:
            request.flash(_(u'The password-reset key expired or the link '
                            u'was invalid.'), error=True)
            return redirect(url_for('core.reset_password'))
        new_password = user.set_random_password()
        session.commit()

    # otherwise validate the form
    elif request.method == 'POST' and form.validate(request.form):
        user = form.user
        reset_url = url_for('core.reset_password', email=user.email,
                            key=user.password_reset_key, _external=True)
        send_email(_(u'Reset Password'),
                   render_template('mails/reset_password.txt', user=user,
                                   reset_url=reset_url), user.email)
        request.flash(_(u'A mail with a link to reset the password '
                        u'was sent to “%s”') % user.email)
        return redirect(url_for('kb.overview'))

    return render_template('core/reset_password.html', form=form.as_widget(),
                           new_password=new_password)
Пример #57
0
def new(request):
    """The new-question form."""
    form = QuestionForm()

    if request.method == 'POST' and form.validate():
        topic = form.create_topic()
        session.commit()
        request.flash(_(u'Your question was posted.'))
        return redirect(url_for(topic))

    return render_template('kb/new.html', form=form.as_widget())
Пример #58
0
    def edit_profile(self, request):
        """Invoked like a view and does the profile handling."""
        form = self.get_edit_profile_form(request.user)

        if request.method == 'POST' and form.validate():
            request.flash(_(u'Your profile was updated'))
            form.apply_changes()
            session.commit()
            return form.redirect(form.user)

        return self.render_edit_profile_template(request, form)
Пример #59
0
def ban_user(user):
    """Bans a user if it was not already banned.  This also sends the
    user an email that he was banned.
    """
    if user.is_banned:
        return

    user.is_banned = True
    send_email(_(u'User account banned'),
               render_template('mails/user_banned.txt', user=user),
               user.email)
    session.commit()
Пример #60
0
 def perform_login(self, request, openid_identifier):
     try:
         consumer = Consumer(request.session, SolaceOpenIDStore())
         auth_request = consumer.begin(openid_identifier)
     except discover.DiscoveryFailure:
         raise LoginUnsucessful(_(u'The OpenID was invalid'))
     trust_root = request.host_url
     redirect_to = url_for('core.login',
                           openid_complete='yes',
                           next=request.next_url,
                           _external=True)
     return redirect(auth_request.redirectURL(trust_root, redirect_to))