intitial
This commit is contained in:
commit
62a835718a
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal 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
8
.idea/modules.xml
Normal 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
28
app/__init__.py
Normal 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
53
app/auth.py
Normal 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
14
app/main.py
Normal 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
16
app/models.py
Normal 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
25
app/routes.py
Normal 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
43
app/static/styles.css
Normal 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
15
app/templates/index.html
Normal 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
18
app/templates/login.html
Normal 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>
|
||||
18
app/templates/register.html
Normal file
18
app/templates/register.html
Normal 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
4
requirements.txt
Normal file
@ -0,0 +1,4 @@
|
||||
Flask
|
||||
Flask-SQLAlchemy
|
||||
Flask-Login
|
||||
passlib
|
||||
Loading…
Reference in New Issue
Block a user