· 5 years ago · Apr 22, 2020, 03:34 PM
1#pk_3ee3137973c343d5be8ca8f03fed3663
2import os
3
4from cs50 import SQL
5from flask import Flask, flash, jsonify, redirect, render_template, request, session
6from flask_session import Session
7from tempfile import mkdtemp
8from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
9from werkzeug.security import check_password_hash, generate_password_hash
10
11from helpers import apology, login_required, lookup, usd
12
13# Configure application
14app = Flask(__name__)
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 rows = db.execute("SELECT symbol, shares FROM purchase WHERE user_id = :username", username = session["user_id"])
48 symbols_shares = {}
49 for dictionary in rows:
50 if dictionary["symbol"] not in symbols_shares:
51 #add to symbol to dictionary as key, and shares as value
52 symbols_shares[dictionary["symbol"]] = dictionary["shares"]
53 else:
54 #update value of key.
55 symbols_shares[dictionary["symbol"]] = symbols_shares[dictionary["symbol"]] + dictionary["shares"]
56 symb_list = []
57 share_list = []
58 curr_price = []
59 prices2 = []
60 value_shares = []
61 values2 = []
62 #make list of symbols and shares from symb_shr dictionary
63 for key in symbols_shares:
64 if symbols_shares[key] != 0:
65 symb_list.append(key)
66 share_list.append(symbols_shares[key])
67
68 for symbol in symb_list:
69 price = lookup(symbol)["price"]
70 curr_price.append(price)
71 prices2.append(usd(price))
72
73 for i in range(len(share_list)):
74 value = share_list[i] * curr_price[i]
75 value_shares.append(value)
76 values2.append(usd(value))
77
78 money = db.execute("SELECT CASH FROM users WHERE id = :user_id", user_id = session["user_id"])
79 cash = money[0]["cash"]
80 val_total = cash + sum(value_shares)
81 column = len(symb_list)
82 return render_template("index.html", cash = usd(cash), column = column, val_total = usd(val_total), symb_list = symb_list, share_list = share_list, curr_price = prices2, value_shares = values2, current_user = session["user"])
83 #return apology("TODO")
84 #export API_KEY=pk_3ee3137973c343d5be8ca8f03fed3663
85
86
87
88@app.route("/buy", methods=["GET", "POST"])
89@login_required
90def buy():
91 """Buy shares of stock"""
92 #if POST
93 if request.method == "POST":
94 symbol = request.form.get("symbol")
95 #if symbol not exist/input blank
96 if not symbol:
97 return apology("PLEASE INPUT A SYMBOL", 403)
98 shares = int(request.form.get("shares"))
99 if shares < 1:
100 return apology("SHARES MUST BE ATLEAST ONE")
101 stocks = lookup(symbol)
102 if not stocks:
103 return apology("STOCK DOES NOT EXIST")
104 price = stocks["price"]
105 #get the cash from the users table
106 rows = db.execute("SELECT cash from users WHERE id = :user_id", user_id = session["user_id"])
107 cash = rows[0]["cash"]
108 #determine how many stocks they can buy
109 if cash > price * shares:
110 #buy stocks.
111 #remove amount from cash
112 paid = price * shares
113 cash = cash - paid
114 #if table does not already exist
115 db.execute("CREATE TABLE IF NOT EXISTS purchase (id INTEGER PRIMARY KEY, user_id INTEGER, symbol VARCHAR(4), transact_type VARCHAR, shares INTEGER, paid INTEGER, time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)")
116 #insert info of purchase into table
117 db.execute("INSERT INTO purchase (user_id, symbol, transact_type, shares, paid) VALUES (:user_id, :symbol, :transact_type, :shares, :paid)", user_id=session["user_id"], symbol = symbol, transact_type = "BOUGHT", shares = shares, paid = usd(price * shares))
118 db.execute("UPDATE users SET cash =:cash WHERE id = :user_id", cash= cash, user_id = session["user_id"])
119 #create table of balances.
120 #cash balance. how much shares for each stock now owned
121 #db.execute("CREATE TABLE IF NOT EXISTS stocks (id INTEGER PRIMARY KEY, user_id INTEGER, symbol VARCHAR(3), number INTEGER")
122 #db.execute("INSERT INTO stocks (user_id, symbol, number) VALUES (:user_id, :symbol, :number)", user_id = user_id, symbol = symbol, number = number + shares)
123 return redirect("/")
124 else:
125 return apology("You do not have enough cash for this purchase!")
126 else:
127 return render_template("buy.html", current_user = session["user"])
128
129
130@app.route("/history")
131@login_required
132def history():
133 """Show history of transactions"""
134 rows = db.execute("SELECT symbol, transact_type, shares, paid, time FROM purchase WHERE user_id = :username", username = session["user_id"])
135 length = len(rows)
136 return render_template("history.html", rows = rows, length = length, current_user = session["user"])
137
138
139@app.route("/login", methods=["GET", "POST"])
140def login():
141 """Log user in"""
142
143 # Forget any user_id
144 session.clear()
145
146 # User reached route via POST (as by submitting a form via POST)
147 if request.method == "POST":
148
149 # Ensure username was submitted
150 if not request.form.get("username"):
151 return apology("must provide username", 403)
152
153 # Ensure password was submitted
154 elif not request.form.get("password"):
155 return apology("must provide password", 403)
156
157 # Query database for username
158 username = request.form.get("username")
159 username = username.lower()
160 rows = db.execute("SELECT * FROM users WHERE username = :username",
161 username=username)
162
163 # Ensure username exists and password is correct
164 if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
165 return apology("invalid username and/or password", 403)
166
167 # Remember which user has logged in
168 session["user_id"] = rows[0]["id"]
169 session["user"] = username
170
171 # Redirect user to home page
172 return redirect("/")
173
174 # User reached route via GET (as by clicking a link or via redirect)
175 else:
176 return render_template("login.html")
177
178
179@app.route("/logout")
180def logout():
181 """Log user out"""
182
183 # Forget any user_id
184 session.clear()
185
186 # Redirect user to login form
187 return redirect("/")
188
189
190@app.route("/quote", methods=["GET", "POST"])
191@login_required
192def quote():
193 """Get stock quote."""
194 #if submitted via GET
195 if request.method == "POST":
196 #store symbol in variable
197 symbol = request.form.get("symbol")
198 if not symbol:
199 return apology("must enter valid symbol", 403)
200 #check what the prices for what the user just entered
201 else:
202 return render_template("quoted.html", look_up = lookup(symbol), current_user = session["user"])
203 else:
204 return render_template("quote.html", current_user = session["user"])
205
206
207@app.route("/register", methods=["GET", "POST"])
208def register():
209 """Register user"""
210 # Forget any user_id
211 session.clear()
212 #if user submits form
213 if request.method == "POST":
214 # Ensure username was submitted
215 if not request.form.get("username"):
216 return apology("must provide username", 403)
217
218 #Ensure password was submitted
219 if not request.form.get("password"):
220 return apology("must provide password", 403)
221
222 #ensure both passwords match
223 if request.form.get("password")!= request.form.get("confirmation"):
224 return apology("password mismatch", 403)
225
226 #check if user not already registered
227 # Ensure username exists and password is correct
228 username = request.form.get("username")
229 username = username.lower()
230 rows = db.execute("SELECT * FROM users WHERE username = :username", username=username)
231 if rows:
232 return apology("username already taken", 403)
233
234 #Insert username and password into db
235 #db.execute("INSERT INTO registrants (name, email) VALUES (:name, :email)", name=name, email=email)
236 password = generate_password_hash(request.form.get("password"))
237 db.execute("INSERT INTO users (username, hash) VALUES (:username, :password)", username = username, password = password)
238
239 rows = db.execute("SELECT * FROM users WHERE username = :username", username=username)
240
241 # Remember which user has logged in
242 session["user_id"] = rows[0]["id"]
243 session["user"] = username
244
245 # Redirect user to home page
246 return redirect("/")
247
248 #return apology("TODO")
249 # User reached route via GET (as by clicking a link or via redirect)
250 else:
251 return render_template("register.html")
252
253
254@app.route("/sell", methods=["GET", "POST"])
255@login_required
256def sell():
257 """Sell shares of stock"""
258 #if POST
259 if request.method == "POST":
260 symbol = request.form.get("symbol")
261 #if symbol not exist/input blank
262 if not symbol:
263 return apology("PLS SELECT STOCK")
264 #if user does not own any of that shares
265 #check purchases table, check the symbols column
266 symbols = db.execute("SELECT symbol from purchase WHERE user_id = :user_id", user_id = session["user_id"])
267 #if the symbol has not been bought
268 list_symbols = []
269 for dictionary in symbols:
270 for i in dictionary:
271 list_symbols.append(dictionary[i])
272 if symbol not in list_symbols:
273 return apology("SORRY YOU DO NOT OWN THIS STOCK")
274 total_shares = db.execute("SELECT shares FROM (SELECT * from purchase WHERE user_id = :user_id) WHERE symbol = :symbol", user_id = session["user_id"], symbol = symbol)
275 user_shares = 0
276 for dictionary in total_shares:
277 for i in dictionary:
278 user_shares += dictionary[i]
279 #if symbol not in symbols:
280 #return apology("YOU DO NOT OWN THIS STOCK", 403)
281 shares = int(request.form.get("shares"))
282 if shares < 1:
283 return apology("SHARES MUST BE ATLEAST ONE")
284 if shares <= user_shares:
285 #TODO
286 stocks = lookup(symbol)
287 price = stocks["price"]
288 #get the cash from the users table
289 rows = db.execute("SELECT cash from users WHERE id = :user_id", user_id = session["user_id"])
290 cash = rows[0]["cash"]
291 #sell stocks.
292 #add revenue to cash
293 cash = cash + price * shares
294 #if table does not already exist
295 db.execute("CREATE TABLE IF NOT EXISTS purchase (id INTEGER PRIMARY KEY, user_id INTEGER, symbol VARCHAR(4), transact_type VARCHAR, shares INTEGER, paid INTEGER, time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)")
296 #insert info of purchase into table
297 db.execute("INSERT INTO purchase (user_id, symbol, transact_type, shares, paid) VALUES (:user_id, :symbol, :transact_type, :shares, :paid)", user_id=session["user_id"], symbol = symbol, transact_type = "SOLD", shares = -shares, paid = usd(price * shares))
298 db.execute("UPDATE users SET cash =:cash WHERE id = :user_id", cash= cash, user_id = session["user_id"])
299 return redirect("/")
300 else:
301 return apology("You do not have Enough Stocks")
302 else:
303
304 #new sale
305 rows = db.execute("SELECT symbol, shares FROM purchase WHERE user_id = :username", username = session["user_id"])
306 symbols_shares = {}
307 for dictionary in rows:
308 if dictionary["symbol"] not in symbols_shares:
309 #add to symbol to dictionary as key, and shares as value
310 symbols_shares[dictionary["symbol"]] = dictionary["shares"]
311 else:
312 #update value of key.
313 symbols_shares[dictionary["symbol"]] = symbols_shares[dictionary["symbol"]] + dictionary["shares"]
314 list_symbols = []
315 #make list of symbols and shares from symb_shr dictionary
316 for key in symbols_shares:
317 if symbols_shares[key] != 0:
318 list_symbols.append(key)
319 list_symbols.sort()
320
321 return render_template("sell.html", current_user = session["user"], list_symbols = list_symbols)
322
323
324@app.route("/password", methods=["GET", "POST"])
325@login_required
326def password():
327 if request.method == "POST":
328 password = request.form.get("password")
329 if not password:
330 return apology("please enter a password")
331 #change the password
332 #check that new password exists
333 #check that new password repeat match
334 if password != request.form.get("confirmation"):
335 return apology("passwords do not match")
336 #if all goes well
337 #insert new password into users table
338 db.execute("UPDATE users SET hash = :password WHERE id = :user_id", password = generate_password_hash(password), user_id = session["user_id"])
339 return redirect("/")
340 else:
341 return render_template("password.html", current_user = session["user"])
342
343def errorhandler(e):
344 """Handle error"""
345 if not isinstance(e, HTTPException):
346 e = InternalServerError()
347 return apology(e.name, e.code)
348
349
350# Listen for errors
351for code in default_exceptions:
352 app.errorhandler(code)(errorhandler)