diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..ee8b618 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,19 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_login import LoginManager + +db = SQLAlchemy() +login_manager = LoginManager() + +def create_app(): + app = Flask(__name__) + app.config['SECRET_KEY'] = 'your_secret_key' + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///webapp.db' + db.init_app(app) + login_manager.init_app(app) + + with app.app_context(): + from . import routes, models + db.create_all() + + return app \ No newline at end of file diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..4a67f83 --- /dev/null +++ b/app/forms.py @@ -0,0 +1,9 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField, SubmitField +from wtforms.validators import DataRequired, Length, EqualTo + +class LoginForm(FlaskForm): + username = StringField('Username', validators=[DataRequired(), Length(min=4, max=150)]) + password = PasswordField('Password', validators=[DataRequired()]) + remember_me = BooleanField('Remember Me') + submit = SubmitField('Login') \ No newline at end of file diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..e0e8763 --- /dev/null +++ b/app/models.py @@ -0,0 +1,8 @@ +from . import db +from flask_login import UserMixin + +class User(UserMixin, db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(150), unique=True, nullable=False) + password = db.Column(db.String(150), nullable=False) + is_admin = db.Column(db.Boolean, default=False) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py new file mode 100644 index 0000000..f358db3 --- /dev/null +++ b/app/routes.py @@ -0,0 +1,38 @@ +from flask import render_template, redirect, url_for, flash, request +from flask_login import login_user, logout_user, login_required, current_user +from app import app, db +from app.forms import LoginForm +from app.models import User + +@app.route('/') +@app.route('/home') +def home(): + return render_template('home.html') + +@app.route('/admin') +@login_required +def admin(): + if not current_user.is_admin: + flash('You do not have permission to access this page.') + return redirect(url_for('home')) + return render_template('admin.html') + +@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(username=form.username.data).first() + if user and user.check_password(form.password.data): + login_user(user, remember=form.remember_me.data) + next_page = request.args.get('next') + return redirect(next_page) if next_page else redirect(url_for('home')) + else: + flash('Invalid username or password') + return render_template('login.html', form=form) + +@app.route('/logout') +def logout(): + logout_user() + return redirect(url_for('home')) \ No newline at end of file diff --git a/app/static/css/styles.css b/app/static/css/styles.css new file mode 100644 index 0000000..4142a2b --- /dev/null +++ b/app/static/css/styles.css @@ -0,0 +1,37 @@ +/* Base styles */ +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; +} + +/* Navigation styles */ +nav { + @apply bg-gray-800 text-white p-4; +} + +nav a { + @apply text-white mx-4 no-underline; +} + +/* Form styles */ +form { + @apply max-w-md mx-auto my-8 p-6 bg-white rounded-lg shadow-md; +} + +form label { + @apply block mb-2; +} + +form input { + @apply w-full p-2 mb-4 border border-gray-300 rounded; +} + +form button { + @apply py-2 px-4 bg-gray-800 text-white rounded cursor-pointer; +} + +form button:hover { + @apply bg-gray-700; +} \ No newline at end of file diff --git a/app/static/js/scripts.js b/app/static/js/scripts.js new file mode 100644 index 0000000..a2d2ba6 --- /dev/null +++ b/app/static/js/scripts.js @@ -0,0 +1,13 @@ +// JavaScript for handling form submissions and other dynamic behavior + +// Example function to handle form submission +document.addEventListener('DOMContentLoaded', function() { + const form = document.querySelector('form'); + if (form) { + form.addEventListener('submit', function(event) { + event.preventDefault(); + // Add form validation or submission logic here + alert('Form submitted!'); + }); + } +}); \ No newline at end of file diff --git a/app/templates/admin.html b/app/templates/admin.html new file mode 100644 index 0000000..c2aef56 --- /dev/null +++ b/app/templates/admin.html @@ -0,0 +1,47 @@ + + + + + + Admin Dashboard + + + +
+ +
+
+

Admin Dashboard

+
+

Manage Users

+ + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
UsernameRoleActions
{{ user.username }}{{ user.role }} + + +
+
+
+ + \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..27036a8 --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,7 @@ + + + + + + {% block title %}Flask App{% endblock %} + \ No newline at end of file diff --git a/app/templates/home.html b/app/templates/home.html new file mode 100644 index 0000000..f55d7cf --- /dev/null +++ b/app/templates/home.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} +{% block title %}Home{% endblock %} +{% block content %} +

Welcome to the Flask App

+

This is the homepage of the Flask application.

+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..762e194 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,32 @@ + + + + + + Login + + + +
+ +
+
+

Login

+
+ + + + + + + +
+
+ + \ No newline at end of file diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..69a4719 --- /dev/null +++ b/plan.md @@ -0,0 +1,56 @@ +# Flask Application Boilerplate Plan + +## Overview +This plan outlines the steps to create a comprehensive Flask application boilerplate that integrates Tailwind CSS for styling, HTML templates for the frontend, and includes the following features: + +1. **Homepage**: A welcoming landing page with basic navigation. +2. **Admin Page**: A secure admin dashboard for managing users, accessible only to authenticated administrators. +3. **Login Page**: A secure login page with two-factor authentication (2FA) for enhanced security. +4. **Database**: Use SQLite for the database, with the database file named `webapp.db` and the first username set to `admin`. + +## Project Structure +The application will be structured with proper routing, authentication mechanisms, and session management. Necessary configurations for Tailwind CSS and HTML templates will be included. + +## Steps to Implement the Plan + +### 1. Set Up the Flask Application +- Create the basic Flask application structure. +- Set up the necessary configurations for Tailwind CSS and HTML templates. + +### 2. Create the Homepage +- Design a welcoming landing page with basic navigation. +- Implement the necessary routes and templates. + +### 3. Create the Admin Page +- Design a secure admin dashboard for managing users. +- Implement authentication mechanisms to restrict access to authenticated administrators. +- Implement the necessary routes and templates. + +### 4. Create the Login Page +- Design a secure login page with two-factor authentication (2FA). +- Implement the necessary routes and templates. +- Set up the authentication mechanisms for the login page. + +### 5. Set Up the Database +- Use SQLite for the database. +- Create the necessary database schema. +- Implement the database connection and queries. + +### 6. Provide Instructions for Setting Up and Running the Application +- Write clear instructions for setting up and running the application. + +## Mermaid Diagram + +```mermaid +graph TD + A[Start] --> B[Set Up Flask Application] + B --> C[Create Homepage] + C --> D[Create Admin Page] + D --> E[Create Login Page] + E --> F[Set Up Database] + F --> G[Provide Instructions] + G --> H[End] +``` + +## Next Steps +- Switch to another mode to implement the solution based on this plan. \ No newline at end of file