diff --git a/app/templates/admin/list.html b/app/templates/admin/list.html new file mode 100644 index 00000000..af845a9d --- /dev/null +++ b/app/templates/admin/list.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block title %} + Admin Tools +{% endblock %} + +{% block content %} + +{% endblock %} diff --git a/app/templates/admin/switch_user_page.html b/app/templates/admin/switch_user_page.html new file mode 100644 index 00000000..01497866 --- /dev/null +++ b/app/templates/admin/switch_user_page.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %} + Switch User +{% endblock %} + +{% block content %} + {% from "macros/forms.html" import render_field, render_submit_field %} +
+ {{ form.hidden_tag() }} + + {{ render_field(form.username) }} + {{ render_submit_field(form.submit) }} +
+{% endblock %} diff --git a/app/views/__init__.py b/app/views/__init__.py index cd4f0e65..dba81adf 100644 --- a/app/views/__init__.py +++ b/app/views/__init__.py @@ -30,4 +30,4 @@ def home_page(): packages = Package.query.filter_by(approved=True).all() return render_template("index.html", packages=packages) -from . import users, githublogin, packages, sass, tasks +from . import users, githublogin, packages, sass, tasks, admin diff --git a/app/views/admin.py b/app/views/admin.py new file mode 100644 index 00000000..0c6364d4 --- /dev/null +++ b/app/views/admin.py @@ -0,0 +1,37 @@ +from flask import * +from flask_user import * +from flask.ext import menu +from app import app +from app.models import * +from flask_wtf import FlaskForm +from wtforms import * +from .utils import loginUser, rank_required + +@menu.register_menu(app, ".admin", "Admin", order=30, + visible_when=lambda: current_user.rank.atLeast(UserRank.ADMIN)) +@app.route("/admin/") +@rank_required(UserRank.ADMIN) +def admin_page(): + return render_template("admin/list.html") + +class SwitchUserForm(FlaskForm): + username = StringField("Username") + submit = SubmitField("Switch") + + +@app.route("/admin/switchuser/", methods=["GET", "POST"]) +@rank_required(UserRank.ADMIN) +def switch_user_page(): + form = SwitchUserForm(formdata=request.form) + if request.method == "POST" and form.validate(): + user = User.query.filter_by(username=form["username"].data).first() + if user is None: + flash("Unable to find user", "error") + elif loginUser(user): + return redirect(url_for("user_profile_page", username=current_user.username)) + else: + flash("Unable to login as user", "error") + + + # Process GET or invalid POST + return render_template("admin/switch_user_page.html", form=form) diff --git a/app/views/githublogin.py b/app/views/githublogin.py index 30cb61f6..875f1b27 100644 --- a/app/views/githublogin.py +++ b/app/views/githublogin.py @@ -5,63 +5,12 @@ import flask_menu as menu from flask_github import GitHub from app import app, github from app.models import * - +from .utils import loginUser @app.route("/user/github/start/") def github_signin_page(): return github.authorize("") - -def _do_login_user(user, remember_me=False): - def _call_or_get(v): - if callable(v): - return v() - else: - return v - - # User must have been authenticated - if not user: - return False - - user.active = True - if not user.rank.atLeast(UserRank.NEW_MEMBER): - user.rank = UserRank.NEW_MEMBER - - db.session.commit() - - # Check if user account has been disabled - if not _call_or_get(user.is_active): - flash("Your account has not been enabled.", "error") - return False - - # Check if user has a confirmed email address - user_manager = current_app.user_manager - if user_manager.enable_email and user_manager.enable_confirm_email \ - and not current_app.user_manager.enable_login_without_confirm_email \ - and not user.has_confirmed_email(): - url = url_for("user.resend_confirm_email") - flash("Your email address has not yet been confirmed", "error") - return False - - # Use Flask-Login to sign in user - login_user(user, remember=remember_me) - signals.user_logged_in.send(current_app._get_current_object(), user=user) - - flash("You have signed in successfully.", "success") - - return True - - - -def _login_user(user): - user_mixin = None - if user_manager.enable_username: - user_mixin = user_manager.find_user_by_username(user.username) - - return _do_login_user(user_mixin, False) - - - @app.route("/user/github/callback/") @github.authorized_handler def github_authorized(oauth_token): @@ -99,12 +48,12 @@ def github_authorized(oauth_token): db.session.add(newUser) db.session.commit() - if not _login_user(newUser): + if not loginUser(newUser): raise Exception("Unable to login as user we just created") flash("Created an account", "success") return redirect(url_for("user_profile_page", username=username)) - elif _login_user(userByGithub): + elif loginUser(userByGithub): return redirect(next_url or url_for("home_page")) else: flash("Authorization failed [err=gh-login-failed]", "danger") diff --git a/app/views/utils.py b/app/views/utils.py index 488e32e6..f22e8740 100644 --- a/app/views/utils.py +++ b/app/views/utils.py @@ -1,4 +1,7 @@ -from flask import request, flash +from flask import request, flash, abort +from flask_user import * +from flask_login import login_user, logout_user +from app.models import * from app import app import random, string, os @@ -29,3 +32,62 @@ def doFileUpload(file, allowedExtensions, fileTypeName): filename = randomString(10) + "." + ext file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename)) return "/uploads/" + filename + + +def _do_login_user(user, remember_me=False): + def _call_or_get(v): + if callable(v): + return v() + else: + return v + + # User must have been authenticated + if not user: + return False + + user.active = True + if not user.rank.atLeast(UserRank.NEW_MEMBER): + user.rank = UserRank.NEW_MEMBER + + db.session.commit() + + # Check if user account has been disabled + if not _call_or_get(user.is_active): + flash("Your account has not been enabled.", "error") + return False + + # Check if user has a confirmed email address + user_manager = current_app.user_manager + if user_manager.enable_email and user_manager.enable_confirm_email \ + and not current_app.user_manager.enable_login_without_confirm_email \ + and not user.has_confirmed_email(): + url = url_for("user.resend_confirm_email") + flash("Your email address has not yet been confirmed", "error") + return False + + # Use Flask-Login to sign in user + login_user(user, remember=remember_me) + signals.user_logged_in.send(current_app._get_current_object(), user=user) + + flash("You have signed in successfully.", "success") + + return True + +def loginUser(user): + user_mixin = None + if user_manager.enable_username: + user_mixin = user_manager.find_user_by_username(user.username) + + return _do_login_user(user_mixin, False) + +def rank_required(rank): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if not current_user.rank.atLeast(rank): + abort(403) + + return f(*args, **kwargs) + + return decorated_function + return decorator