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)
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)
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)
def sections(request): """Shows a page where all sections are listed for the user to select one. """ if len(settings.LANGUAGE_SECTIONS) == 1: return redirect(url_for("kb.overview", lang_code=settings.LANGUAGE_SECTIONS[0])) return render_template("kb/sections.html", languages=list_sections())
def post_revisions(request, id): """Shows all post revisions and a diff of the text.""" post = Post.query.get(id) if post is None or post.topic.locale != request.view_lang: raise NotFound() if post.is_deleted and not (request.user and request.user.is_moderator): raise Forbidden() revisions = [{ 'id': None, 'latest': True, 'date': post.updated, 'editor': post.editor or post.author, 'text': post.text }] + [{ 'id': revision.id, 'latest': False, 'date': revision.date, 'editor': revision.editor, 'text': revision.text } for revision in post.revisions.order_by(PostRevision.date.desc())] last_text = None for revision in reversed(revisions): if last_text is not None: revision['diff'] = format_creole_diff(last_text, revision['text']) else: revision['diff'] = format_creole(revision['text']) last_text = revision['text'] return render_template('kb/post_revisions.html', post=post, revisions=revisions)
def tags(request): """Shows the tag-cloud.""" tags = Tag.query.filter((Tag.tagged > 0) & (Tag.locale == request.view_lang)).order_by( Tag.tagged.desc()).limit(40).all() tags.sort(key=lambda x: x.name.lower()) return render_template('kb/tags.html', tags=tags)
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())
def profile(request, username): """Shows a users's profile.""" user = User.query.filter_by(username=username).first() if user is None: raise NotFound() topics = Topic.query.eagerposts().filter_by(author=user) \ .order_by(Topic.votes.desc()).limit(4).all() replies = Post.query.options(eagerload('topic')) \ .filter_by(is_question=False, author=user) \ .order_by(Post.votes.desc()).limit(15).all() # count and sort all badges badges = {} for badge in user.badges: badges[badge] = badges.get(badge, 0) + 1 badges = sorted(badges.items(), key=lambda x: (-x[1], x[0].name.lower())) # we only create the active_in list if there are multiple sections if len(settings.LANGUAGE_SECTIONS) > 1: active_in = sorted(user.activities.items(), key=lambda x: x[1].counter, reverse=True) else: active_in = None return render_template('users/profile.html', user=user, active_in=active_in, topics=topics, replies=replies, badges=badges)
def sections(request): """Shows a page where all sections are listed for the user to select one. """ if len(settings.LANGUAGE_SECTIONS) == 1: return redirect( url_for('kb.overview', lang_code=settings.LANGUAGE_SECTIONS[0])) return render_template('kb/sections.html', languages=list_sections())
def tags(request): """Shows the tag-cloud.""" tags = Tag.query.filter( (Tag.tagged > 0) & (Tag.locale == request.view_lang) ).order_by(Tag.tagged.desc()).limit(40).all() tags.sort(key=lambda x: x.name.lower()) return render_template('kb/tags.html', tags=tags)
def test_simple_render(self): """Basic Template rendering.""" me = models.User('me', '*****@*****.**') rv = templating.render_template('mails/activate_user.txt', user=me, confirmation_url='MEH') self.assert_('Hi me!' in rv) self.assert_('MEH' in rv) self.assert_('See you soon on Solace' in rv)
def show_badge(request, identifier): """Shows a single badge.""" badge = badges_by_id.get(identifier) if badge is None: raise NotFound() user_badges = UserBadge.query.filter_by(badge=badge) \ .order_by(UserBadge.awarded.desc()).limit(20).all() return render_template('badges/show_badge.html', badge=badge, user_badges=user_badges)
def edit_users(request): """Edit a user.""" pagination = Pagination(request, User.query, request.args.get('page', type=int)) form = EditUserRedirectForm() if request.method == 'POST' and form.validate(): return redirect(url_for('admin.edit_user', user=form.user.username)) return render_template('admin/edit_users.html', pagination=pagination, users=pagination.get_objects(), form=form.as_widget())
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)
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())
def edit_user(request, user): """Edits a user.""" user = User.query.filter_by(username=user).first() if user is None: raise NotFound() form = EditUserForm(user) if request.method == 'POST' and form.validate(): form.apply_changes() request.flash(_(u'The user details where changed.')) session.commit() return form.redirect('admin.edit_users') return render_template('admin/edit_user.html', form=form.as_widget(), user=user)
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()
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.'))
def bans(request): """Manages banned users""" form = BanUserForm() query = User.query.filter_by(is_banned=True) pagination = Pagination(request, query, request.args.get('page', type=int)) if request.method == 'POST' and form.validate(): admin_utils.ban_user(form.user) request.flash(_(u'The user “%s” was successfully banned and notified.') % form.user.username) return form.redirect('admin.bans') return render_template('admin/bans.html', pagination=pagination, banned_users=pagination.get_objects(), form=form.as_widget())
def unban_user(user): """Unbans the user. What this actually does is sending the user an email with a link to reactivate his account. For reactivation he has to give himself a new password. """ if not user.is_banned: return if settings.REQUIRE_NEW_PASSWORD_ON_UNBAN: user.is_active = False user.is_banned = False reset_url = url_for('core.reset_password', email=user.email, key=user.password_reset_key, _external=True) send_email(_(u'Your ban was lifted'), render_template('mails/user_unbanned.txt', user=user, reset_url=reset_url), user.email) session.commit()
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.'))
def _topic_list(template_name, request, query, order_by, **context): """Helper for views rendering a topic list.""" # non moderators cannot see deleted posts, so we filter them out first # for moderators the template marks 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]) # optimize the query for the template. The template needs the author # of the topic as well (but not the editor) which is not eagerly # loaded by default. query = query.options(eagerload('author')) pagination = Pagination(request, query, request.args.get('page', type=int)) return render_template(template_name, pagination=pagination, order_by=order_by, topics=pagination.get_objects(), **context)
def delete_post(request, id): post = Post.query.get(id) # sanity checks if not request.user.is_moderator: raise Forbidden() elif post.is_deleted: return redirect(url_for(post)) form = EmptyForm() if request.method == "POST" and form.validate(): if "yes" in request.form: post.delete() session.commit() request.flash(_("The post was deleted")) return redirect(url_for(post)) return render_template("kb/delete_post.html", post=post, form=form.as_widget())
def get_comments(request, post, form=None): """Returns the partial comment template. This is intended to be used on by XHR requests. """ if not request.is_xhr: raise BadRequest() post = Post.query.get(post) if post is None: raise NotFound() # sanity check. This should not happen because the UI does not provide # a link to retrieve the comments, but it could happen if the user # accesses the URL directly or if he requests the comments to be loaded # after a moderator deleted the post. if post.is_deleted and not (request.user and request.user.is_moderator): raise Forbidden() form = _get_comment_form(post) return json_response(html=render_template("kb/_comments.html", post=post, form=form.as_widget()))
def userlist(request, locale=None): """Displays list of users. Optionally a locale identifier can be passed in that replaces the default "all users" query. This is used by the userlist form the knowledge base that forwards the call here. """ query = User.query if locale is not None: # if we just have one language, we ignore that there is such a thing # as being active in a section of the webpage and redirect to the # general user list. if len(settings.LANGUAGE_SECTIONS) == 1: return redirect(url_for('users.userlist')) locale = Locale.parse(locale) query = query.active_in(locale) query = query.order_by(User.reputation.desc()) pagination = Pagination(request, query, request.args.get('page', type=int)) return render_template('users/userlist.html', pagination=pagination, users=pagination.get_objects(), locale=locale, sections=list_sections())
def get_comments(request, post, form=None): """Returns the partial comment template. This is intended to be used on by XHR requests. """ if not request.is_xhr: raise BadRequest() post = Post.query.get(post) if post is None: raise NotFound() # sanity check. This should not happen because the UI does not provide # a link to retrieve the comments, but it could happen if the user # accesses the URL directly or if he requests the comments to be loaded # after a moderator deleted the post. if post.is_deleted and not (request.user and request.user.is_moderator): raise Forbidden() form = _get_comment_form(post) return json_response(html=render_template( 'kb/_comments.html', post=post, form=form.as_widget()))
def delete_post(request, id): post = Post.query.get(id) # sanity checks if not request.user.is_moderator: raise Forbidden() elif post.is_deleted: return redirect(url_for(post)) form = EmptyForm() if request.method == 'POST' and form.validate(): if 'yes' in request.form: post.delete() session.commit() request.flash(_('The post was deleted')) return redirect(url_for(post)) return render_template('kb/delete_post.html', post=post, form=form.as_widget())
def register(self, request): """Called like a view function with only the request. Has to do the register heavy-lifting. Auth systems that only use the internal database do not have to override this method. Implementers that override this function *have* to call `after_register` to finish the registration of the new user. If `before_register` is unnused it does not have to be called, otherwise as documented. """ rv = self.before_register(request) if rv is not None: return rv form = RegistrationForm() if request.method == 'POST' and form.validate(): user = User(form['username'], form['email'], form['password']) self.after_register(request, user) session.commit() if rv is not None: return rv return form.redirect('kb.overview') return render_template('core/register.html', form=form.as_widget())
def first_login(self, request): """Until the openid information is removed from the session, this view will be use to create the user account based on the openid url. """ identity_url = request.session.get('openid') if identity_url is None: return redirect(url_for('core.login')) if request.is_logged_in: del request.session['openid'] return redirect(request.next_url or url_for('kb.overview')) form = OpenIDRegistrationForm() if request.method == 'POST' and form.validate(): user = User(form['username'], form['email']) user.openid_logins.add(identity_url) self.after_register(request, user) session.commit() del request.session['openid'] self.set_user_checked(request, user) return self.redirect_back(request) return render_template('core/register_openid.html', form=form.as_widget(), identity_url=identity_url)
def debug_dump(obj): """Dumps the data into a HTML page for debugging.""" dump = _escaped_newline_re.sub( '\n', simplejson.dumps(obj, ensure_ascii=False, indent=2)) return render_template('api/debug_dump.html', dump=dump)
def render_login_template(self, request, form): return render_template('core/login_openid.html', form=form.as_widget())
def forbidden(request): """Shows a forbidden page.""" return Response(render_template('core/forbidden.html'), status=401, mimetype='text/html')
def help(request): return render_template('api/help.html', methods=list_api_methods(), xmlns=XML_NS)
def render_login_template(self, request, form): """Renders the login template""" return render_template('core/login.html', form=form.as_widget())
def render_edit_profile_template(self, request, form): """Renders the template for the profile edit page.""" return render_template('users/edit_profile.html', form=form.as_widget())
def bad_request(request): """Shows a "bad request" page.""" return Response(render_template('core/bad_request.html'), status=400, mimetype='text/html')
def about(request): """Just shows a simple about page that explains the system.""" return render_template('core/about.html')
def not_found(request): """Shows a not found page.""" return Response(render_template('core/not_found.html'), status=404, mimetype='text/html')
def status(request): """Displays system statistics such as the database settings.""" return render_template('admin/status.html', active_settings=describe_settings())
def no_javascript(request): """Displays a page to the user that tells him to enable JavaScript. Some non-critical functionality requires it. """ return render_template('core/no_javascript.html')
def debug_dump(obj): """Dumps the data into a HTML page for debugging.""" dump = _escaped_newline_re.sub('\n', simplejson.dumps(obj, ensure_ascii=False, indent=2)) return render_template('api/debug_dump.html', dump=dump)