def account(): """Show account management page""" user_id = session.get("user_id") # User reached route via POST (as by submitting a form with new username/password via POST) if request.method == "POST": username = request.form.get("newname") password = request.form.get("newpass") confirmation = request.form.get("confpass") if username or password: # if new password was submitted if password: # Check password matches pattern if not re.match( "(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*(&|%|#)).{8,}", password): return apology( "Password must contain at least one number, one uppercase and lowercase letter, one special symbol (&,$,#) and has at least 8 characters", 403) # Ensure password confirmation matches password if password != confirmation or not confirmation: return apology("confirmation does not match password", 403) # Udate password hash in database cur_user = Users.query.filter(Users.id == user_id).first() cur_user.hash = generate_password_hash(password) db.session.commit() # if new username was submitted if username: # Ensure username is not in use if Users.query.filter(Users.username == username, Users.id != user_id).first() is not None: return apology("username already exists", 403) # Udate username in database cur_user = Users.query.filter(Users.id == user_id).first() cur_user.username = username db.session.commit() # Flash success message flash("Your username / password were changed.") # Redirect user to home page return redirect(url_for("home.index")) else: # Flash no-change message flash("Your username / password were not changed") # Redirect user to home page return redirect(url_for("admin.account")) else: user = db.session.query(Users.username, Users.cash).filter(Users.id == user_id) return render_template("account.html", user=user)
def history(): """Show history of transactions""" data = get_history("date", "desc", "all") if data[0] == "error": # return render_template('debug.html', fund = data[1]) return apology("Database read error", 403) elif data == "empty": return apology("You did not make any transaction yet", 403) return render_template("history.html", history=data)
def register(): """Register user""" # User reached route via POST (as by submitting a form via POST) if request.method == "POST": username = request.form.get("username") password = request.form.get("password") confirmation = request.form.get("confirmation") # Ensure username was submitted if not username: return apology("must provide username", 403) # Ensure username is uniq elif Users.query.filter(Users.username == username).first() is not None: return apology("username already exists", 403) # Ensure password was submitted elif not password: return apology("must provide password", 403) # Check password matches pattern if not re.match("(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*(&|%|#)).{8,}", password): return apology("Password must contain at least one number, one uppercase and lowercase letter, one special symbol (&,$,#) and has at least 8 characters", 403) # Ensure password confirmation matches password elif password != confirmation or not confirmation: return apology("confirmation does not match password", 403) # Insert username in database new_user = Users( username = username, hash = generate_password_hash(password)) db.session.add(new_user) db.session.flush() # log newly registered user in #id = db.session.query(Users.id).filter(Users.username == username).first() session["user_id"] = new_user.id # finalize changes to database db.session.commit() # Flash success message flash("Congratulation! You were successfully registered!") # Redirect user to home page return redirect(url_for("home.index")) # User reached route via GET (as by clicking a link or via redirect) else: return render_template("register.html")
def index(): """Show portfolio of stocks""" # request necessary data data = get_portfolio("symbol", "asc") if data == "error": return apology("database read error", 403) #return render_template('debug.html', fund = data) return render_template("index.html", rows = data[1], totals = data[0])
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": username = request.form.get("username") password = request.form.get("password") # Ensure username was submitted if not username: return apology("must provide username", 403) # Ensure password was submitted elif not password: return apology("must provide password", 403) # Query database for username try: cur_user = Users.query.filter(Users.username == username).first() except Exception as error: return apology("database read error", 403) # Ensure username exists if cur_user is None: return apology("Invalid username", 403) # Ensure password is correct if not check_password_hash(cur_user.hash, password): return apology("invalid password", 403) # Remember which user has logged in session["user_id"] = cur_user.id # Redirect user to home page return redirect(url_for("index")) # User reached route via GET (as by clicking a link or via redirect) else: return render_template("/login.html")
def changefund(): """Manage cash funds in portfolio""" user_id = session.get("user_id") # User reached route via POST by submitting a form if request.method == "POST": operation = request.form.get("cashop") amount = int(request.form.get("amount")) if not amount or amount < 0: return apology( "Please enter amount of cash you would like to add / withdraw a a positive number", 403) #current = db.execute("SELECT cash FROM users WHERE id = :user_id", user_id = user_id) current = Users.query.filter(Users.id == user_id).first() if operation == "add": new_amount = current.cash + amount message = "You successfully added funds to your account" if operation == "withdraw": if amount > current.cash: return apology( "The amount of cash in your account is not enough", 403) new_amount = current.cash - amount message = "You successfully withdrew funds from your account" # Udate cash amount in database current.cash = new_amount db.session.commit() # Flash success message flash(message) # Redirect user to home page return redirect(url_for("home.index")) else: return redirect(url_for("admin.account"))
def sell(): """Sell shares of stock""" rows = db.session.query( Transactions.symbol, Transactions.shares).filter_by(user_id=current_user.id).all() symbols = [row[0] for row in rows] form = SellForm() form.symbol.choices = ['Select Symbol'] + list(set(symbols)) if form.validate_on_submit(): if form.symbol.data not in symbols: return apology('symbol not in portfolio', 403) elif int(form.shares.data) > sum( [row[1] for row in rows if row[0] == form.symbol.data]): return apology('share number exceeded', 403) user = User.query.filter_by(id=current_user.id).first() resp = lookup(form.symbol.data) total_price = int(form.shares.data) * resp['price'] user.cash += total_price transaction = Transactions(symbol=form.symbol.data, shares=-form.shares.data, price=resp['price'], user_id=user.id) db.session.add(transaction) db.session.commit() flash('SOLD!', 'success') return redirect('/') else: return render_template('sell.html', symbols=symbols, form=form)
def buy(): """Buy shares of stock""" form = BuyForm() if form.validate_on_submit(): resp = lookup(form.symbol.data) user = User.query.filter_by(id=current_user.id).first() total_price = int(form.shares.data) * resp['price'] if user.cash < total_price: return apology("not enough cash to complete the transaction") user.cash -= total_price transaction = Transactions(symbol=form.symbol.data, shares=form.shares.data, price=resp['price'], user_id=user.id) db.session.add(transaction) db.session.commit() flash('BOUGHT!', 'success') return redirect('/') return render_template('buy.html', form=form)
def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code)
def buy(): """Buy shares of stock""" # return base buy page if no url variiables if not request.args and request.method == "GET": return render_template("buy.html") # get user id user_id = session.get("user_id") # request stock ticker symbol from URL symbol = request.args.get("symbol", '') shares = request.args.get("shares", '') # set shares if no number is provided if not shares: shares = 0 # check 'shares' is positive number if int(shares) < 0: return apology("Please enter positive number of shares to buy", 403) # get cash available #fund = db.execute("SELECT cash FROM users WHERE id = :user_id", user_id = user_id) fund = Users.query.filter(Users.id == user_id).first() funds = float(fund.cash) # no stock ticker symbol was provided through GET method if not symbol: # User reached route via POST (as by submitting a form via POST) if request.method == "POST": symbol = request.form.get("symbol") name = request.form.get("name") shares = int(request.form.get("shares")) price = float(request.form.get("price")) # load apology if symbol is not provided if not symbol: return apology("please enter stock ticker symbol", 403) # load apology if number is not provided if not shares or shares <= 0: return apology("Please enter positive number of shares to buy", 403) # check funds available if funds < price * shares: return apology("Sorry, not enough funds for this transaction", 403) # prepare data to be inserted into db amount = round(shares * price, 2) cash_after = funds - amount # fill in transactions table with new data new_transaction = Transactions(user_id=user_id, symbol=symbol, name=name, number=shares, price=price, amount=shares * price, type="buy") db.session.add(new_transaction) db.session.commit() # update cash cur_user = Users.query.filter(Users.id == user_id).first() cur_user.cash = cash_after db.session.commit() message = "You've successfully bought " + str( shares) + " shares of " + symbol flash(message) return redirect(url_for("index")) else: return apology("please enter stock ticker symbol", 403) # request symbol information from IEX cloud quoteInfo = lookup(symbol) # redirect to buy page with error message if no symbol was found if quoteInfo is None: return apology( "The symbol was not found or something else went wrong.", 403) # load buy page with stock ticker information filled in return render_template("buy.html", quoteInfo=quoteInfo, shares=shares, price=quoteInfo["price"], cash=funds, required=quoteInfo["price"] * int(shares))
def sell(): """Sell shares of stock""" user_id = session.get("user_id") # request a list of owned shares #holdings = db.execute("SELECT symbol, name, SUM(number) shares, SUM(amount) total, (SUM(amount) / SUM(number)) avgprice FROM transactions WHERE user_id = :user_id GROUP BY symbol", user_id = user_id) holdings = db.session.query(Transactions.symbol, Transactions.name, func.sum(Transactions.number).label('shares'), func.sum(Transactions.amount).label('total'), label('avgprice', func.sum(Transactions.amount) / func.sum(Transactions.number))).\ filter(Transactions.user_id == user_id).group_by(Transactions.symbol).all() # return base sell page if no url variiables if not request.args and request.method == "GET": if holdings is not None: # prepare a list of owned shares to choose from list = [] for row in holdings: list.append(row.symbol) # load sell page return render_template("sell.html", list=list) # return apology if user does not own any stock else: return apology("You do not own any stock to sell", 403) # request stock ticker symbol from URL symbol = request.args.get("symbol", '') # no stock ticker symbol was provided via GET if not symbol: # User reached route via POST (as by submitting a form via POST) if request.method == "POST": symbol = request.form.get("symbol") name = request.form.get("name") shares = request.form.get("shares") price = float(request.form.get("price")) # load apology if symbol is not provided if not symbol: return apology( "Please choose ticker symbol of stock you want to sell", 403) # load apology if number is not provided if not shares or int(shares) <= 0: return apology( "Please enter positive number of shares to sell", 403) # get owned number of stocks for row in holdings: if symbol == row.symbol: sharesOwned = row.shares break # check number of shares available if int(shares) > sharesOwned: return apology( "Sorry, you do not own enough number of shares ", 403) # prepare data to be inserted into db amount = round(int(shares) * price, 2) * -1 #funds = db.execute("SELECT cash FROM users WHERE id = :user_id", user_id = user_id) funds = Users.query.filter(Users.id == user_id).first() cash_after = float(funds.cash) - amount # fill in transactions table with new data new_transaction = Transactions(user_id=user_id, symbol=symbol, name=name, number=int(shares) * -1, price=price, amount=amount, type="sell") db.session.add(new_transaction) db.session.commit() cur_user = Users.query.filter(Users.id == user_id).first() cur_user.cash = cash_after db.session.commit() message = "You've successfully sold " + str( shares) + " shares of " + symbol flash(message) return redirect(url_for("index")) else: return apology("must enter stock ticker symbol", 403) # request symbol information from IEX cloud quoteInfo = lookup(symbol) # redirect to buy page with error message if no symbol was found if quoteInfo is None: return apology( "The symbol was not found or something else went wrong.", 403) # get number of owned stocks and average price of aquisition for row in holdings: if symbol == row.symbol: sharesOwned = row.shares avgPrice = row.avgprice amount = row.total break # load sell page with stock ticker information filled in return render_template("sell.html", quoteInfo=quoteInfo, sharesOwned=sharesOwned, avgPrice=avgPrice, amount=amount)