Skip to content

Commit

Permalink
Code after the thirteenth episode of Flask Series
Browse files Browse the repository at this point in the history
  • Loading branch information
jimdevops19 committed Jan 10, 2021
1 parent cb399ac commit fdbe66b
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 0 deletions.
14 changes: 14 additions & 0 deletions 13 - Logout & Customizations/market/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///market.db'
app.config['SECRET_KEY'] = 'ec9439cfc6c796ae2029594d'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = "login_page"
login_manager.login_message_category = "info"
from market import routes
28 changes: 28 additions & 0 deletions 13 - Logout & Customizations/market/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import Length, EqualTo, Email, DataRequired, ValidationError
from market.models import User


class RegisterForm(FlaskForm):
def validate_username(self, username_to_check):
user = User.query.filter_by(username=username_to_check.data).first()
if user:
raise ValidationError('Username already exists! Please try a different username')

def validate_email_address(self, email_address_to_check):
email_address = User.query.filter_by(email_address=email_address_to_check.data).first()
if email_address:
raise ValidationError('Email Address already exists! Please try a different email address')

username = StringField(label='User Name:', validators=[Length(min=2, max=30), DataRequired()])
email_address = StringField(label='Email Address:', validators=[Email(), DataRequired()])
password1 = PasswordField(label='Password:', validators=[Length(min=6), DataRequired()])
password2 = PasswordField(label='Confirm Password:', validators=[EqualTo('password1'), DataRequired()])
submit = SubmitField(label='Create Account')


class LoginForm(FlaskForm):
username = StringField(label='User Name:', validators=[DataRequired()])
password = PasswordField(label='Password:', validators=[DataRequired()])
submit = SubmitField(label='Sign in')
Binary file added 13 - Logout & Customizations/market/market.db
Binary file not shown.
43 changes: 43 additions & 0 deletions 13 - Logout & Customizations/market/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from market import db, login_manager
from market import bcrypt
from flask_login import UserMixin

@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

class User(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(length=30), nullable=False, unique=True)
email_address = db.Column(db.String(length=50), nullable=False, unique=True)
password_hash = db.Column(db.String(length=60), nullable=False)
budget = db.Column(db.Integer(), nullable=False, default=1000)
items = db.relationship('Item', backref='owned_user', lazy=True)

@property
def prettier_budget(self):
if len(str(self.budget)) >= 4:
return f'{str(self.budget)[:-3]},{str(self.budget)[-3:]}$'
else:
return f"{self.budget}$"

@property
def password(self):
return self.password

@password.setter
def password(self, plain_text_password):
self.password_hash = bcrypt.generate_password_hash(plain_text_password).decode('utf-8')

def check_password_correction(self, attempted_password):
return bcrypt.check_password_hash(self.password_hash, attempted_password)

class Item(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(length=30), nullable=False, unique=True)
price = db.Column(db.Integer(), nullable=False)
barcode = db.Column(db.String(length=12), nullable=False, unique=True)
description = db.Column(db.String(length=1024), nullable=False, unique=True)
owner = db.Column(db.Integer(), db.ForeignKey('user.id'))
def __repr__(self):
return f'Item {self.name}'
67 changes: 67 additions & 0 deletions 13 - Logout & Customizations/market/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from market import app
from flask import render_template, redirect, url_for, flash
from market.models import Item, User
from market.forms import RegisterForm, LoginForm
from market import db
from flask_login import login_user, logout_user, login_required

@app.route('/')
@app.route('/home')
def home_page():
return render_template('home.html')

@app.route('/market')
@login_required
def market_page():
items = Item.query.all()
return render_template('market.html', items=items)

@app.route('/register', methods=['GET', 'POST'])
def register_page():
form = RegisterForm()
if form.validate_on_submit():
user_to_create = User(username=form.username.data,
email_address=form.email_address.data,
password=form.password1.data)
db.session.add(user_to_create)
db.session.commit()
login_user(user_to_create)
flash(f"Account created successfully! You are now logged in as {user_to_create.username}", category='success')
return redirect(url_for('market_page'))
if form.errors != {}: #If there are not errors from the validations
for err_msg in form.errors.values():
flash(f'There was an error with creating a user: {err_msg}', category='danger')

return render_template('register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login_page():
form = LoginForm()
if form.validate_on_submit():
attempted_user = User.query.filter_by(username=form.username.data).first()
if attempted_user and attempted_user.check_password_correction(
attempted_password=form.password.data
):
login_user(attempted_user)
flash(f'Success! You are logged in as: {attempted_user.username}', category='success')
return redirect(url_for('market_page'))
else:
flash('Username and password are not match! Please try again', category='danger')

return render_template('login.html', form=form)

@app.route('/logout')
def logout_page():
logout_user()
flash("You have been logged out!", category='info')
return redirect(url_for("home_page"))










89 changes: 89 additions & 0 deletions 13 - Logout & Customizations/market/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<title>
{% block title %}

{% endblock %}
</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<a class="navbar-brand" href="#">Flask Market</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="{{ url_for('home_page') }}">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('market_page') }}">Market</a>
</li>
</ul>
{% if current_user.is_authenticated %}
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" style="color: lawngreen; font-weight: bold">
<i class="fas fa-coins"></i>
{{ current_user.prettier_budget }}
</a>
</li>
<li class="nav-item">
<a class="nav-link">Welcome, {{ current_user.username }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout_page') }}">Logout</a>
</li>
</ul>
{% else %}
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login_page') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register_page') }}">Register</a>
</li>
</ul>
{% endif %}
</div>
</nav>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
<button type="button" class="m1-2 mb-1 close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}

{% endblock %}
<!-- Future Content here -->



<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src='https://kit.fontawesome.com/a076d05399.js'></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
</body>
<style>
body {
background-color: #212121;
color: white
}
</style>
</html>
15 changes: 15 additions & 0 deletions 13 - Logout & Customizations/market/templates/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block title %}
Welcome to Jim Shaped Coding Market
{% endblock %}
{% block content %}
<div class="position-relative overflow-hidden p-3 p-md-5 m-md-3 text-center bg-dark" style="color:white">
<div class="col-md-5 p-lg-5 mx-auto my-5">
<h1 class="display-4 font-weight-normal">Jim Shaped Coding Market</h1>
<p class="lead font-weight-normal">Start purchasing products by clicking the link below</p>
<a class="btn btn-primary" href="{{ url_for('market_page') }}">Get Started</a>
</div>
<div class="product-device box-shadow d-none d-md-block"></div>
<div class="product-device product-device-2 box-shadow d-none d-md-block"></div>
</div>
{% endblock %}
35 changes: 35 additions & 0 deletions 13 - Logout & Customizations/market/templates/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{% extends 'base.html' %}
{% block title %}
Login Page
{% endblock %}

{% block content %}
<body class="text-center">
<div class="container">
<form method="POST" class="form-signin" style="color:white">
{{ form.hidden_tag() }}
<img class="mb-4" src="https://res.cloudinary.com/jimshapedcoding/image/upload/v1597332609/android-icon-192x192_ove2a7.png" alt="">
<h1 class="h3 mb-3 font-weight-normal">
Please Login
</h1>
<br>
{{ form.username.label() }}
{{ form.username(class="form-control", placeholder="User Name") }}

{{ form.password.label() }}
{{ form.password(class="form-control", placeholder="Password") }}

<br>


<div class="checkbox mb-3">
<h6>Do not have an account?</h6>
<a class="btn btn-sm btn-secondary" href="{{ url_for('register_page') }}">Register</a>
</div>

{{ form.submit(class="btn btn-lg btn-block btn-primary") }}

</form>
</div>
</body>
{% endblock %}
34 changes: 34 additions & 0 deletions 13 - Logout & Customizations/market/templates/market.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{% extends 'base.html' %}
{% block title %}
Market Page
{% endblock %}

{% block content %}
<table class="table table-hover table-dark">
<thead>
<tr>
<!-- Your Columns HERE -->
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Barcode</th>
<th scope="col">Price</th>
<th scope="col">Options</th>
</tr>
</thead>
<tbody>
<!-- Your rows inside the table HERE: -->
{% for item in items %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.barcode }}</td>
<td>{{ item.price }}$</td>
<td>
<button class="btn btn-outline btn-info">More Info</button>
<button class="btn btn-outline btn-success">Purchase this Item</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
40 changes: 40 additions & 0 deletions 13 - Logout & Customizations/market/templates/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{% extends 'base.html' %}
{% block title %}
Register Page
{% endblock %}

{% block content %}
<body class="text-center">
<div class="container">
<form method="POST" class="form-register" style="color:white">
{{ form.hidden_tag() }}
<img class="mb-4" src="https://res.cloudinary.com/jimshapedcoding/image/upload/v1597332609/android-icon-192x192_ove2a7.png" alt="">
<h1 class="h3 mb-3 font-weight-normal">
Please Create your Account
</h1>
<br>
{{ form.username.label() }}
{{ form.username(class="form-control", placeholder="User Name") }}

{{ form.email_address.label() }}
{{ form.email_address(class="form-control", placeholder="Email Address") }}

{{ form.password1.label() }}
{{ form.password1(class="form-control", placeholder="Password") }}

{{ form.password2.label() }}
{{ form.password2(class="form-control", placeholder="Confirm Password") }}

<br>

<div class="checkbox mb-3">
<h6>Already have an account?</h6>
<a class="btn btn-sm btn-secondary" href="{{ url_for('login_page') }}">Login</a>
</div>

{{ form.submit(class="btn btn-lg btn-block btn-primary") }}

</form>
</div>
</body>
{% endblock %}
5 changes: 5 additions & 0 deletions 13 - Logout & Customizations/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from market import app

#Checks if the run.py file has executed directly and not imported
if __name__ == '__main__':
app.run(debug=True)

0 comments on commit fdbe66b

Please sign in to comment.