Initial commit

This commit is contained in:
bvandeusen
2025-07-28 21:57:49 +00:00
commit d200550b35
41 changed files with 591 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()
def create_app(config_class='config.Config'):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
login_manager.login_view = 'auth.login' # IMPORTANT: now uses auth Blueprint
from app.main import main
from app.auth import auth
app.register_blueprint(main)
app.register_blueprint(auth)
return app
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+41
View File
@@ -0,0 +1,41 @@
# app/auth.py
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, login_required
from werkzeug.security import generate_password_hash, check_password_hash
from app import db
from app.models import User
from app.forms import RegistrationForm, LoginForm
auth = Blueprint('auth', __name__, url_prefix='/auth')
@auth.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = generate_password_hash(form.password.data)
user = User(username=form.username.data, email=form.email.data, password_hash=hashed_password)
db.session.add(user)
db.session.commit()
flash('Account created! Please log in.', 'success')
return redirect(url_for('auth.login'))
return render_template('register.html', form=form)
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and check_password_hash(user.password_hash, form.password.data):
login_user(user)
return redirect(url_for('main.index'))
else:
flash('Login failed. Check username/password.', 'danger')
return render_template('login.html', form=form)
@auth.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('main.index'))
+26
View File
@@ -0,0 +1,26 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, ValidationError, Length
from .models import User
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=3, max=64)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=8, max=64)])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('Username already exists.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('Email already registered.')
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
+9
View File
@@ -0,0 +1,9 @@
# app/main.py
from flask import Blueprint, render_template
main = Blueprint('main', __name__)
@main.route('/')
def index():
return render_template('index.html')
+13
View File
@@ -0,0 +1,13 @@
from . import db
from flask_login import UserMixin
from . import login_manager
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(256), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
+4
View File
@@ -0,0 +1,4 @@
.error {
color: red;
font-size: 0.9em;
}
+8
View File
@@ -0,0 +1,8 @@
{% extends "layout.html" %}
{% block title %}Home{% endblock %}
{% block content %}
<h1>Welcome to the Flask Template App!</h1>
<p>This is the index page.</p>
{% endblock %}
+37
View File
@@ -0,0 +1,37 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Flask Template App</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<header>
{% if current_user.is_authenticated %}
Hello {{ current_user.username }} |
<a href="{{ url_for('auth.logout') }}">Logout</a>
{% else %}
<a href="{{ url_for('auth.login') }}">Login</a> |
<a href="{{ url_for('auth.register') }}">Register</a>
{% endif %}
</header>
<!-- FLASH MESSAGES -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="flash {{ category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<hr>
<!-- MAIN CONTENT -->
{% block content %}{% endblock %}
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
{% extends "layout.html" %}
{% block content %}
<h2>Login</h2>
<form method="POST">
{{ form.hidden_tag() }}
{{ form.email(size=32, placeholder=form.email.label.text) }}<br>
{{ form.password(size=32, placeholder=form.password.label.text) }}<br>
{{ form.submit() }}
</form>
{% endblock %}
+39
View File
@@ -0,0 +1,39 @@
{% extends "layout.html" %}
{% block content %}
<h2>Register</h2>
<form method="POST">
{{ form.hidden_tag() }}
<p>
{{ form.username(size=32, placeholder=form.username.label.text) }}
{% for error in form.username.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</p>
<p>
{{ form.email(size=32, placeholder=form.email.label.text) }}
{% for error in form.email.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</p>
<p>
{{ form.password(size=32, placeholder=form.password.label.text) }}
{% for error in form.password.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</p>
<p>
{{ form.confirm_password(size=32, placeholder=form.confirm_password.label.text) }}
{% for error in form.confirm_password.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</p>
<p>
{{ form.submit() }}
</p>
</form>
{% endblock %}