def reset(): "Reset the password for a user account and send email." if not flask.current_app.config["MAIL_SERVER"]: utils.flash_error("Cannot reset password; no email server defined.") return flask.redirect(flask.url_for("home")) if utils.http_GET(): email = flask.request.args.get("email") or "" email = email.lower() return flask.render_template("user/reset.html", email=email) elif utils.http_POST(): try: user = get_user(email=flask.request.form["email"]) if user is None: raise KeyError if user["status"] != constants.ENABLED: raise KeyError except KeyError: pass else: with UserSaver(user) as saver: saver.set_password() send_password_code(user, "password reset") utils.get_logger().info(f"reset user {user['username']}") utils.flash_message( "An email has been sent if the user account exists.") return flask.redirect(flask.url_for("home"))
def do_login(username, password): """Set the session cookie if successful login. Raise ValueError if some problem. """ user = get_user(username=username) if user is None: raise ValueError if not check_password_hash(user["password"], password): raise ValueError if user["status"] != constants.ENABLED: raise ValueError flask.session["username"] = user["username"] flask.session.permanent = True utils.get_logger().info(f"logged in {user['username']}")
def disable(username): "Disable the given user account." user = get_user(username=username) if user is None: utils.flash_error("No such user.") return flask.redirect(flask.url_for("home")) if user["username"] == flask.g.current_user["username"]: utils.flash_error("You cannot disable yourself.") return flask.redirect(flask.url_for("home")) with UserSaver(user) as saver: saver.set_status(constants.DISABLED) utils.get_logger().info(f"disabled user {username}") return flask.redirect(flask.url_for(".display", username=username))
def password(): "Set the password for a user account, and login user." if utils.http_GET(): return flask.render_template( "user/password.html", username=flask.request.args.get("username"), code=flask.request.args.get("code")) elif utils.http_POST(): try: code = "" try: username = flask.request.form.get("username") or "" if not username: raise ValueError user = get_user(username=username) if user is None: raise ValueError if flask.g.am_admin and \ flask.g.current_user["username"] != username: pass # No check for either code or current password. elif flask.current_app.config["MAIL_SERVER"]: code = flask.request.form.get("code") or "" if user["password"] != f"code:{code}": raise ValueError else: password = flask.request.form.get("current_password") or "" if not check_password_hash(user["password"], password): raise ValueError except ValueError: if flask.current_app.config["MAIL_SERVER"]: raise ValueError("No such user or wrong code.") else: raise ValueError("No such user or wrong password.") password = flask.request.form.get("password") or "" if len(password) < flask.current_app.config["MIN_PASSWORD_LENGTH"]: raise ValueError("Too short password.") if not flask.current_app.config["MAIL_SERVER"]: if password != flask.request.form.get("confirm_password"): raise ValueError("Wrong password entered; confirm failed.") except ValueError as error: utils.flash_error(str(error)) return flask.redirect( flask.url_for(".password", username=username, code=code)) else: with UserSaver(user) as saver: saver.set_password(password) utils.get_logger().info(f"password user {user['username']}") if not flask.g.current_user: do_login(username, password) return flask.redirect(flask.url_for("home"))
def enable(username): "Enable the given user account." user = get_user(username=username) if user is None: utils.flash_error("No such user.") return flask.redirect(flask.url_for("home")) if user["username"] == flask.g.current_user["username"]: utils.flash_error("You cannot enable yourself.") return flask.redirect(flask.url_for("home")) with UserSaver(user) as saver: saver.set_status(constants.ENABLED) saver.set_apikey() # Better safety to set/change API key on enable. if user["password"][:5] == "code:" and \ flask.current_app.config["MAIL_SERVER"]: send_password_code(user, "enabled") utils.get_logger().info(f"enabled user {username}") return flask.redirect(flask.url_for(".display", username=username))
def register(): "Register a new user account." if not flask.g.am_admin and not flask.current_app.config["USER_REGISTER"]: utils.flash_error("Only admin can register new user accounts.") return flask.redirect(flask.url_for("home")) if utils.http_GET(): return flask.render_template("user/register.html") elif utils.http_POST(): try: with UserSaver() as saver: saver.set_username(flask.request.form.get("username")) saver.set_email(flask.request.form.get("email")) saver.set_role(constants.USER) if flask.g.am_admin: saver.set_password( flask.request.form.get("password") or None) saver.set_apikey() saver.set_status(constants.ENABLED) else: saver.set_password() user = saver.doc except ValueError as error: utils.flash_error(error) return flask.redirect(flask.url_for(".register")) utils.get_logger().info(f"registered user {user['username']}") if user["status"] == constants.ENABLED: # Directly enabled and code set. Send code to the user. if user["password"][:5] == "code:": send_password_code(user, "registration") utils.get_logger().info(f"enabled user {user['username']}") utils.flash_message("User account created; check your email.") # Directly enabled and password set. No email to anyone. else: utils.get_logger().info(f"enabled user {user['username']}" " and set password") utils.flash_message("User account created and password set.") # Was set to 'pending'; send email to admins. else: admins = get_users(constants.ADMIN, status=constants.ENABLED) emails = [u["email"] for u in admins] message = flask_mail.Message("DataGraphics user account pending", recipients=emails) url = flask.url_for(".display", username=user["username"], _external=True) message.body = f"To enable the user account, go to {url}" utils.mail.send(message) utils.get_logger().info(f"pending user {user['username']}") utils.flash_message("User account created; an email will be sent" " when it has been enabled by the admin.") return flask.redirect(flask.url_for("home"))
def login(): """Login to a user account. Creates the admin user specified in the settings.json, if not done. """ app = flask.current_app if app.config.get("ADMIN_USER"): user = get_user(username=app.config["ADMIN_USER"]["username"]) if user is None: try: with UserSaver() as saver: saver.set_username(app.config["ADMIN_USER"]["username"]) saver.set_email(app.config["ADMIN_USER"]["email"]) saver.set_role(constants.ADMIN) saver.set_status(constants.ENABLED) saver.set_password(app.config["ADMIN_USER"]["password"]) utils.get_logger().info("Created admin user " + app.config["ADMIN_USER"]["username"]) except ValueError as error: utils.get_logger().error("Could not create admin user;" " misconfiguration.") if utils.http_GET(): return flask.render_template("user/login.html", next=flask.request.args.get("next")) if utils.http_POST(): username = flask.request.form.get("username") password = flask.request.form.get("password") try: if username and password: do_login(username, password) else: raise ValueError try: next = flask.request.form["next"] except KeyError: return flask.redirect(flask.url_for("home")) else: return flask.redirect(next) except ValueError: utils.flash_error("Invalid user or password, or account disabled.") return flask.redirect(flask.url_for(".login"))
def edit(username): "Edit the user display. Or delete the user." user = get_user(username=username) if user is None: utils.flash_error("No such user.") return flask.redirect(flask.url_for("home")) if not am_admin_or_self(user): utils.flash_error("Access not allowed.") return flask.redirect(flask.url_for("home")) if utils.http_GET(): return flask.render_template("user/edit.html", user=user, deletable=is_empty(user)) elif utils.http_POST(): with UserSaver(user) as saver: if flask.g.am_admin: email = flask.request.form.get("email") if email != user["email"]: saver.set_email(email) if am_admin_and_not_self(user): saver.set_role(flask.request.form.get("role")) if flask.request.form.get("apikey"): saver.set_apikey() return flask.redirect( flask.url_for(".display", username=user["username"])) elif utils.http_DELETE(): if not is_empty(user): utils.flash_error("Cannot delete non-empty user account.") return flask.redirect(flask.url_for(".display", username=username)) for log in utils.get_logs(user["_id"], cleanup=False): flask.g.db.delete(log) flask.g.db.delete(user) utils.flash_message(f"Deleted user {username}.") utils.get_logger().info(f"deleted user {username}") if flask.g.am_admin: return flask.redirect(flask.url_for(".all")) else: return flask.redirect(flask.url_for("home"))
def init(app): "Initialize; update CouchDB design document." db = utils.get_db(app=app) logger = utils.get_logger(app) if db.put_design("graphics", DESIGN_DOC): logger.info("Updated graphics design document.")
def logout(): "Logout from the user account." username = flask.session.pop("username", None) if username: utils.get_logger().info(f"logged out {username}") return flask.redirect(flask.url_for("home"))