diff options
Diffstat (limited to 'application.py')
| -rw-r--r-- | application.py | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/application.py b/application.py new file mode 100644 index 0000000..54c7e6e --- /dev/null +++ b/application.py @@ -0,0 +1,261 @@ +import os + +from cs50 import SQL +from flask import Flask, flash, redirect, render_template, request, session +from flask_session import Session +from tempfile import mkdtemp +from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError +from werkzeug.security import check_password_hash, generate_password_hash + +from helpers import apology, deal_finder, login_required, passw_requirements, usd + +# Configure application +app = Flask(__name__) + +# Ensure templates are auto-reloaded +app.config["TEMPLATES_AUTO_RELOAD"] = True + +# Ensure responses aren't cached, allows smoother implementation of development-changes +@app.after_request +def after_request(response): + response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" + response.headers["Expires"] = 0 + response.headers["Pragma"] = "no-cache" + return response + +# Custom filter +app.jinja_env.filters["usd"] = usd + +# Configure session to use filesystem (instead of signed cookies, to avoid multiple cookies in one browser) +app.config["SESSION_FILE_DIR"] = mkdtemp() +app.config["SESSION_PERMANENT"] = False +app.config["SESSION_TYPE"] = "filesystem" +Session(app) + +# Configure the SQLite database +db = SQL("sqlite:///spending.db") + + +@app.route("/") +def home(): + """Home page with different versions for visiting guests & logged-in users """ + + # When a non-registered guest visits the website: + if not session: + return render_template("welcome.html") + + # For a logged-in user: + else: + user_id = session["user_id"] + + # Getting username & budget + user_info = db.execute("SELECT * FROM users WHERE id = ?", user_id) + username = user_info[0]["username"] + cash = user_info[0]["cash"] + + # Getting total amount of money spent in each category + amounts = [] + categories = ['%Rent', '%Maintenance', '%Food', '%Family', '%Pets', '%Clothes', '%Hobbies', '%Investing', '%Other'] + + for element in categories: + result = db.execute("SELECT SUM(amount) FROM expenses WHERE user_id = ? AND category LIKE ?", user_id, element)[0]["SUM(amount)"] + if result == None: + result = 0 + amounts.append(result) + + return render_template("home.html", name=username, cash=cash, rent=amounts[0], maintain=amounts[1], food=amounts[2], family=amounts[3], + pets=amounts[4], clothes=amounts[5], hobbies=amounts[6], invest=amounts[7], other=amounts[8]) + + +@app.route("/account", methods=["GET", "POST"]) +@login_required +def account(): + """ View user data & replace passsword """ + + user_id = session["user_id"] + user_info = db.execute("SELECT * FROM users WHERE id = ?", user_id) + username = user_info[0]["username"] + cash = user_info[0]["cash"] + + if request.method == "GET": + return render_template("account.html", name=username, budget=cash) + + else: + # allowing the user to set a new password for their account + pw_new = request.form.get("pw_new") + if not check_password_hash(user_info[0]["hash"], request.form.get("pw_old")): + return apology("Your old password was not correct", 400) + elif pw_new != request.form.get("confirmation"): + return apology("New Password and Confirm New Password did not match", 400) + elif passw_requirements(pw_new) != "valid": + return apology("Password must be between 6 and 25 characters long and contain at least one number and one letter", 400) + + # replace password in the db if all requirements were met + db.execute("UPDATE users SET hash = ? WHERE username = ?", generate_password_hash(pw_new), username) + flash("You successfully changed your password!") + return render_template("/account.html", name=username, budget=cash) + + +@app.route("/bargain", methods=["GET", "POST"]) +@login_required +def bargain(): + """Search for & display cheapest deals for a user-specified item """ + + # display search form + if request.method == "GET": + return render_template("bargain.html") + # display results collected & sorted by web scraping helper function + else: + item = request.form.get("product-search") + deals = deal_finder(item) + + return render_template("bargain.html", deals=deals) + + +@app.route("/budget", methods=["GET", "POST"]) +@login_required +def budget(): + """ View & set budget """ + + user_id = session["user_id"] + budget = db.execute("SELECT cash FROM users WHERE id = ?", user_id)[0]["cash"] + + # view current budget + if request.method == "GET": + return render_template("budget.html", budget=budget) + + # update budget + else: + added_budget = request.form.get("add_budget") + new_budget = float(budget) + float(added_budget) + db.execute("UPDATE users SET cash = ? WHERE id = ?", new_budget, user_id) + + flash("Budget updated!") + return render_template("budget.html", budget=new_budget) + + +@app.route("/history") +@login_required +def history(): + """ Show record of all previous expenses """ + + user_id = session["user_id"] + record = db.execute("SELECT * FROM expenses WHERE user_id = ? ORDER BY date", user_id) + return render_template("history.html", record=record) + + +@app.route("/login", methods=["GET", "POST"]) +def login(): + """Log user in""" + + # Forget any user_id + session.clear() + + # User reached the route via GET: + if request.method == "GET": + return render_template("login.html") + + # User submitted via POST to log in: + else: + # Ensure username was submitted + if not request.form.get("username"): + return apology("must provide username", 403) + + # Ensure password was submitted + elif not request.form.get("password"): + return apology("must provide password", 403) + + # Query database for username + rows = db.execute("SELECT * FROM users WHERE username = ?", request.form.get("username")) + + # Ensure username exists and password is correct + if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")): + return apology("invalid username and/or password", 403) + + # Remember which user has logged in + session["user_id"] = rows[0]["id"] + + # Redirect user to home page + return redirect("/") + + +@app.route("/logout") +def logout(): + """Log user out""" + + # Forget any user_id + session.clear() + + # Redirect user to login form + return redirect("/") + + +@app.route("/register", methods=["GET", "POST"]) +def register(): + """ Register a new user account """ + + # If the user visits this route, display the form to sign up for a new account + if request.method == "GET": + return render_template("register.html") + + # If the user submits their registration with POST + else: + # Get the user's name & password from the form + reg_name = request.form.get("username") + reg_passw = request.form.get("password") + + # Checking if the user failed to provide a username & password, if the name is already taken or if the confirmed password was different + if not reg_name: + return apology("Please enter a username", 400) + elif len(db.execute("SELECT * FROM users WHERE username = ?", reg_name)) != 0: + return apology("Username is already taken", 400) + elif not reg_passw: + return apology("Please choose a unique password", 400) + elif reg_passw != request.form.get("confirmation"): + return apology("Password and Confirm Password did not match", 400) + # Special check with a helper function for password safety + elif passw_requirements(reg_passw) != "valid": + return apology("Password must be between 6 and 25 characters long and contain at least one number and one letter", 400) + + # Otherwise register the new user into the database (with a hashed password for extra security) and redirect them to the main page + db.execute("INSERT INTO users (username, hash) VALUES (?, ?)", reg_name, generate_password_hash(reg_passw)) + return redirect("/login") + + +@app.route("/tracker", methods=["POST", "GET"]) +@login_required +def tracker(): + """ Add new expenses """ + + # Display form to add a new expense + if request.method == "GET": + return render_template("tracker.html") + # When submitting a new expense: + else: + user_id = session["user_id"] + budget = db.execute("SELECT cash FROM users WHERE id = ?", user_id)[0]["cash"] + + # ternary condition if the user does not give an optional comment on the expense + comment = "Unspecified" if not request.form.get("comment") else request.form.get("comment") + category, amount, date = request.form.get("category"), request.form.get("amount", type=float), request.form.get("date") + + # subtract expense from budget + updated_budget = float(budget) - amount + db.execute("UPDATE users SET cash = ? WHERE id = ?", updated_budget, user_id) + + # update table "expenses" in database for use in history.html + db.execute("INSERT INTO expenses (user_id, comment, category, amount, date) VALUES (?, ?, ?, ?, ?)", + user_id, comment, category, amount, date) + return redirect("/") + + +# Handle errors +def errorhandler(e): + if not isinstance(e, HTTPException): + e = InternalServerError() + return apology(e.name, e.code) + + +# Listen for errors +for code in default_exceptions: + app.errorhandler(code)(errorhandler) |
