from __future__ import annotations import os from authlib.integrations.flask_client import OAuth from flask import flash from flask import Flask from flask import jsonify from flask import redirect from flask import render_template from flask import request from flask import session from flask import url_for from flask_security import current_user from flask_security import login_user from flask_security import logout_user from flask_security import Security from flask_security import SQLAlchemySessionUserDatastore from QuizTheWord import database from QuizTheWord.admin import admin app = Flask(__name__) environment_configuration = os.environ.get('CONFIGURATION_SETUP', "QuizTheWord.config.Development") with app.app_context(): app.config.from_object(environment_configuration) user_datastore = SQLAlchemySessionUserDatastore(database.get_session(), database.User, database.Role) security = Security(app, user_datastore, False) CONF_URL = "https://accounts.google.com/.well-known/openid-configuration" oauth = OAuth(app) oauth.register( name="google", server_metadata_url=CONF_URL, client_kwargs={ "scope": "openid email profile", }, ) app.register_blueprint(admin.Admin) @app.context_processor def func(): if current_user.is_authenticated: data = { "user_authenticated": True, "has_admin_access": current_user.has_permission("admin_site_access"), "is_admin": current_user.has_role("admin"), } else: data = { "user_authenticated": False, "has_admin_access": False, "is_admin": False, } return data @app.route("/") def index(): return multiple_choice_category() @app.route("/category/hidden_answer") def hidden_answer_category(): easy = database.get_random_hidden_answer(1) medium = database.get_random_hidden_answer(2) hard = database.get_random_hidden_answer(3) return render_template( "hidden_answer.html", title="Hidden Answer", easy=easy, medium=medium, hard=hard, ) @app.route("/category/multiple_choice") def multiple_choice_category(): easy = database.get_random_multiple_choice(1) medium = database.get_random_multiple_choice(2) hard = database.get_random_multiple_choice(3) return render_template( "multiple_choice.html", title="Multiple Choice", easy=easy, medium=medium, hard=hard, ) @app.route("/category/multiple_choice/check_answer", methods=["GET"]) def check_answer(): question_id = request.args.get("question_id", type=int) answer = request.args.get("answer", type=str) if question_id is not None and answer is not None: return jsonify(database.check_answer(question_id, answer)) @app.route("/category/hidden_answer/next_question") def next_hidden_answer(): if "hidden_answer_ids" not in session: session["hidden_answer_ids"] = [] difficulty = request.args.get("difficulty", 1, int) next_question = database.next_hidden_answer(session["hidden_answer_ids"], difficulty) if next_question: session["hidden_answer_ids"].append(next_question.question_id) session.modified = True return jsonify(next_question.get_dict()) else: session.pop("hidden_answer_ids", None) return jsonify(None), 204 @app.route("/category/multiple_choice/next_question") def next_multiple_choice(): if "multiple_choice_ids" not in session: session["multiple_choice_ids"] = [] difficulty = request.args.get("difficulty", 1, int) next_question = database.next_multiple_choice(session["multiple_choice_ids"], difficulty) if next_question: session["multiple_choice_ids"].append(next_question.question_id) session.modified = True return jsonify(next_question.get_dict_shuffled_choices()) else: session.pop("multiple_choice_ids", None) return jsonify(None), 204 def get_auth_url(redirect_uri, **kwargs): rv = oauth.google.create_authorization_url(redirect_uri, **kwargs) if oauth.google.request_token_url: request_token = rv.pop('request_token', None) oauth.google._save_request_token(request_token) oauth.google.save_authorize_data(request, redirect_uri=redirect_uri, **rv) return rv["url"] @app.route("/login", methods=["GET", "POST"]) def login(): redirect_uri = url_for("auth_google", _external=True) google_url = get_auth_url(redirect_uri) next_page = request.args.get("next", default=url_for("index")) if request.method == "POST": email = request.form.get("email") password = request.form.get("password") remember = request.args.get("remember") user = user_datastore.find_user(email=email) if user is None or not user.check_password(password): flash("invalid email or password") return redirect(url_for("login")) login_user(user, remember=remember) return redirect(next_page) return render_template("login.html", title="login", google_url=google_url) @app.route("/login/auth/google") def auth_google(): token = oauth.google.authorize_access_token() user = oauth.google.parse_id_token(token) unique_id = user["sub"] email = user["email"] username = user["given_name"] user = database.get_user(google_id=unique_id) if user is not None: login_user(user) else: user = database.add_user(email, None, username, google_id=unique_id) if user is not None: login_user(user) else: flash("That email is already in use. Login with that email or choose a different account.") return redirect(url_for("login")) return redirect(url_for("index")) @app.route("/register", methods=["GET", "POST"]) def register(): if request.method == "POST": email = request.form.get("email") password = request.form.get("password") user = database.add_user(email, password) if user is None: flash("email already in use") return redirect(url_for("register")) login_user(user) return redirect(url_for("index")) return render_template("register.html") @app.route("/logout") def logout(): logout_user() return redirect(url_for("index")) @app.errorhandler(404) def error_404(e): print(e) return render_template("error.html", error_msg="The requested page can not be found.", error_code=404), 404 @app.errorhandler(500) def error_500(e): print(e) msg = "There was an error with the server." if app.config["DEBUG"]: msg = e return render_template("error.html", error_msg=msg, error_code=500), 500 if __name__ == "__main__": with app.app_context(): database.init_db() app.run()