UME14

CS50/pset7/application.py

Mar 13th, 2019
316
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.42 KB | None | 0 0
  1. import os
  2.  
  3. from cs50 import SQL
  4. from flask import Flask, flash, redirect, render_template, request, session
  5. from flask_session import Session
  6. from passlib.apps import custom_app_context as pwd_context
  7. from tempfile import mkdtemp
  8. from time import gmtime, strftime
  9. from werkzeug.exceptions import default_exceptions
  10. from werkzeug.security import check_password_hash, generate_password_hash
  11.  
  12. from helpers import apology, login_required, lookup, usd
  13.  
  14. # Configure application
  15. app = Flask(__name__)
  16.  
  17. # Ensure templates are auto-reloaded
  18. app.config["TEMPLATES_AUTO_RELOAD"] = True
  19.  
  20. # Ensure responses aren't cached
  21. @app.after_request
  22. def after_request(response):
  23.     response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
  24.     response.headers["Expires"] = 0
  25.     response.headers["Pragma"] = "no-cache"
  26.     return response
  27.  
  28. # Custom filter
  29. app.jinja_env.filters["usd"] = usd
  30.  
  31. # Configure session to use filesystem (instead of signed cookies)
  32. app.config["SESSION_FILE_DIR"] = mkdtemp()
  33. app.config["SESSION_PERMANENT"] = False
  34. app.config["SESSION_TYPE"] = "filesystem"
  35. Session(app)
  36.  
  37. # Configure CS50 Library to use SQLite database
  38. db = SQL("sqlite:///finance.db")
  39.  
  40.  
  41. @app.route("/")
  42. @login_required
  43. def index():
  44.     """Show portfolio of stocks"""
  45.     # NOTE: TABLE to use is (most probably) portfolio
  46.     # An array of arrays to store stock info (ID-wise)
  47.     # Use jinja for-loop to generate table rows
  48.  
  49.     # User ID
  50.     userID = session["user_id"]
  51.     username = db.execute("SELECT username FROM users WHERE id = :userid", userid=userID)[0]["username"]
  52.     portfolio = db.execute("SELECT symbol, name, shares, price, total FROM portfolio WHERE id=:userid", userid=userID)
  53.  
  54.     # How many rows to generate
  55.     dblength = len(portfolio)
  56.  
  57.     # Cash in account
  58.     csh = db.execute("SELECT cash FROM users WHERE id = :userid", userid=userID)[0]["cash"]
  59.     cash = usd(csh)
  60.  
  61.     # Total worth
  62.     grandtotal = 0
  63.     for i in range(dblength):
  64.         grandtotal += portfolio[i]["cash"]
  65.  
  66.     # All stocks
  67.     #return apology("TODO")
  68.     return render_template("index.html")
  69.  
  70.  
  71. @app.route("/buy", methods=["GET", "POST"])
  72. @login_required
  73. def buy():
  74.     """Buy shares of stock"""
  75.     # Display form
  76.     # Add stock to user porfolio
  77.     # Update cash
  78.     #--->show chart (of transaction (Portfolio))
  79.  
  80.     # User reached via POST
  81.     if request.method == "POST":
  82.  
  83.         # Ensure symbol was submitted
  84.         if not request.form.get("symbol"):
  85.             return apology("Missing symbol", 400)
  86.  
  87.         # Validate symbol
  88.         symbol = request.form.get("symbol")
  89.         if not symbol:
  90.             return apology("Invalid symbol", 400)
  91.  
  92.         # Ensure shares was submitted
  93.         if not request.form.get("shares"):
  94.             return apology("Must provide number of shares", 400)
  95.         shares = request.form.get("shares")
  96.  
  97.         # Which user
  98.         userID = session["user_id"]
  99.  
  100.         # Credit in account
  101.         cash = db.execute("SELECT cash FROM users WHERE id = :userid", userid=userID)[0]["cash"]
  102.  
  103.         # Quote the share value
  104.         quote = lookup(request.form.get("symbol"))
  105.         price = usd(quote['price'])
  106.  
  107.         # Variables to put in the database
  108.         total = price * shares
  109.         name = lookup(symbol)["name"]
  110.  
  111.         # If enough money in cash
  112.         if cash > (price * shares):
  113.  
  114.             # userID, shares, price >> are declared elsewhere in this function
  115.             datetime = strftime("%Y-%m-%d %H:%M:%S", gmtime())
  116.  
  117.             # Check if symbol is already in database
  118.             matched_symbol = db.execute("SELECT symbol FROM portfolio WHERE id = :id", id=userID)[0]
  119.  
  120.             if matched_symbol["symbol"] == symbol:
  121.  
  122.                 # Add symbol data
  123.                 db.execute("UPDATE portfolio SET shares = shares + :shares, price = :price, total = total + :total WHERE id=:id AND symbol=:symbol", shares=shares, price=price, total=total, id=userID, symbol=symbol)
  124.  
  125.                 # Add in History datatbase
  126.                 db.execute("INSERT INTO history (id, symbol, shares, price, transacted) VALUES (:id, :symbol, :shares, :price, :transacted)", id=userID, symbol=symbol, shares=shares, price=price, transacted=datetime)
  127.  
  128.             # If symbol not in database
  129.             else:
  130.                 # Entry into transaction database
  131.                 db.execute("INSERT INTO portfolio (id, symbol, name, shares, price, total) VALUES (:id, :symbol, :name, :shares, :price, :total)", id=userID, symbol=symbol, name=name, shares=shares, price=price, total=total)
  132.  
  133.                 # Add in History database
  134.                 db.execute("INSERT INTO history (id, symbol, shares, price, transacted) VALUES (:id, :symbol, :shares, :price, :transacted)", id=userID, symbol=symbol, shares=shares, price=price, transacted=datetime)
  135.  
  136.             # Update cash
  137.             cash -= price * shares
  138.  
  139.             # Update cash in users database
  140.             db.execute("UPDATE users SET cash = cash + :total WHERE id = :user_id", total=total, user_id=userID)
  141.  
  142.             # Redirect user to home page
  143.             return redirect("/")
  144.  
  145.         # If NOT enough money in cash
  146.         else:
  147.             return apology("Can't afford", 400)
  148.  
  149.  
  150.     # User reached via GET
  151.     else:
  152.         render_template("buy.html")
  153.  
  154.  
  155. @app.route("/history")
  156. @login_required
  157. def history():
  158.     """Show history of transactions"""
  159.  
  160.     # Select all the tables from history database
  161.     history = db.execute("SELECT * FROM history")
  162.  
  163.     # Show all list items (dict) in html
  164.  
  165.     return render_template("history.html")
  166.  
  167.  
  168. @app.route("/login", methods=["GET", "POST"])
  169. def login():
  170.     """Log user in"""
  171.  
  172.     # Forget any user_id
  173.     session.clear()
  174.  
  175.     # User reached route via POST (as by submitting a form via POST)
  176.     if request.method == "POST":
  177.  
  178.         # Ensure username was submitted
  179.         if not request.form.get("username"):
  180.             return apology("must provide username", 403)
  181.  
  182.         # Ensure password was submitted
  183.         elif not request.form.get("password"):
  184.             return apology("must provide password", 403)
  185.  
  186.         # Query database for username
  187.         rows = db.execute("SELECT * FROM users WHERE username = :username",
  188.                           username=request.form.get("username"))
  189.  
  190.         # Ensure username exists and password is correct
  191.         if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
  192.             return apology("invalid username and/or password", 403)
  193.  
  194.         # Remember which user has logged in
  195.         session["user_id"] = rows[0]["id"]
  196.  
  197.         # Redirect user to home page
  198.         return redirect("/")
  199.  
  200.     # User reached route via GET (as by clicking a link or via redirect)
  201.     else:
  202.         return render_template("login.html")
  203.  
  204.  
  205. @app.route("/logout")
  206. def logout():
  207.     """Log user out"""
  208.  
  209.     # Forget any user_id
  210.     session.clear()
  211.  
  212.     # Redirect user to login form
  213.     return redirect("/")
  214.  
  215.  
  216. @app.route("/quote", methods=["GET", "POST"])
  217. @login_required
  218. def quote():
  219.     """Get stock quote."""
  220.  
  221.     # User reached via POST (via submitting the form)
  222.     if request.method == 'POST':
  223.  
  224.         # Ensure symbol was submitted
  225.         if not request.form.get("symbol"):
  226.             return apology("Missing symbol", 400)
  227.  
  228.         quoted = lookup(request.form.get("symbol"))
  229.  
  230.         # Ensre symbol is valid
  231.         if not quote:
  232.             return apology("Invalid symbol", 400)
  233.         return render_template("showquote.html", company=quoted['name'], symbol=quoted['symbol'], usd=quoted['price'])
  234.  
  235.     # User reached via GET
  236.     else:
  237.         return render_template("quote.html")
  238.  
  239.  
  240. @app.route("/register", methods=["GET", "POST"])
  241. def register():
  242.     """Register user"""
  243.  
  244.     # Forget any user_id
  245.     session.clear()
  246.  
  247.     # User reached route via POST (as by submitting a form via POST)
  248.     if request.method == "POST":
  249.  
  250.         # Ensure username was submitted
  251.         if not request.form.get("username"):
  252.             return apology("must provide username", 403)
  253.  
  254.         # Ensure password was submitted
  255.         elif not request.form.get("password"):
  256.             return apology("must provide password", 403)
  257.  
  258.         # Ensure password was submitted (twice)
  259.         elif not request.form.get("passwordConfirm"):
  260.             return apology("must provide password", 403)
  261.  
  262.         # Hash password
  263.         hashpass = pwd_context.hash(request.form.get("password"))
  264.  
  265.         # Query database for username
  266.         result = db.execute("INSERT INTO users (username, hash) VALUES(:username, :hash)", username=request.form.get("username"), hash=hashpass)
  267.         if not result:
  268.             return apology("Username already exists.")
  269.  
  270.         # Remember which user has logged in
  271.         session["user_id"] = result[0]["id"]
  272.  
  273.         # Redirect user to home page
  274.         return redirect("/")
  275.  
  276.     # User reached route via GET (as by clicking a link or via redirect)
  277.     else:
  278.         return render_template("register.html")
  279.  
  280.  
  281.  
  282. @app.route("/sell", methods=["GET", "POST"])
  283. @login_required
  284. def sell():
  285.     """Sell shares of stock"""
  286.  
  287.     # User reached route via POST (as by submitting a form via POST)
  288.     if request.method == "POST":
  289.  
  290.         # Ensure symbol was submitted
  291.         if not request.form.get("symbol"):
  292.             return apology("Missing symbol", 400)
  293.         symbol = request.form.get("symbol")
  294.  
  295.         # Ensure shares was submitted
  296.         if not request.form.get("shares"):
  297.             return apology("Missing shares", 400)
  298.         shares = request.form.get("shares")
  299.  
  300.         # List all the symbols in user's portfolio
  301.         db_symbols = db.execute("SELECT symbol FROM portfolio WHERE id = :id", id=session["user_id"])
  302.         symbols_total = len(db_symbols)
  303.  
  304.         # Number of share in database
  305.         db_shares = db.execute("SELECT shares FROM portfolio WHERE id = :id AND symbol = :symbol", id=session["user_id"], symbol=symbol)[0]["shares"]
  306.  
  307.         # Ensure user has enough share(s)
  308.         if not db_shares >= shares:
  309.             return apology("Too many shares", 400)
  310.  
  311.         # Present date-time
  312.         datetime = strftime("%Y-%m-%d %H:%M:%S", gmtime())
  313.  
  314.         # Present price
  315.         price = lookup(symbol)["price"]
  316.  
  317.         # Total price if bought
  318.         total_price = shares * price
  319.  
  320.         # Subtract/Remove shares from user's portfolio
  321.         if (db_shares - shares) > 0:
  322.             db.execute("UPDATE portfolio SET shares - :shares, total - :totalPr WHERE id=:id AND symbol=:symbol", shares=shares, totalPr=total_price, id=session["user_id"], symbol=symbol)
  323.  
  324.         else:
  325.             db.execute("DELETE FROM portfolio WHERE id=:id", id=session["user_id"])
  326.  
  327.         # Add transaction in history database
  328.         db.execute("INSERT INTO history (id, symbol, shares, price, transacted) VALUES (:id, :symbol, :shares, :price, :transacted)", id=session["user_id"], symbol=symbol, shares=(-shares), price=price, transacted=datetime)
  329.  
  330.         # Update cash in users database
  331.         db.execute("UPDATE users SET cash + :totalPr WHERE id=:id", totalPr=total_price, id=session["user_id"])
  332.  
  333.     # User reached route via GET (as by clicking a link or via redirect)
  334.     else:
  335.         return render_template("sell.html")
  336.  
  337.  
  338. def errorhandler(e):
  339.     """Handle error"""
  340.     return apology(e.name, e.code)
  341.     #return apology(e)
  342.  
  343.  
  344. # listen for errors
  345. for code in default_exceptions:
  346.     app.errorhandler(code)(errorhandler)
Advertisement
Add Comment
Please, Sign In to add comment