This is my first time posting. I was hoping to receive some help and guidance regarding a CS50 assignment! 🙂
When the “register” button is clicked on the homepage, the page automatically goes to a 500 Internal Server Error. It won’t even load the page.
When I attempt to run flask, here are the error messages I receive:
Traceback (most recent call last):
File "/opt/cs50/lib/flask", line 19, in <module>
sys.exit(flask.cli.main())
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/flask/cli.py", line 1105, in main
cli.main()
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1688, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
finance/ $ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/decorators.py", line 92, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
I attempted to watch and follow along with the code presented on (CS50) FINANCE – PROBLEM SET 9 | SOLUTION by Dors Coding School on YouTube, but it is two years outdated.
From what research I’ve read about, I heard that this assignment no longer supports an API key? I have no idea what that means but I’ve heard that it alters what code you need to write.
For the sake of a shorter post, I’ll only include the files of code that I think are important, or I have altered from CS50.
The following will include:
- add.html
- app.py
- buy.html
- helpers.py
- history.html
- index.html
- phpLiteAdmin.sql
- quote.html
- quoted.html
- register.html
- sell.html
I’ll appreciate any help at all! 🙂 At the end of the day I’m just a bored kid looking for something to do over the summer.
**add.html:**
{% extends "layout.html" %}
{% block title %}
Add Cash
{% endblock %}
{% block main %}
<h1>Add Cash</h1>
<form action="/add_cash" method="post">
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="new_cash" placeholder="Add Some Cash" type="number">
</div>
<button class="btn btn-primary" type="submit">Add</button>
</form>
{% endblock %}
**app.py:**
import os
from cs50 import SQL
from flask import Flask, flash, redirect, render_template, request, session
from flask_session import Session
from werkzeug.security import check_password_hash, generate_password_hash
import datetime
from helpers import apology, login_required, lookup, usd
# Configure application
app = Flask(__name__)
# Custom filter
app.jinja_env.filters["usd"] = usd
# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///finance.db")
@app.after_request
def after_request(response):
"""Ensure responses aren't cached"""
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
@app.route("/")
@login_required
def index():
"""Show portfolio of stocks"""
user_id = session["user_id"]
transactions_db = db.execute("SELECT symbol, SUM(shares) AS shares, price FROM transactions WHERE user_id = ? GROUP BY symbol", user_id)
cash_db = db.execute("SELECT cash FROM users WHERE id = ?", user_id)
cash = cash_db[0]["cash"]
return render_template("index.html", database = transactions_db, cash = cash)
@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
"""Buy shares of stock"""
if request.method == "GET":
return render_template("buy.html")
else:
symbol = request.form.get("symbol")
shares = int(request.form.get("shares"))
if not symbol:
return apology("Must Give Symbol")
stock = lookup(symbol.upper())
if stock == None:
return apology("Symbol Does Not Exist")
if shares < 0:
return apology("Share Not Allowed")
transaction_value = shares * stock["price"]
user_id = session["user_id"]
user_cash_db = db.execute("SELECT cash FROM users WHERE id = :id", id=user_id)
user_cash = user_cash_db[0]["cash"]
if user_cash < transaction_value:
return apology("Not Enough Money")
uptd_cash = user_cash - transaction_value
db.execute("UPDATE users SET cash = ? WHERE id = ?", uptd_cash, user_id)
date = datetime.datetime.now()
db.execute("INSERT INTO transactions (user_id, symbol, shares, price, date) VALUES (?, ?, ?, ?, ?)", user_id, stock["symbol"], shares, stock["price"], date)
flash("Bought!")
return redirect("/")
@app.route("/history")
@login_required
def history():
"""Show history of transactions"""
user_id = session["user_id"]
transactions.db = db.execute("SELECT * FROM transactions WHERE user_id = :id", id=user_id)
return render_template("history.html", transactions = transactions_db)
@app.route("/add_cash", methods=["GET", "POST"])
@login_required
def add_cash():
"""User can add cash"""
if request.method == "GET":
return render_template("add.html")
else:
new_cash = int(request.form.get("new_cash"))
if not new_cash:
return apology("You Must Give Money")
user_id = session["user_id"]
user_cash_db = db.execute("SELECT cash FROM users WHERE id = :id", id=user_id)
user_cash = user_cash_db[0]["cash"]
uptd_cash = user_cash + new_cash
db.execute("UPDATE users SET cash = ? WHERE id = ?", uptd_cash, user_id)
return redirect("/")
@app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# 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("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
@app.route("/logout")
def logout():
"""Log user out"""
# Forget any user_id
session.clear()
# Redirect user to login form
return redirect("/")
@app.route("/quote", methods=["GET", "POST"])
@login_required
def quote():
"""Get stock quote."""
if request.method == "GET":
return render_template("quote.html")
else:
symbol = request.form.get("symbol")
if not symbol:
return apology("Must Give Symbol")
stock = lookup(symbol.upper())
if stock == None:
return apology("Symbol Does Not Exist")
return render_template("quoted.html", name = stock["name"], price = stock["price"], symbol = stock["symbol"])
@app.route("/register", methods=["GET", "POST"])
def register():
"""Register user"""
if request.method == "GET":
return render_template("register.html")
else:
username = request.form.get("username")
password = request.form.get("password")
confirmation = request.form.get("confirmation")
if not username:
return apology("Must Give Username")
if not password:
return apology("Must Give Password")
if not confirmation:
return apology("Must Give Confirmation")
if password != confirmation:
return apology("Passwords Do Not Match")
hash = generate_password_hash(password)
try:
new_user = db.execute("INSERT INTO users (username, hash) VALUES (?, ?)", username, hash)
except:
return apology("Username Already Exists")
session["user_id"] = new_user
return redirect("/")
@app.route("/sell", methods=["GET", "POST"])
@login_required
def sell():
"""Sell shares of stock"""
if request.method == "GET":
user_id = session["user_id"]
symbols_user = db.execute("SELECT symbol FROM transaction WHERE user_id = :id GROUP BY symbol HAVING SUM(shares) > 0", id=user_id)
return render_template("sell.html", symbols = [row["symbol"] for row in symbols_user])
else:
symbol = request.form.get("symbol")
shares = int(request.form.get("shares"))
if not symbol:
return apology("Must Give Symbol")
stock = lookup(symbol.upper())
if stock == None:
return apology("Symbol Does Not Exist")
if shares < 0:
return apology("Share Not Allowed")
transaction_value = shares * stock["price"]
user_id = session["user_id"]
user_cash_db = db.execute("SELECT cash FROM users WHERE id = :id", id=user_id)
user_cash = user_cash_db[0]["cash"]
user_shares = db.execute("SELECT shares FROM transactions WHERE user_id=:id AND symbol = :symbol GROUP BY symbol", id=user_id, symbol)
user_shares_real = user_shares[0]["shares"]
if shares > user_shares_real:
return apology("You Do Not Have This Amount Of Shares")
uptd_cash = user_cash + transaction_value
db.execute("UPDATE users SET cash = ? WHERE id = ?", uptd_cash, user_id)
date = datetime.datetime.now()
db.execute("INSERT INTO transactions (user_id, symbol, shares, price, date) VALUES (?, ?, ?, ?, ?)", user_id, stock["symbol"], (-1)*shares, stock["price"], date)
flash("Sold!")
return redirect("/")
`**buy.html:**`
{% extends "layout.html" %}
{% block title %}
Buy
{% endblock %}
{% block main %}
<h1>Buy</h1>
<form action="/buy" method="post">
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="symbol" placeholder="Symbol" type="text">
</div>
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="shares" placeholder="Shares" type="number">
</div>
<button class="btn btn-primary" type="submit">Buy</button>
</form>
{% endblock %}
**helpers.py:**
import csv
import datetime
import pytz
import requests
import urllib
import uuid
from flask import redirect, render_template, request, session
from functools import wraps
def apology(message, code=400):
"""Render message as an apology to user."""
def escape(s):
"""
Escape special characters.
https://github.com/jacebrowning/memegen#special-characters
"""
for old, new in [
("-", "--"),
(" ", "-"),
("_", "__"),
("?", "~q"),
("%", "~p"),
("#", "~h"),
("/", "~s"),
('"', "''"),
]:
s = s.replace(old, new)
return s
return render_template("apology.html", top=code, bottom=escape(message)), code
def login_required(f):
"""
Decorate routes to require login.
https://flask.palletsprojects.com/en/latest/patterns/viewdecorators/
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if session.get("user_id") is None:
return redirect("/login")
return f(*args, **kwargs)
return decorated_function
def lookup(symbol):
"""Look up quote for symbol."""
# Prepare API request
symbol = symbol.upper()
end = datetime.datetime.now(pytz.timezone("US/Eastern"))
start = end - datetime.timedelta(days=7)
# Yahoo Finance API
url = (
f"https://query1.finance.yahoo.com/v7/finance/download/{urllib.parse.quote_plus(symbol)}"
f"?period1={int(start.timestamp())}"
f"&period2={int(end.timestamp())}"
f"&interval=1d&events=history&includeAdjustedClose=true"
)
# Query API
try:
response = requests.get(
url,
cookies={"session": str(uuid.uuid4())},
headers={"Accept": "*/*", "User-Agent": request.headers.get("User-Agent")},
)
response.raise_for_status()
# CSV header: Date,Open,High,Low,Close,Adj Close,Volume
quotes = list(csv.DictReader(response.content.decode("utf-8").splitlines()))
price = round(float(quotes[-1]["Adj Close"]), 2)
return {"price": price, "symbol": symbol}
except (KeyError, IndexError, requests.RequestException, ValueError):
return None
def usd(value):
"""Format value as USD."""
return f"${value:,.2f}"
**history.html:**
{% extends "layout.html" %}
{% block title %}
History
{% endblock %}
{% block main %}
<table class="table">
<thead>
<tr>
<th scope="col">Symbols</th>
<th scope="col">Shares</th>
<th scope="col">Price</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
{% for row in transactions %}
<tr>
<td>{{ row["symbols"] }}</td>
<td>{{ row["shares"] }}</td>
<td>{{ row["price"] }}</td>
<td>{{ row["date"] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
**index.html:**
{% extends "layout.html" %}
{% block title %}
Portfolio
{% endblock %}
{% block main %}
<table class="table">
<thead>
<tr>
<th scope="col">Symbols</th>
<th scope="col">Shares</th>
<th scope="col">Price</th>
<th scope="col">TOTAL</th>
</tr>
</thead>
<tbody>
{% for row in database %}
<tr>
<td>{{ row["symbols"] }}</td>
<td>{{ row["shares"] }}</td>
<td>{{ row["price"] }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<th scope="1">Cash</th>
<th scope="1">{{ cash }}</th>
</tr>
</tfoot>
</table>
{% endblock %}
**phpLiteAdmin.sql:**
----
-- phpLiteAdmin database dump (https://www.phpliteadmin.org/)
-- phpLiteAdmin version: 1.9.9-dev
-- Exported: 4:44pm on July 9, 2024 (UTC)
-- database file: /workspaces/172411988/finance/finance.db
----
BEGIN TRANSACTION;
----
-- Table structure for users
----
CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username TEXT NOT NULL, hash TEXT NOT NULL, cash NUMERIC NOT NULL DEFAULT 10000.00);
----
-- Data dump for users, a total of 0 rows
----
----
-- Table structure for transactions
----
CREATE TABLE 'transactions' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'user_id' INTEGER, 'symbol' TEXT, 'shares' INTEGER, 'price' REAL, 'date' DATETIME);
----
-- Data dump for transactions, a total of 0 rows
----
----
-- structure for index username on table users
----
CREATE UNIQUE INDEX username ON users (username);
COMMIT;
**quote.html:**
{% extends "layout.html" %}
{% block title %}
Quote
{% endblock %}
{% block main %}
<h1>Quote</h1>
<form action="/quote" method="post">
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="symbol" placeholder="Symbol" type="text">
</div>
<button class="btn btn-primary" type="submit">Quote</button>
</form>
{% endblock %}
**quoted.html:**
{% extends "layout.html" %}
{% block title %}
Register
{% endblock %}
{% block main %}
<form action="/register" method="post">
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="username" placeholder="Username" type="text">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" name="password" placeholder="Password" type="password">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" name="confirmation" placeholder="Confirm Password" type="password">
</div>
<button class="btn btn-primary" type="submit">Register</button>
</form>
{% endblock %}
**register.html:**
{% extends "layout.html" %}
{% block title %}
Register
{% endblock %}
{% block main %}
<form action="/register" method="post">
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="username" placeholder="Username" type="text">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" name="password" placeholder="Password" type="password">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" name="confirmation" placeholder="Confirm Password" type="password">
</div>
<button class="btn btn-primary" type="submit">Register</button>
</form>
{% endblock %}
**sell.html:**
{% extends "layout.html" %}
{% block title %}
Sell
{% endblock %}
{% block main %}
<h1>Sell</h1>
<form action="/sell" method="post">
<div class="mb-3">
<select name="symbol">
{% for symbol in symbols %}
<option value="{{ symbol }}">{{ symbol }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" name="shares" placeholder="Shares" type="number">
</div>
<button class="btn btn-primary" type="submit">Sell</button>
</form>
{% endblock %}
I’ve tried watching a number of other videos and tutorials, but nothing ended up working out quite right. Thank you so much for reading this far!
Rain is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.