Skip to content

Instantly share code, notes, and snippets.

@Hamleyburger
Created May 15, 2020 20:17
Show Gist options
  • Save Hamleyburger/0d19011f5fd6f40c3445bdbe5f845ace to your computer and use it in GitHub Desktop.
Save Hamleyburger/0d19011f5fd6f40c3445bdbe5f845ace to your computer and use it in GitHub Desktop.
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")
{% 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 %}
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