diff options
Diffstat (limited to 'server.py')
-rw-r--r-- | server.py | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/server.py b/server.py new file mode 100644 index 0000000..013089a --- /dev/null +++ b/server.py @@ -0,0 +1,144 @@ +from flask import Flask, Response, render_template, request, session, redirect, url_for +import functools +import re +from scripts.database.mongo import mongo_database +from scripts.scraping.scraper import scrape +from scripts.recipes.handle_recipes import recipe_exists, add_single_recipe, get_all_recipes, get_single_recipe, get_facets, delete_single_recipe, search_recipes +from scripts.users.handle_users import user_exists, authenticate_user, add_user +from flask_bcrypt import Bcrypt + +# Bcrypt.check_password_hash(hashed_password, "eligible password") +app = Flask(__name__) +bcrypt = Bcrypt(app) +app.config["TEMPLATES_AUTO_RELOAD"] = True +app.secret_key = 'wdkbahjfbqb' + +# Decorator function to check for username in session to protect routes +def login_required(func): + @functools.wraps(func) + def secure_function(*args, **kwargs): + if "username" not in session: + return redirect(url_for("login")) + return func(*args, **kwargs) + return secure_function + +# Pages +@app.route("/home") +@login_required +def home_page(): + tags = get_facets(session["username"]) + all_recipes = get_all_recipes(session["username"]) + return render_template("/pages/home.html",recipes=all_recipes, facets=tags) + +@app.route("/") +def landing_page(): + return render_template("/pages/landing.html") + +@app.route("/recipe/<recipe_id>") +@login_required +def single_recipe_page(recipe_id): + recipe_details = get_single_recipe(recipe_id) + return render_template("/pages/single-recipe.html", single_recipe=recipe_details) + +@app.route("/login") +def login(): + return render_template("/pages/login.html") + +@app.route("/signup") +def signup(): + return render_template("/pages/signup.html") + +@app.route("/account") +def account(): + if "username" not in session: + return redirect(url_for("login")) + else: + return render_template("/pages/account.html") + +@app.route("/about") +def about(): + return render_template("/pages/about.html") + +# API routes +@app.post("/recipes/add") +def add_recipe(): + req_data = request.form.to_dict() + submitted_url = req_data["url"] + if submitted_url == '': + return "<span class='text-red-500'>No recipe supplied!</span>" + + does_recipe_exist = recipe_exists(session["username"], submitted_url) + + if does_recipe_exist: + return "<h1>Recipe already exists</h1>" + else: + recipe_json = scrape(submitted_url, session["username"]) + add_single_recipe(recipe_json) + all_recipes = get_all_recipes(session["username"]) + all_facets = get_facets(session["username"]) + return render_template("/components/app.html", recipes=all_recipes, facets=all_facets) + +@app.post("/recipes/search") +def search(): + req_data = request.form.to_dict() + all_recipes = search_recipes(req_data, session["username"]) + all_facets = get_facets(session["username"], req_data) + return render_template("/components/app.html", recipes=all_recipes, facets=all_facets) + +@app.delete("/recipes/delete/<recipe_id>") +def delete_recipe(recipe_id): + res = delete_single_recipe(recipe_id) + if res["success"]: + return f'<p class="success">Recipe {recipe_id} successfully deleted, <a href="/home">Go home</a>' + else: + error_html = f'<p class="error">Error deleting {recipe_id}</p>' + return error_html + +@app.post("/login") +def login_user(): + req_data = request.form.to_dict() + user = req_data["username"] + pw = req_data["password"] + res = user_exists(user) + if res["success"] and res["user"] is None: + return "<p class='error'>User doesn't exist, <a href='/signup'>signup instead</a></p>" + elif res["success"] and res["user"] is not None: + pw_matches = bcrypt.check_password_hash(res["password"], pw) + if pw_matches: + session["username"] = user + return Response(headers={"HX-Redirect": "/home"}) + else: + return "Incorrect password, try again" + else: + return "<p class='error'>Something went wrong with the login</p>" + +@app.post("/signup") +def signup_user(): + req_data = request.form.to_dict() + user = req_data["username"] + pw = req_data["password"] + + if user == "" or pw == "": + return "<p class='error'>You must fill in both username and password</p>" + + res = user_exists(user) + if res["success"] and res["user"] is not None: + return "<p class='error'>User already exists, <a href='/login'>Login instead</a></p>" + elif res["success"] and res["user"] is None: + pattern = r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$' + is_strong = bool(re.match(pattern, pw)) + if is_strong: + pw_hash = bcrypt.generate_password_hash(pw) + res = add_user(user, pw_hash) + if res["success"]: + session["username"] = user + return Response(headers={"HX-Redirect": "/home"}) + else: + return "<p class='error'>Something went wrong</p>" + else: + return "<p class='error'>Password must be at least 8 characters long and contain at least 1 digit and 1 number</p>" + +@app.post("/logout") +def logout_user(): + session.pop('username', None) + return Response(headers={"HX-Redirect": "/"})
\ No newline at end of file |