Skip to content
Snippets Groups Projects
Verified Commit fe38433b authored by Arun Joshua's avatar Arun Joshua
Browse files

Basic site and authentication

parent 6f291165
No related branches found
No related tags found
No related merge requests found
__pycache__
# Database
data.db
# Virtualenv
bam-venv
{
"python.formatting.provider": "black",
"python.formatting.blackPath": "black",
"editor.formatOnSave": true,
"[python]": {
"editor.defaultFormatter": null
}
}
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config["SECRET_KEY"] = "enterasecretkeyhere"
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///data.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
from bam import routes
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from bam.models import User
class RegistrationForm(FlaskForm):
email = StringField("Email", validators=[DataRequired(), Email()], render_kw={"placeholder": "Enter your email"})
password = PasswordField("Password", validators=[DataRequired()], render_kw={"placeholder": "Choose a strong password"})
confirm_password = PasswordField(
"Confirm Password", validators=[DataRequired(), EqualTo("password")],
render_kw={"placeholder":"Re-enter your password"}
)
submit = SubmitField("Sign Up")
def validate_email(self, email):
if User.query.filter_by(email=email.data).first():
raise ValidationError("A user with this email already exists.")
class LoginForm(FlaskForm):
email = StringField("Email", validators=[DataRequired(), Email()], render_kw={"placeholder": "bookmaster@bam.com"})
password = PasswordField("Password", validators=[DataRequired()], render_kw={"placeholder": "masterofbooks"})
remember = BooleanField("Remember Me")
submit = SubmitField("Login")
from bam import db, login_manager
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)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
def __repr__(self):
return f"User({self.email}, {self.password})"
from flask import render_template, url_for, flash, redirect
from flask_login import login_user, current_user, logout_user
from bam import app, db, bcrypt
from bam.forms import RegistrationForm, LoginForm
from bam.models import User
@app.route("/")
@app.route("/home")
def home():
if current_user.is_authenticated:
return render_template("dash.html")
return render_template("home.html")
@app.route("/register", methods=["GET", "POST"])
def register():
if current_user.is_authenticated:
return redirect(url_for("home"))
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode(
"utf-8"
)
user = User(email=form.email.data, password=hashed_password)
db.session.add(user)
db.session.commit()
flash(
f"Account successfully created! You may login now.", "success"
)
return redirect(url_for("login"))
return render_template("register.html", title="Register", form=form)
@app.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect(url_for("home"))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
return redirect(url_for("home"))
flash("Hmmm .. those credentials don't seem to be right", "error")
return render_template("login.html", title="Login", form=form)
@app.route("/logout")
def logout():
logout_user()
# flash("You have been successfully logged out", "success")
return redirect(url_for("home"))
\ No newline at end of file
.tagline {
font-size: 3.5rem;
text-align: center;
font-family: Roboto;
font-weight: 700;
text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.6);
}
.explanation {
text-align: center;
font-size: 1.5rem;
text-shadow: 1px 1px 5px rgba(0, 0, 0, 0.6);
}
.jk {
font-size: 0.7rem;
color: rgba(0, 0, 0, 0.1);
}
@media screen and (max-width: 600px) {
.tagline {
font-size: 2.5rem;
margin-bottom: 10px;
}
.explanation {
font-size: 1.3rem;
}
}
@media screen and (min-width: 1200px) {
.tagline {
font-size: 4rem;
margin-bottom: 10px;
}
.explanation {
font-size: 1.6rem;
}
}
.container {
background-color: var(--t-dark);
padding: 15px;
border-radius: 3px;
}
.f-message {
font-style: oblique;
}
h1 {
text-align: center;
}
form {
display: flex;
flex-direction: column;
gap: 5px;
min-width: min(90vw, 400px);
}
input {
font-family: Roboto;
font-size: 16px;
/* margin-bottom: 5px; */
border-radius: 3px;
padding: 17px;
background-color: var(--t-dark);
border: 1px solid black;
color: #eee;
transition: background 0.3s;
/* margin: 3px 0 10px; */
}
.field:hover {
background-color: rgba(0, 0, 0, 0.9);
}
.field:focus,
.field:active {
background-color: rgba(30, 30, 30, 0.5);
border: 1px solid grey;
}
label {
text-transform: uppercase;
font-weight: 700;
font-size: 0.9rem;
letter-spacing: 1px;
}
.field-error {
font-style: oblique;
color: var(--red);
font-size: 0.9rem;
}
[type="submit"] {
background-color: var(--red);
border: none;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
}
[type="submit"]:hover {
background-color: var(--dark-red);
cursor: pointer;
}
label,
[type="submit"] {
margin-top: 10px;
}
/* Checkbox - inspired by https://codepen.io/grayghostvisuals/pen/yOxGxz */
.remember-row {
display: flex;
align-items: center;
gap: 15px;
margin-top: 10px;
}
.remember-row input {
order: 2;
opacity: 0;
}
.checkbox-indicator {
display: flex;
height: 1.5rem;
width: 1.5rem;
border: 1px solid black;
align-items: center;
transition: border 0.2s ease;
background-color: var(--t-dark);
}
.checkbox-indicator svg {
height: 50%;
width: 100%;
fill: transparent;
}
.remember-row:hover .checkbox-indicator {
border: 1px solid grey;
background-color: rgba(30, 30, 30, 0.5);
}
.remember-input:checked + .checkbox-indicator svg {
fill: var(--red);
}
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap");
html,
body {
margin: 0;
padding: 0;
min-height: 100vh;
}
:root {
--red: #e50914;
--dark-red: #bb0009;
--t-dark: rgba(0, 0, 0, 0.8);
}
* {
box-sizing: border-box;
}
body {
background-image: url("https://i.imgur.com/4LLrhbS.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
color: white;
font-family: Roboto;
}
.maincontainer {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
.navbar {
height: 100px;
align-items: center;
padding: 20px 50px;
display: flex;
width: 100%;
gap: 10px;
}
.navbar .logo {
height: 100%;
}
.navbar .logo img {
height: 100%;
filter: drop-shadow(2px 2px 6px #000);
}
.navbar .space {
flex-grow: 1;
}
.navbar button {
background-color: var(--red);
border: none;
color: white;
padding: 5px 10px;
font-family: Roboto;
border-radius: 2px;
font-size: 1.1rem;
box-shadow: 1px 1px 5px black;
transition: background 0.3s;
cursor: pointer;
}
.navbar button:hover {
background-color: var(--dark-red);
}
.content {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 65ch;
max-width: 90vw;
}
.rowspacer {
height: 10vh;
}
.credits {
padding: 15px;
font-size: 0.7rem;
color: #460e0c;
opacity: 0.3;
}
@media screen and (max-width: 600px) {
.navbar {
padding: 15px;
height: 76px;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BAM - Dashboard</title>
</head>
<body>
Yaaay - you are authorized!
</body>
</html>
{% extends "outlayout.html" %} {% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='home.css') }}" />
{% endblock head %} {% block content %}
<div class="tagline">The only missing piece in your life.</div>
<div class="explanation">
BAM is an all-in-one Book Management System built on the principles of
simplicity and minimalism
</div>
<div class="jk">
Nah, just kidding, it wasn't built with anything in mind lol
</div>
{% endblock content %}
{% extends "outlayout.html" %} {% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='outform.css') }}" />
{% endblock head %} {% block content %}
<div class="container">
<form action="" method="POST">
{{ form.hidden_tag() }}
<h1>Sign In</h1>
{% with messages = get_flashed_messages(with_categories=True) %} {% if
messages %} {% for category, message in messages %}
<div class="f-message f-message-{{ category }}">{{ message }}</div>
{% endfor %} {% endif %} {% endwith %}
<!-- <div>Your account has been successfully created.</div> -->
{{ form.email.label() }} {{ form.email(class="field") }} {% for error in
form.email.errors %}
<div class="field-error">{{ error }}</div>
{% endfor %} {{ form.password.label() }} {{ form.password(class="field") }}
{% for error in form.password.errors %}
<div class="field-error">{{ error }}</div>
{% endfor %}
<label for="{{ form.remember.label.field_id }}" class="remember-row">
{{ form.remember(class="remember-input") }}
<span class="checkbox-indicator" aria-hidden="true">
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 21 16"
>
<path
d="M21,2.1L7.3,16l-0.4-0.4l-0.3,0.3L0,9.3l2.1-2.1l4.9,4.9L18.9,0L21,2.1z"
/>
</svg>
</span>
<div>{{ form.remember.label.text }}</div>
</label>
{{ form.submit() }}
</form>
</div>
{% endblock content %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% if title %}
<title>BAM - {{ title }}</title>
{% else %}
<title>BAM</title>
{% endif %}
<link
rel="stylesheet"
href="{{ url_for('static', filename='outlayout.css') }}"
/>
{% block head %}{% endblock %}
</head>
<body>
<div class="maincontainer">
<div class="navbar">
<div class="logo">
<a href="{{ url_for('home') }}">
<img src="https://i.imgur.com/t2ZlJ06.png" />
</a>
</div>
<div class="space"></div>
<a href="{{ url_for('login') }}"><button>Sign In</button></a>
<a href="{{ url_for('register') }}"><button>Register</button></a>
</div>
<div class="content">{% block content %}{% endblock %}</div>
<div class="rowspacer"></div>
<div class="credits">Built with ❤ using Flask</div>
</div>
</body>
</html>
{% extends "outlayout.html" %} {% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='outform.css') }}" />
{% endblock head %} {% block content %}
<div class="container">
<form action="" method="POST">
{{ form.hidden_tag() }}
<h1>Create an account</h1>
{{ form.email.label() }} {{ form.email(class="field") }} {% for error in
form.email.errors %}
<div class="field-error">{{ error }}</div>
{% endfor %} {{ form.password.label() }} {{ form.password(class="field") }}
{% for error in form.password.errors %}
<div class="field-error">{{ error }}</div>
{% endfor %} {{ form.confirm_password.label() }} {{
form.confirm_password(class="field") }} {% for error in
form.confirm_password.errors %}
<div class="field-error">{{ error }}</div>
{% endfor %}
<input type="submit" value="Sign in" />
</form>
</div>
{% endblock content %}
from bam import db
db.create_all()
appdirs==1.4.4
bcrypt==3.2.0
black==20.8b1
cffi==1.14.4
click==7.1.2
dnspython==2.0.0
email-validator==1.1.2
Flask==1.1.2
Flask-Bcrypt==0.7.1
Flask-Login==0.5.0
Flask-SQLAlchemy==2.4.4
Flask-WTF==0.14.3
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
mypy-extensions==0.4.3
pathspec==0.8.1
pycparser==2.20
regex==2020.11.13
six==1.15.0
SQLAlchemy==1.3.22
toml==0.10.2
typed-ast==1.4.1
typing-extensions==3.7.4.3
Werkzeug==1.0.1
WTForms==2.3.3
run.py 0 → 100644
from bam import app
if __name__ == "__main__":
app.run(debug=True)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment