This commit is contained in:
Isaak Buslovich 2024-01-19 19:46:42 +01:00
commit 62a835718a
14 changed files with 262 additions and 0 deletions

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/th_htmx_demo.iml" filepath="$PROJECT_DIR$/.idea/th_htmx_demo.iml" />
</modules>
</component>
</project>

28
app/__init__.py Normal file
View File

@ -0,0 +1,28 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SECRET_KEY'] = 'your-secret-key'
db.init_app(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from .models import User
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
return app

53
app/auth.py Normal file
View File

@ -0,0 +1,53 @@
from flask import Blueprint, request, render_template, redirect, url_for, flash
from flask_login import login_user, logout_user, login_required
from .models import User, db
from passlib.hash import argon2
auth = Blueprint('auth', __name__)
@auth.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# Check if username already exists
existing_user = User.query.filter_by(username=username).first()
if existing_user:
flash('Username already exists.')
return redirect(url_for('auth.register'))
# Create new user with hashed password
new_user = User(username=username)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
flash('Registration successful.')
return redirect(url_for('auth.login'))
return render_template('register.html')
@auth.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
login_user(user)
return redirect(url_for('main.index'))
flash('Invalid username or password.')
return render_template('login.html')
@auth.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('main.index'))

14
app/main.py Normal file
View File

@ -0,0 +1,14 @@
from flask import Blueprint, render_template
import random
main = Blueprint('main', __name__)
@main.route('/')
def index():
return render_template('index.html')
@main.route('/random-number')
def random_number():
return str(random.randint(1, 100))

16
app/models.py Normal file
View File

@ -0,0 +1,16 @@
from flask_sqlalchemy import SQLAlchemy
from passlib.hash import argon2
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
def set_password(self, password):
self.password_hash = argon2.hash(password)
def check_password(self, password):
return argon2.verify(password, self.password_hash)

25
app/routes.py Normal file
View File

@ -0,0 +1,25 @@
from flask import Blueprint, render_template, request, redirect, url_for
from .models import User, db
auth = Blueprint('auth', __name__)
@auth.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
new_user = User(username=username)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
return redirect(url_for('auth.login'))
return render_template('register.html')
@auth.route('/login', methods=['GET', 'POST'])
def login():
# Implement login logic
return render_template('login.html')

43
app/static/styles.css Normal file
View File

@ -0,0 +1,43 @@
@import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;700&display=swap');
body {
font-family: 'Lora', serif;
background-color: #fbfbfb;
color: #383a42;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 90%;
max-width: 400px;
text-align: center;
}
button {
background-color: #61afef;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #528bca;
}
@media (max-width: 600px) {
.card {
width: 80%;
}
}

15
app/templates/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Flask App</title>
</head>
<body>
<h1>Welcome to the Flask App</h1>
<nav>
<ul>
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
</ul>
</nav>
</body>
</html>

18
app/templates/login.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="card">
<h1>Login</h1>
<form method="POST">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<p>New user? <a href="{{ url_for('auth.register') }}">Register here</a></p>
</div>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="card">
<h1>Register</h1>
<form method="POST">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="{{ url_for('auth.login') }}">Login here</a></p>
</div>
</body>
</html>

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
Flask
Flask-SQLAlchemy
Flask-Login
passlib

11
run.py Normal file
View File

@ -0,0 +1,11 @@
from app import create_app, db
from app.models import User
app = create_app()
@app.before_first_request
def create_tables():
db.create_all()
if __name__ == '__main__':
app.run(debug=True) # Turn off debug in production