test
This commit is contained in:
19
app/__init__.py
Normal file
19
app/__init__.py
Normal file
@@ -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
|
||||
9
app/forms.py
Normal file
9
app/forms.py
Normal file
@@ -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')
|
||||
8
app/models.py
Normal file
8
app/models.py
Normal file
@@ -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)
|
||||
38
app/routes.py
Normal file
38
app/routes.py
Normal file
@@ -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'))
|
||||
37
app/static/css/styles.css
Normal file
37
app/static/css/styles.css
Normal file
@@ -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;
|
||||
}
|
||||
13
app/static/js/scripts.js
Normal file
13
app/static/js/scripts.js
Normal file
@@ -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!');
|
||||
});
|
||||
}
|
||||
});
|
||||
47
app/templates/admin.html
Normal file
47
app/templates/admin.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Dashboard</title>
|
||||
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('admin') }}">Admin</a></li>
|
||||
<li><a href="{{ url_for('logout') }}">Logout</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<h1>Admin Dashboard</h1>
|
||||
<section>
|
||||
<h2>Manage Users</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.role }}</td>
|
||||
<td>
|
||||
<button onclick="editUser('{{ user.username }}')">Edit</button>
|
||||
<button onclick="deleteUser('{{ user.username }}')">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
7
app/templates/base.html
Normal file
7
app/templates/base.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Flask App{% endblock %}</title>
|
||||
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet">
|
||||
13
app/templates/home.html
Normal file
13
app/templates/home.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Home{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Welcome to the Flask App</h1>
|
||||
<p>This is the homepage of the Flask application.</p>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('admin') }}">Admin</a></li>
|
||||
<li><a href="{{ url_for('login') }}">Login</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
32
app/templates/login.html
Normal file
32
app/templates/login.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login</title>
|
||||
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('home') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('admin') }}">Admin</a></li>
|
||||
<li><a href="{{ url_for('logout') }}">Logout</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<h1>Login</h1>
|
||||
<form method="POST" action="{{ url_for('login') }}">
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
<label for="otp">OTP:</label>
|
||||
<input type="text" id="otp" name="otp" required>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user