Skip to content

Commit

Permalink
Release v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
app-generator committed Nov 11, 2024
1 parent ae3e45a commit a4fad23
Show file tree
Hide file tree
Showing 13 changed files with 385 additions and 1 deletion.
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Flask
instance/
.webassets-cache
app.db

# Virtual Environment
venv/
ENV/

# IDE
.idea/
.vscode/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,63 @@
# docs-flask-simple-app
# Flask Authentication Project

A simple Flask application demonstrating authentication, SQLAlchemy ORM, and a REST API.

## Features

- User authentication (login/register/logout)
- Public and protected routes
- SQLite database with SQLAlchemy ORM
- REST API endpoint for users
- Bootstrap-styled templates

## Installation

1. Create a virtual environment:
```bash
python -m venv venv
```

2. Activate the virtual environment:
- Windows:
```bash
venv\Scripts\activate
```
- Unix or MacOS:
```bash
source venv/bin/activate
```

3. Install requirements:
```bash
pip install -r requirements.txt
```

4. Run the application:
```bash
python run.py
```

## Routes

- `/` - Public homepage
- `/private` - Protected route (requires login)
- `/api/users` - API endpoint listing all users
- `/login` - User login
- `/register` - User registration
- `/logout` - User logout

## API Usage

Get list of all users:
```bash
curl http://localhost:5000/api/users
```

## Security Note

This is a demonstration project. In a production environment, you should:
- Use a proper secret key
- Enable HTTPS
- Implement proper password validation
- Add rate limiting
- Use environment variables for sensitive data
24 changes: 24 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from app.config import Config

db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth.login'

def create_app():
app = Flask(__name__)
app.config.from_object(Config)

db.init_app(app)
login_manager.init_app(app)

from app.routes import main, auth
app.register_blueprint(main)
app.register_blueprint(auth)

with app.app_context():
db.create_all()

return app
4 changes: 4 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Config:
SECRET_KEY = 'your-secret-key-here' # Change this to a secure secret key
SQLALCHEMY_DATABASE_URI = 'sqlite:///app.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
18 changes: 18 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from app import db, 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)
password_hash = db.Column(db.String(128))

def set_password(self, password):
self.password_hash = generate_password_hash(password)

def check_password(self, password):
return check_password_hash(self.password_hash, password)

@login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
61 changes: 61 additions & 0 deletions app/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from flask import Blueprint, render_template, redirect, url_for, request, jsonify
from flask_login import login_user, logout_user, login_required, current_user
from app.models import User, db

main = Blueprint('main', __name__)
auth = Blueprint('auth', __name__)

# Public homepage route
@main.route('/')
def home():
return render_template('home.html')

# Protected route
@main.route('/private')
@login_required
def private():
return render_template('private.html')

# API route to list users
@main.route('/api/users')
def list_users():
users = User.query.all()
return jsonify([{'id': user.id, 'username': user.username} for user in users])

# Authentication routes
@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.private'))

return render_template('login.html')

@auth.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')

if User.query.filter_by(username=username).first():
return "Username already exists"

user = User(username=username)
user.set_password(password)
db.session.add(user)
db.session.commit()

return redirect(url_for('auth.login'))

return render_template('register.html')

@auth.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('main.home'))
62 changes: 62 additions & 0 deletions app/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">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{% endblock %} - Flask App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
<div class="container">
<a class="navbar-brand" href="{{ url_for('main.home') }}">Flask App</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.home') }}">Home</a>
</li>
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.private') }}">Private</a>
</li>
{% endif %}
</ul>
<ul class="navbar-nav">
{% if current_user.is_authenticated %}
<li class="nav-item">
<span class="nav-link">Welcome, {{ current_user.username }}!</span>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.register') }}">Register</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>

<div class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}

{% block content %}{% endblock %}
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions app/templates/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends "base.html" %}

{% block title %}Home{% endblock %}

{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<h1 class="card-title">Welcome to Flask App</h1>
<p class="card-text">This is a public page that anyone can access.</p>
{% if not current_user.is_authenticated %}
<p class="card-text">
<a href="{{ url_for('auth.login') }}" class="btn btn-primary">Login</a> or
<a href="{{ url_for('auth.register') }}" class="btn btn-success">Register</a>
to access private content.
</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
31 changes: 31 additions & 0 deletions app/templates/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends "base.html" %}

{% block title %}Login{% endblock %}

{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h2 class="card-title text-center mb-4">Login</h2>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Login</button>
</div>
</form>
<p class="text-center mt-3">
Don't have an account? <a href="{{ url_for('auth.register') }}">Register here</a>
</p>
</div>
</div>
</div>
</div>
{% endblock %}
17 changes: 17 additions & 0 deletions app/templates/private.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends "base.html" %}

{% block title %}Private Page{% endblock %}

{% block content %}
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<h1 class="card-title">Private Page</h1>
<p class="card-text">Welcome to the private page, {{ current_user.username }}!</p>
<p class="card-text">This content is only visible to authenticated users.</p>
</div>
</div>
</div>
</div>
{% endblock %}
31 changes: 31 additions & 0 deletions app/templates/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends "base.html" %}

{% block title %}Register{% endblock %}

{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h2 class="card-title text-center mb-4">Register</h2>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-success">Register</button>
</div>
</form>
<p class="text-center mt-3">
Already have an account? <a href="{{ url_for('auth.login') }}">Login here</a>
</p>
</div>
</div>
</div>
</div>
{% endblock %}
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
Flask-Login==0.6.3
werkzeug==3.0.1
Loading

0 comments on commit a4fad23

Please sign in to comment.