· 5 years ago · Sep 07, 2020, 09:52 AM
1import os
2
3from cs50 import SQL
4from flask import Flask, flash, jsonify, redirect, render_template, request, session
5from flask_session import Session
6from tempfile import mkdtemp
7from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
8from werkzeug.security import check_password_hash, generate_password_hash
9
10from helpers import apology, login_required, lookup, usd
11
12# Configure application
13app = Flask(__name__)
14
15# Ensure templates are auto-reloaded
16app.config["TEMPLATES_AUTO_RELOAD"] = True
17
18# Ensure responses aren't cached
19@app.after_request
20def after_request(response):
21 response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
22 response.headers["Expires"] = 0
23 response.headers["Pragma"] = "no-cache"
24 return response
25
26# Custom filter
27app.jinja_env.filters["usd"] = usd
28
29# Configure session to use filesystem (instead of signed cookies)
30app.config["SESSION_FILE_DIR"] = mkdtemp()
31app.config["SESSION_PERMANENT"] = False
32app.config["SESSION_TYPE"] = "filesystem"
33Session(app)
34
35# Configure CS50 Library to use SQLite database
36db = SQL("sqlite:///finance.db")
37
38# Make sure API key is set
39if not os.environ.get("API_KEY"):
40 raise RuntimeError("API_KEY not set")
41
42
43@app.route("/")
44@login_required
45def index():
46 """Show portfolio of stocks"""
47 cash = db.execute("SELECT * from users WHERE id=:user_id", user_id=session["user_id"])
48 rows = db.execute("SELECT symbol, SUM(shares) as shares FROM transactions WHERE user_id =:user_id GROUP BY symbol HAVING shares > 0", user_id=session["user_id"])
49 print("index",rows)
50 holdings = list()
51 total = 0
52
53 for row in rows:
54 symbol = row['symbol']
55 shares = row['shares']
56 stock = lookup(symbol)
57 holdings.append({"symbol": stock['symbol'], 'name': stock['name'], 'shares': shares, 'price': stock['price'], "total": stock['price'] * shares})
58 total += stock['price'] * shares
59
60 cash_remaining = cash[0]["cash"]
61 total += cash_remaining
62
63 print("index", holdings)
64
65 return render_template("index.html", holdings = holdings, cash_remaining = cash_remaining, total = total)
66
67@app.route("/buy", methods=["GET","POST"])
68@login_required
69def buy():
70
71 if request.method == "POST":
72 if request.form.get("symbol") == "":
73 return apology("NO symbol", 400)
74
75 stock = request.form.get("symbol").upper()
76 x = lookup(stock)
77
78 if x is None:
79 return apology("No Stock exists", 400)
80
81 shares = int(request.form.get("shares"))
82
83 rows = db.execute("SELECT * FROM users WHERE id=:id", id=session["user_id"])
84
85 cash = rows[0]["cash"]
86 price = x["price"]
87 print(price)
88
89 total_price = shares * int(price)
90
91 if total_price > cash:
92 return apology("CASH NOT AVAILABLE", 400)
93
94 cash = cash - total_price
95
96 db.execute("UPDATE users SET cash =:cash WHERE id=:id", cash=cash, id=session["user_id"])
97 db.execute("INSERT INTO transactions(user_id, symbol, shares, price) VALUES(:user_id, :symbol, :shares, :price)", user_id=session["user_id"], symbol=x["symbol"], shares=shares, price=x["price"])
98
99 flash("Bought {0} shares of {1} for {2}".format(shares, x["symbol"], x["price"]))
100
101 return redirect("/")
102
103 else:
104 return render_template("buy.html")
105
106
107@app.route("/history")
108@login_required
109def history():
110 """Show history of transactions"""
111 transactions = db.execute(
112 "SELECT symbol, shares, price, transacted FROM transactions WHERE user_id = :user_id ORDER BY transacted ASC", user_id=session["user_id"])
113 return render_template("history.html", transactions=transactions)
114
115
116@app.route("/login", methods=["GET", "POST"])
117def login():
118 """Log user in"""
119
120 # Forget any user_id
121 session.clear()
122
123 # User reached route via POST (as by submitting a form via POST)
124 if request.method == "POST":
125
126 # Ensure username was submitted
127 if not request.form.get("username"):
128 return apology("must provide username", 403)
129
130 # Ensure password was submitted
131 elif not request.form.get("password"):
132 return apology("must provide password", 403)
133
134 # Query database for username
135 rows = db.execute("SELECT * FROM users WHERE username = :username",
136 username=request.form.get("username"))
137
138 # Ensure username exists and password is correct
139 if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
140 return apology("invalid username and/or password", 403)
141
142 # Remember which user has logged in
143 session["user_id"] = rows[0]["id"]
144
145 # Redirect user to home page
146 return redirect("/")
147
148 # User reached route via GET (as by clicking a link or via redirect)
149 else:
150 return render_template("login.html")
151
152
153@app.route("/logout")
154def logout():
155 """Log user out"""
156
157 # Forget any user_id
158 session.clear()
159
160 # Redirect user to login form
161 return redirect("/")
162
163
164@app.route("/quote", methods=["GET", "POST"])
165@login_required
166def quote():
167 """Get stock quote."""
168 if request.method == "POST":
169 if request.form.get("symbol") == "":
170 return apology("NO symbol", 400)
171
172 stock = request.form.get("symbol").upper()
173 x = lookup(stock)
174
175 if x is None:
176 return apology("No Stock exists", 400)
177
178 return render_template("quoted.html", stock=x)
179
180 else:
181 return render_template("quote.html")
182
183
184@app.route("/register", methods=["GET", "POST"])
185def register():
186 """Register user"""
187
188 # User reached route via POST (as by submitting a form via POST)
189 if request.method == "POST":
190
191 # Ensure username was submitted
192 if not request.form.get("username"):
193 return apology("must provide username", 403)
194 # Ensure password was submitted
195 elif not request.form.get("password"):
196 return apology("must provide password", 403)
197 # Ensure password and confirmation match
198 elif request.form.get("password") != request.form.get("confirmation"):
199 return apology("passwords do not match", 403)
200
201 userkey = db.execute("INSERT INTO users (username, hash) VALUES (:username, :hash)",username = request.form.get("username"),hash = generate_password_hash(request.form.get("password")))
202
203 if not userkey:
204 return apology("username taken", 400)
205
206 session["user_id"] = userkey
207
208 return redirect("/")
209
210 else:
211 return render_template("register.html")
212
213@app.route("/sell", methods=["GET", "POST"])
214@login_required
215def sell():
216 """Sell shares of stock"""
217 if request.method == "POST":
218
219 stock = request.form.get("symbol").upper()
220
221 x = lookup(stock)
222
223 rows = db.execute("SELECT SUM(shares) as shares_owned FROM transactions WHERE symbol=:symbol AND user_id=:user_id",symbol=x['symbol'], user_id=session["user_id"])
224 shares_owned = int(rows[0]["shares_owned"])
225 shares = int(request.form.get("shares"))
226
227 print(rows)
228
229 if shares > shares_owned:
230 return apology("NOT SO MANY SHARES AVAILABLE", 403)
231
232 cash = db.execute("SELECT * FROM users WHERE id=:id", id=session["user_id"])
233
234 cash = int(cash[0]["cash"])
235 price = int(x["price"])
236
237 total_price = shares * price
238 cash = cash + total_price
239
240 db.execute("UPDATE users SET cash =:cash WHERE id = :user_id",cash = cash, user_id=session["user_id"])
241 db.execute("INSERT INTO transactions (user_id, symbol, shares, price) VALUES(:user_id, :symbol, :shares, :price)",
242 user_id=session["user_id"],
243 symbol=x["symbol"],
244 shares= -1 * shares,
245 price=x["price"])
246
247 flash("Sold {0} shares of {1} for {2}".format(shares, x["symbol"], x["price"]))
248
249 return redirect("/")
250
251 else:
252 rows = db.execute("SELECT symbol FROM transactions WHERE user_id=:user_id GROUP BY symbol HAVING SUM(shares) > 0", user_id=session["user_id"])
253 return render_template("sell.html",symbols = [row["symbol"] for row in rows] )
254
255
256
257@app.route("/change_password", methods=["GET", "POST"])
258@login_required
259def change_password():
260 """Allow user to change her password"""
261
262 if request.method == "POST":
263
264 rows = db.execute("SELECT * FROM users WHERE id = :id",
265 id=session["user_id"])
266
267 print(rows)
268
269 hash = rows[0]["hash"]
270 current = request.form.get("current")
271
272 # Ensure current password exists and new password is correct
273 if check_password_hash(hash, current) == False:
274 return apology("invalid password", 403)
275
276 elif request.form.get("conf") != request.form.get("new"):
277 return apology("password don't match", 403)
278
279 new_hash = generate_password_hash(request.form.get("new"))
280 db.execute("UPDATE users SET hash=:hash WHERE id=:id", hash=new_hash, id=session["user_id"])
281
282 flash("UPDATED")
283 return redirect("/")
284
285 else:
286 return render_template("change_password.html")
287
288def errorhandler(e):
289 """Handle error"""
290 if not isinstance(e, HTTPException):
291 e = InternalServerError()
292 return apology(e.name, e.code)
293
294
295# Listen for errors
296for code in default_exceptions:
297 app.errorhandler(code)(errorhandler)
298