Skip to content

Commit

Permalink
base login signup htmls
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtenberger committed May 28, 2024
1 parent 2216e87 commit c5834f3
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 1 deletion.
108 changes: 108 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import os
from flask import Flask, render_template, redirect, session, g, flash

from forms import LoginForm, UserAddForm, CocktailForm
from models import db, connect_db, User, Cocktails

CURR_USER_KEY = 'curr_user'

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = (os.environ.get('DATABASE_URL', 'postgresql://drinks'))
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = False
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', "it's a secret")

connect_db(app)

# User join/login/logout

@app.before_request
def add_user_to_g():
"""If we're logged in, add curr user to Flask global."""

if CURR_USER_KEY in session:
g.user = User.query.get(session[CURR_USER_KEY])

else:
g.user = None


def do_login(user):
"""Log in user."""

session[CURR_USER_KEY] = user.id


def do_logout():
"""Logout user."""

if CURR_USER_KEY in session:
del session[CURR_USER_KEY]


@app.route('/signup', methods=["GET", "POST"])
def signup():
"""Handle user signup.
Create new user and add to DB. Redirect to home page.
If form not valid, present form.
If the there already is a user with that username: flash message
and re-present form.
"""
if CURR_USER_KEY in session:
del session[CURR_USER_KEY]
form = UserAddForm()

if form.validate_on_submit():
try:
user = User.signup(
username=form.username.data,
password=form.password.data,
email=form.email.data
)
db.session.commit()

except IntegrityError as e:
flash("Username already taken", 'danger')
return render_template('users/signup.html', form=form)

do_login(user)

return redirect("/")

else:
return render_template('users/signup.html', form=form)


@app.route('/login', methods=["GET", "POST"])
def login():
"""Handle user login."""

form = LoginForm()

if form.validate_on_submit():
user = User.authenticate(form.username.data,
form.password.data)

if user:
do_login(user)
flash(f"Hello, {user.username}!", "success")
return redirect("/")

flash("Invalid credentials.", 'danger')

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


@app.route('/logout')
def logout():
"""Handle logout of user."""

do_logout()

flash("You have successfully logged out.", 'success')
return redirect("/login")

22 changes: 22 additions & 0 deletions forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, TextAreaField
from wtforms.validators import DataRequired, Email, Length

class UserAddForm(FlaskForm):
'''Form for adding users'''

username = StringField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[Length(min=8)])

class LoginForm(FlaskForm):
'''Form for logging in user'''

username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[Length(min=8)])

class CocktailForm(FlaskForm):
'''Form for choosing cocktail to make'''

cocktail = StringField('Cocktail')
ingredients = StringField('Ingredient')
90 changes: 90 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy

bcrypt = Bcrypt()
db = SQLAlchemy()

class Cocktails(db.Model):
'''Cocktails'''

__tablename__ = 'cocktails'

name = db.Column(db.Text, )
image = db.Column(db.Text, )
instructions = db.Column(db.Text, )
ingredients = db.Column(db.Text, )
measurements = db.Column(db.Text, )


'''' USER CLASS'''


class User(db.Model):
"""User in the system."""

__tablename__ = 'users'

id = db.Column(
db.Integer,
primary_key=True,
)

email = db.Column(
db.Text,
nullable=False,
unique=True,
)

username = db.Column(
db.Text,
nullable=False,
unique=True,
)

password = db.Column(
db.Text,
nullable=False,
)


def __repr__(self):
return f"<User #{self.id}: {self.username}, {self.email}>"


@classmethod
def signup(cls, username, email, password):
"""Sign up user.
Hashes password and adds user to system.
"""

hashed_pwd = bcrypt.generate_password_hash(password).decode('UTF-8')

user = User(
username=username,
email=email,
password=hashed_pwd,
)

db.session.add(user)
return user

@classmethod
def authenticate(cls, username, password):
"""Find user with `username` and `password`.
This is a class method (call it on the class, not an individual user.)
It searches for a user whose password hash matches this password
and, if it finds such a user, returns that user object.
If can't find matching user (or if password is wrong), returns False.
"""

user = cls.query.filter_by(username=username).first()

if user:
is_auth = bcrypt.check_password_hash(user.password, password)
if is_auth:
return user

return False
3 changes: 2 additions & 1 deletion schema.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
Schema for Cocktail App

Table 1 - Users
Table 1 - User
username
password
email

Table 2 - Cocktails
name
Expand Down
62 changes: 62 additions & 0 deletions templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Cocktail App</title>

<link rel="stylesheet"
href="https://unpkg.com/bootstrap/dist/css/bootstrap.css">
<script src="https://unpkg.com/jquery"></script>
<script src="https://unpkg.com/popper"></script>
<script src="https://unpkg.com/bootstrap"></script>

<link rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<link rel="stylesheet" href="/static/stylesheets/style.css">
<link rel="shortcut icon" href="/static/favicon.ico">
</head>

<body class="{% block body_class %}{% endblock %}">
<nav class="navbar navbar-expand">
<div class="container-fluid">
<div class="navbar-header">
<a href="/" class="navbar-brand">
<span>Cocktail</span>
</a>
</div>
<ul class="nav navbar-nav navbar-right">
{% if request.endpoint != None %}
<!-- <li>
<form class="navbar-form navbar-right" action="/users">
<input name="q" class="form-control" placeholder="Search Warbler" id="search">
<button class="btn btn-default">
<span class="fa fa-search"></span>
</button>
</form>
</li> -->
{% endif %}
{% if not g.user %}
<li><a href="/signup">Sign up</a></li>
<li><a href="/login">Log in</a></li>
{% else %}
<li>
<a href="/users/{{ g.user.id }}">
</a>
</li>
<li><a href="/logout">Log out</a></li>
{% endif %}
</ul>
</div>
</nav>
<!-- <div class="container">
{% for category, message in get_flashed_messages(with_categories=True) %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% block content %}
{% endblock %}
</div> -->
</body>
</html>
26 changes: 26 additions & 0 deletions templates/user/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% extends 'base.html' %}

{% block body_class %}onboarding{% endblock %}

{% block content %}

<div class="row justify-content-md-center">
<div class="col-md-7 col-lg-5">
<h2 class="join-message">Welcome back.</h2>

<form method="POST" id="user_form">
{{ form.hidden_tag() }}

{% for field in form if field.widget.input_type != 'hidden' %}
{% for error in field.errors %}
<span class="text-danger">{{ error }}</span>
{% endfor %}
{{ field(placeholder=field.label.text, class="form-control") }}
{% endfor %}

<button class="btn btn-primary btn-block btn-lg">Log in</button>
</form>
</div>
</div>

{% endblock %}
25 changes: 25 additions & 0 deletions templates/user/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{% extends 'base.html' %}

{% block body_class %}onboarding{% endblock %}

{% block content %}

<div class="row justify-content-md-center">
<div class="col-md-7 col-lg-5">
<h2 class="join-message">Join Warbler today.</h2>
<form method="POST" id="user_form">
{{ form.hidden_tag() }}

{% for field in form if field.widget.input_type != 'hidden' %}
{% for error in field.errors %}
<span class="text-danger">{{ error }}</span>
{% endfor %}
{{ field(placeholder=field.label.text, class="form-control") }}
{% endfor %}

<button class="btn btn-primary btn-lg btn-block">Sign me up!</button>
</form>
</div>
</div>

{% endblock %}

0 comments on commit c5834f3

Please sign in to comment.