Created
May 15, 2020 20:17
-
-
Save Hamleyburger/0d19011f5fd6f40c3445bdbe5f845ace to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask_wtf import FlaskForm | |
from wtforms import StringField, PasswordField, SubmitField, BooleanField | |
from wtforms.validators import DataRequired, Length, EqualTo, ValidationError | |
from .models import User | |
def uniqueUser(form, field): | |
if User.get(field.data): | |
raise ValidationError('Sorry. That name is already taken') | |
class RegistrationForm(FlaskForm): | |
# First argument will be name and will be used as label | |
username = StringField("Username", validators=[ | |
DataRequired(), Length(min=4, max=30)]) | |
password = PasswordField("Password", validators=[ | |
DataRequired(), Length(min=8, max=30)]) | |
confirm_password = PasswordField("Confirm password", validators=[ | |
DataRequired(), Length(min=8, max=30), EqualTo("password")]) | |
submit = SubmitField("Register") | |
class LoginForm(FlaskForm): | |
# First argument will be name and will be used as label | |
username = StringField("Username", validators=[ | |
DataRequired(), Length(min=4, max=30)]) | |
password = PasswordField("Password", validators=[ | |
DataRequired(), Length(min=8, max=30)]) | |
#remember = BooleanField("Remember me") | |
submit = SubmitField("Login") | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% extends "layout.html" %} | |
{% block title %} | |
{{ title }} | |
{% endblock %} | |
{% block main %} | |
<div class="content-section"> | |
<! --insert novalidate as attribute if you only want to user server side validation--> | |
<form onsubmit="return validateForm(this);" method="POST" action="" novalidate> | |
{{ form.hidden_tag() }} | |
<fieldset class="form-group" style="text-align: left;"> | |
<legend class="border-bottom mb-4">Register a new user</legend> | |
<div class="form-group"> | |
{% if form.username.errors %} | |
{{ form.username(class="form-control is-invalid", autocomplete="off", placeholder="Username") }} | |
<div class="invalid-feedback"> | |
{% for error in form.username.errors %} | |
<span>{{ error }}</span> | |
{% endfor %} | |
</div> | |
{% else %} | |
{{ form.username(class="form-control", autocomplete="off", autofocus=true, placeholder="Username") }} | |
<div id="username-feedback" class="invalid-feedback"></div> | |
{% endif %} | |
</div> | |
<div class="form-group"> | |
{% if form.password.errors %} | |
{{ form.password(class="form-control is-invalid", autocomplete="off", placeholder="Password") }} | |
<div class="invalid-feedback"> | |
{% for error in form.password.errors %} | |
<span>{{ error }}</span> | |
{% endfor %} | |
</div> | |
{% else %} | |
{{ form.password(class="form-control", autocomplete="off", placeholder="Password") }} | |
<div id="password-feedback" class="invalid-feedback"></div> | |
{% endif %} | |
</div> | |
<div class="form-group"> | |
{% if form.confirm_password.errors %} | |
{{ form.confirm_password(class="form-control is-invalid", autocomplete="off", placeholder="Confirm password") }} | |
<div class="invalid-feedback"> | |
{% for error in form.confirm_password.errors %} | |
<span>{{ error }}</span> | |
{% endfor %} | |
</div> | |
{% else %} | |
{{ form.confirm_password(class="form-control", autocomplete="off", placeholder="Confirm password") }} | |
<div id="confirm-feedback" class="invalid-feedback"></div> | |
{% endif %} | |
</div> | |
</fieldset> | |
<div class="form-group"> | |
{{ form.submit(class="btn btn-primary btn-outline-info") }} | |
</div> | |
</form> | |
</div> | |
<script> | |
function validateForm(form) { | |
var flag = true; | |
username = form.username.value; | |
if (!(username.length >= 4 && username.length <= 30)) { | |
var username = document.getElementById("username"); | |
username.classList.add("is-invalid"); | |
document.getElementById("username-feedback").innerHTML = "Username must be between 4 and 30 characters long" | |
flag = false; | |
} | |
pw = form.password.value; | |
if (!(pw.length > 7)) { | |
var password = document.getElementById("password"); | |
password.classList.add("is-invalid"); | |
document.getElementById("password-feedback").innerHTML = "Your password must be at least 8 characters long" | |
flag = false; | |
} | |
if (form.password.value !== form.confirm_password.value) { | |
var confirm_password = document.getElementById("confirm_password"); | |
confirm_password.classList.add("is-invalid"); | |
document.getElementById("confirm-feedback").innerHTML = "The passwords didn't match" | |
flag = false; | |
} | |
if (form.username.value == "") { | |
document.getElementById("username-feedback").innerHTML = "You must provide a username"; | |
username.classList.add("is-invalid"); | |
flag = false; | |
} | |
if (form.password.value == "") { | |
document.getElementById("password-feedback").innerHTML = "You must provide a password"; | |
password.classList.add("is-invalid"); | |
flag = false; | |
} | |
if (form.confirm_password.value == "") { | |
document.getElementById("confirm-feedback").innerHTML = "You must provide a password"; | |
confirm_password.classList.add("is-invalid"); | |
flag = false; | |
} | |
return flag; | |
} | |
</script> | |
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from application import app | |
from flask import session, request, redirect, render_template, flash, jsonify, url_for | |
from .helpers import login_required, apology, lookup, usd, \ | |
clearSessionKeepFlash, setSessionStock | |
from .models import User | |
from .forms import RegistrationForm, LoginForm | |
from werkzeug.exceptions import default_exceptions, HTTPException, \ | |
InternalServerError | |
# Custom filter (this gives an error so I'm commenting it out for now) | |
# app.jinja_env.filters["usd"] = usd | |
# Ensure responses aren't cached | |
@app.after_request | |
def after_request(response): | |
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""" | |
return apology("TODO") | |
@app.route("/buy", methods=["GET", "POST"]) | |
@login_required | |
def buy(): | |
if request.method == "POST": | |
user = User.query.filter_by(id=session["user_id"]).first_or_404() | |
# action can be search, refresh (amount) or buy | |
action = request.form.get("submit-button") | |
# setSessionStock initiates or refreshes session stock info | |
setSessionStock("buystock") | |
# SEARCH | |
if action == "search": | |
symbol = request.form.get("symbol") | |
if lookup(symbol): | |
# Refresh stock info and reset amount if new symbol/stock search | |
setSessionStock("buystock", symbol=symbol) | |
else: | |
flash(u"Invalid stock symbol", "danger") | |
# REFRESH | |
elif action == "refresh": | |
# User refreshed amount. Refresh total if amount > 0. Else | |
amount = int(request.form.get("amount")) | |
if amount > 0: | |
setSessionStock("buystock", amount=amount) | |
else: | |
flash(u"You must input an amount higher than 0", "danger") | |
# BUY | |
else: | |
# User decided to buy a stock. Buy and reset "buystock" in session | |
if user.buy(session["buystock"]["symbol"], session["buystock"]["amount"]): | |
flash(u"Purhased {} {}".format( | |
session["buystock"]["amount"], session["buystock"]["name"]), "success") | |
session["buystock"] = {} | |
session["cash"] = user.cash | |
else: | |
flash("Something went wrong") | |
# Refresh total (amount is handled ) | |
if ("price" in session["buystock"]) and ("amount" in session["buystock"]): | |
session["buystock"]["buytotal"] = float( | |
session["buystock"]["amount"]) * float(session["buystock"]["price"]) | |
return redirect(request.url) | |
# method is get | |
else: | |
return render_template("/buy.html") | |
@app.route("/history") | |
@login_required | |
def history(): | |
"""Show history of transactions""" | |
return apology("TODO") | |
@app.route("/login", methods=["GET", "POST"]) | |
def login(): | |
"""Log user in""" | |
# Forget any user_id | |
clearSessionKeepFlash() | |
# 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 | |
username = request.form.get("username") | |
password = request.form.get("password") | |
# Verify user and store necessary session vars | |
user = User.verify(username, password) | |
if user: | |
session["user_id"] = user.id | |
session["username"] = user.username | |
session["cash"] = user.cash | |
# Redirect user to home page | |
return redirect("/") | |
else: | |
return apology("invalid username or password", 403) | |
# 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 == "POST": | |
# lookup returns a Python dict: | |
quoteDict = lookup(request.form.get("symbol")) | |
if quoteDict: | |
return render_template("/quote.html", quoteDict=quoteDict) | |
else: | |
flash(u"Could not find stock symbol in database", "danger") | |
return redirect(request.url) | |
else: | |
return render_template("/quote.html", quoteDict="") | |
@app.route("/register", methods=["GET", "POST"]) | |
def register(): | |
"""Register user""" | |
# Forget anything user related | |
#session.clear() | |
form = RegistrationForm() | |
if request.method == "POST": | |
# use Flask-WTF's validation: | |
print(form.username.data) | |
print(form.password.data) | |
print(form.confirm_password.data) | |
print(form.errors) | |
print("is submitted: {}".format(form.is_submitted())) | |
print("validate on submit: {}".format(form.validate_on_submit())) | |
print(form.username.errors) | |
print(form.password.errors) | |
return render_template("register.html", form=form) | |
@app.route("/lugin", methods=["GET", "POST"]) | |
def lugin(): | |
"""Log user in""" | |
# Forget any user_id | |
clearSessionKeepFlash() | |
form = LoginForm() | |
print(form.validate_on_submit()) | |
return render_template("lugin.html", title="Login", form=form) | |
@app.route("/sell", methods=["GET", "POST"]) | |
@login_required | |
def sell(): | |
"""Sell shares of stock""" | |
"""TODO: | |
if get: | |
define a list of owned stocks containing: Symbol, name, price, amount owned | |
render template sell | |
if post: | |
search must be searching list of owned stocks for filtering | |
search can redefine the list which will only be reset at get or after sell. | |
search does NOT define what stock is being sold. | |
clicking an item opens a sell modal. | |
make a "reset search" button | |
Sell dialogue (like buy stock): | |
refresh: refreshes amount of sell stocks | |
sell button sells. | |
""" | |
if request.method == "POST": | |
user = User.query.filter_by(id=session["user_id"]).first_or_404() | |
# action can be search, refresh (amount) or sell | |
action = request.form.get("submit-button") | |
# setSessionStock initiates or refreshes session stock info | |
setSessionStock("sellstock") | |
# SEARCH | |
if action == "search": | |
symbol = request.form.get("symbol") | |
if lookup(symbol): | |
# Refresh stock info and reset amount if new symbol/stock search | |
setSessionStock("sellstock", symbol=symbol) | |
else: | |
flash(u"Invalid stock symbol", "danger") | |
# REFRESH | |
elif action == "refresh": | |
# User refreshed amount. Refresh total if amount > 0. Else | |
amount = int(request.form.get("amount")) | |
if amount > 0: | |
setSessionStock("sellstock", amount=amount) | |
else: | |
flash(u"You must input an amount higher than 0", "danger") | |
# SELL | |
else: | |
# User decided to sell a stock. Sell and reset "sellstock" in session | |
if user.sell(session["sellstock"]["symbol"], session["sellstock"]["amount"]): | |
session["sellstock"] = {} | |
session["cash"] = user.cash | |
else: | |
flash("Something went wrong") | |
# Refresh total (amount is handled ) | |
if ("price" in session["sellstock"]) and ("amount" in session["sellstock"]): | |
session["sellstock"]["selltotal"] = float( | |
session["sellstock"]["amount"]) * float(session["sellstock"]["price"]) | |
return redirect(request.url) | |
# method is get | |
else: | |
return render_template("/sell.html") | |
def errorhandler(e): | |
"""Handle error""" | |
if not isinstance(e, HTTPException): | |
e = InternalServerError() | |
return apology(e.name, e.code) | |
# Listen for errors | |
for code in default_exceptions: | |
app.errorhandler(code)(errorhandler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment