mirror of
https://github.com/StefBuwalda/ProjectIOT.git
synced 2025-12-15 10:17:54 +00:00
changed files on the frontend
This commit is contained in:
3
AT_frontend/.gitignore
vendored
3
AT_frontend/.gitignore
vendored
@@ -1,2 +1 @@
|
|||||||
.venv/
|
.venvs/
|
||||||
__pychache__/
|
|
||||||
@@ -1,152 +1,35 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
from flask import Flask, render_template, session, redirect, url_for, session
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
from wtforms import (StringField, BooleanField,
|
||||||
|
RadioField, SelectField,
|
||||||
|
TextAreaField, SubmitField)
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
from functools import wraps
|
|
||||||
import os
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config['SECRET_KEY'] = 'your-secret-key' # Change this to a random string
|
|
||||||
|
|
||||||
# Database configuration - update with your friend's database info
|
app.config['SECRET_KEY'] = 'mijngeheimesleutel'
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logs.db' # Change this to match your friend's DB
|
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
|
|
||||||
# Simple log model - adjust to match your friend's database structure
|
class InfoForm(FlaskForm):
|
||||||
class Log(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
action = db.Column(db.String(100), nullable=False)
|
|
||||||
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"Log('{self.action}', '{self.timestamp}')"
|
|
||||||
|
|
||||||
# Keep your existing user dictionary for authentication
|
naam = StringField('Wat is je naam?',validators=[DataRequired()])
|
||||||
users = {
|
vrouw = BooleanField("Ben je een vrouw?")
|
||||||
"admin": {"password": "admin123", "role": "admin"},
|
instrument = RadioField('Welk instrument wil je leren bespelen?', choices=[('ins_een','Gitaar'),('ins_twee','Drums')])
|
||||||
"user": {"password": "user123", "role": "user"}
|
plaats = SelectField(u'Welke locatie heeft de voorkeur?',
|
||||||
}
|
choices=[('as', 'Assen'), ('dr', 'Drachten'), ('gr', 'Groningen')])
|
||||||
|
feedback = TextAreaField()
|
||||||
|
submit = SubmitField('Verzend')
|
||||||
|
|
||||||
# Add a function to create a new log entry
|
@app.route('/', methods=['GET', 'POST'])
|
||||||
def add_log(action):
|
|
||||||
log = Log(action=action)
|
|
||||||
db.session.add(log)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
|
||||||
username = StringField('Username', validators=[DataRequired()])
|
|
||||||
password = PasswordField('Password', validators=[DataRequired()])
|
|
||||||
remember = BooleanField('Remember Me')
|
|
||||||
|
|
||||||
class GateControlForm(FlaskForm):
|
|
||||||
open_gate = SubmitField('Open Gate')
|
|
||||||
close_gate = SubmitField('Close Gate')
|
|
||||||
check_camera = SubmitField('Check Camera')
|
|
||||||
debug_mode = BooleanField('Debug Mode')
|
|
||||||
|
|
||||||
def login_required(f):
|
|
||||||
@wraps(f)
|
|
||||||
def decorated_function(*args, **kwargs):
|
|
||||||
if 'logged_in' not in session:
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
return f(*args, **kwargs)
|
|
||||||
return decorated_function
|
|
||||||
|
|
||||||
def admin_required(f):
|
|
||||||
@wraps(f)
|
|
||||||
def decorated_function(*args, **kwargs):
|
|
||||||
if 'role' not in session or session['role'] != 'admin':
|
|
||||||
flash('You need to be an admin to access this page.')
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
return f(*args, **kwargs)
|
|
||||||
return decorated_function
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
def index():
|
||||||
if 'logged_in' in session:
|
|
||||||
if session['role'] == 'admin':
|
|
||||||
return redirect(url_for('dashboard'))
|
|
||||||
return redirect(url_for('user_page'))
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
|
|
||||||
@app.route('/login', methods=['GET', 'POST'])
|
form = InfoForm()
|
||||||
def login():
|
|
||||||
form = LoginForm()
|
|
||||||
error = None
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
username = request.form['username']
|
|
||||||
password = request.form['password']
|
|
||||||
|
|
||||||
if username in users and users[username]['password'] == password:
|
|
||||||
session['logged_in'] = True
|
|
||||||
session['username'] = username
|
|
||||||
session['role'] = users[username]['role']
|
|
||||||
|
|
||||||
# Log the login action
|
|
||||||
add_log(f"User {username} logged in")
|
|
||||||
|
|
||||||
if users[username]['role'] == 'admin':
|
|
||||||
return redirect(url_for('dashboard'))
|
|
||||||
else:
|
|
||||||
return redirect(url_for('user_page'))
|
|
||||||
else:
|
|
||||||
# Log the failed login attempt
|
|
||||||
add_log(f"Failed login attempt for user {username}")
|
|
||||||
error = 'Invalid credentials. Please try again.'
|
|
||||||
|
|
||||||
return render_template('inlog.html', form=form, error=error)
|
|
||||||
|
|
||||||
@app.route('/dashboard', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
@admin_required
|
|
||||||
def dashboard():
|
|
||||||
form = GateControlForm()
|
|
||||||
gate_status = "Closed"
|
|
||||||
camera_status = "Inactive"
|
|
||||||
debug_mode = False
|
|
||||||
|
|
||||||
# Get the most recent logs to display
|
|
||||||
recent_logs = Log.query.order_by(Log.timestamp.desc()).limit(10).all()
|
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
if form.open_gate.data:
|
|
||||||
gate_status = "Open"
|
|
||||||
add_log("Gate opened by " + session['username'])
|
|
||||||
elif form.close_gate.data:
|
|
||||||
gate_status = "Closed"
|
|
||||||
add_log("Gate closed by " + session['username'])
|
|
||||||
elif form.check_camera.data:
|
|
||||||
camera_status = "Active"
|
|
||||||
add_log("Camera checked by " + session['username'])
|
|
||||||
|
|
||||||
debug_mode = form.debug_mode.data
|
|
||||||
if debug_mode:
|
|
||||||
add_log("Debug mode enabled by " + session['username'])
|
|
||||||
|
|
||||||
return render_template('dashboard.html', form=form, gate_status=gate_status,
|
|
||||||
camera_status=camera_status, debug_mode=debug_mode,
|
|
||||||
recent_logs=recent_logs)
|
|
||||||
|
|
||||||
@app.route('/user')
|
session['naam'] = form.username.data
|
||||||
@login_required
|
session['password'] = form.password.data
|
||||||
def user_page():
|
|
||||||
add_log(f"User {session['username']} accessed user page")
|
|
||||||
return "Regular user page - Access restricted"
|
|
||||||
|
|
||||||
@app.route('/logout')
|
return render_template('dashboard.html')
|
||||||
def logout():
|
return render_template('login.html', form=form)
|
||||||
if 'username' in session:
|
|
||||||
add_log(f"User {session['username']} logged out")
|
|
||||||
session.clear()
|
|
||||||
return redirect(url_for('login'))
|
|
||||||
|
|
||||||
# Initialize database
|
|
||||||
with app.app_context():
|
|
||||||
db.create_all()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
BIN
AT_frontend/static/images/car.png
Normal file
BIN
AT_frontend/static/images/car.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
AT_frontend/static/images/logo-light.png
Normal file
BIN
AT_frontend/static/images/logo-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -1,68 +1,18 @@
|
|||||||
{%extends 'base.html' %}
|
<!DOCTYPE html>
|
||||||
{% block content %}
|
<html lang="en">
|
||||||
<div class="row">
|
<head>
|
||||||
<div class="col-md-4">
|
<meta charset="UTF-8">
|
||||||
<div class="card mb-4">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<div class="card-body">
|
<title>Document</title>
|
||||||
<h5>Gate Control Dashboard</h5>
|
</head>
|
||||||
<form method="POST">
|
<body>
|
||||||
{{ form.hidden_tag() }}
|
<h1>Bedankt voor de moeite. <br>Dit zijn de ingevulde gegevens:</h1>
|
||||||
<div class="d-grid gap-2 mb-3">
|
<ul>
|
||||||
{{ form.open_gate(class="btn btn-dark") }}
|
<li>Naam: {{ session['naam'] }}</li>
|
||||||
</div>
|
<li>Geslacht: {{ session['geslacht'] }}</li>
|
||||||
<div class="d-grid gap-2 mb-3">
|
<li>Instrument: {{ session['instrument'] }}</li>
|
||||||
{{ form.close_gate(class="btn btn-dark") }}
|
<li>Plaats: {{ session['plaats'] }}</li>
|
||||||
</div>
|
<li>Feedback: {{ session['feedback'] }}</li>
|
||||||
<div class="d-grid gap-2 mb-3">
|
</ul>
|
||||||
{{ form.check_camera(class="btn btn-dark") }}
|
</body>
|
||||||
</div>
|
</html>
|
||||||
<div class="mb-3">
|
|
||||||
{{ form.debug_mode() }}
|
|
||||||
<label for="{{ form.debug_mode.id }}">Enable Debug Mode</label>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" class="btn btn-dark">Submit</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<h6>Gate Status: {{ gate_status }}</h6>
|
|
||||||
<h6>Camera Status: {{ camera_status }}</h6>
|
|
||||||
{% if debug_mode %}
|
|
||||||
<h7>Debug Mode is Enabled</h7>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">System Logs</h5>
|
|
||||||
<div class="log-container" style="max-height: 250px; overflow-y: auto;">
|
|
||||||
<table class="table table-sm table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Time</th>
|
|
||||||
<th scope="col">Action</th>
|
|
||||||
<th scope="col">Status</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for log in recent_logs %}
|
|
||||||
<tr>
|
|
||||||
<td><small>{{ log.timestamp.strftime('%H:%M:%S') }}</small></td>
|
|
||||||
<td><small>{{ log.action }}</small></td>
|
|
||||||
<td>
|
|
||||||
<span class="badge {% if log.status == 'success' %}bg-success{% elif log.status == 'warning' %}bg-warning{% elif log.status == 'error' %}bg-danger{% else %}bg-secondary{% endif %}">
|
|
||||||
{{ log.status }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
{% endblock %}
|
|
||||||
75
AT_frontend/templates/login.html
Normal file
75
AT_frontend/templates/login.html
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-SgOJa3DmI69IUzQ2PVdRZhwQ+dy64/BUtbMJw1MZ8t5HZApcHrRKUc4W0kG879m7" crossorigin="anonymous">
|
||||||
|
<title>Login</title>
|
||||||
|
<style>
|
||||||
|
.rounded-input {
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-background {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh;
|
||||||
|
background-color: #424D66;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
@keyframes moveLeftRight {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(1366px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
margin-top: 70px;
|
||||||
|
width: 770px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.car-image-container {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 33px;
|
||||||
|
}
|
||||||
|
.animate {
|
||||||
|
animation: moveLeftRight 15s infinite alternate;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="split-background">
|
||||||
|
<div class="container-fluid text-center">
|
||||||
|
<img src="../static/images/logo-light.png" alt="Logo" class="logo" class="img-fluid mt-5">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container d-flex justify-content-center align-items-center" style="min-height: 100vh;">
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
<form method="POST" class="p-5 border rounded-input shadow-sm bg-white bg-opacity-75">
|
||||||
|
<div class=" p-4 border rounded-input shadow-sm bg-white">
|
||||||
|
<label for="username" class="form-label text-center w-100">Username</label>
|
||||||
|
<input type="text" class="form-control rounded-input" id="username" name="username" required>
|
||||||
|
<label for="password" class="form-label text-center w-100">Password</label>
|
||||||
|
<input type="password" class="form-control rounded-input" id="password" name="password" required>
|
||||||
|
<br>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-dark rounded-input px-4 mx-auto w-50">Sign in</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="car-image-container">
|
||||||
|
<img src="../static/images/car.png" alt="Moving Image" class="animate">
|
||||||
|
</div>
|
||||||
|
<footer class="py-3 bg-dark text-white fixed-bottom"">
|
||||||
|
<div class="container text-center">
|
||||||
|
<span class="text-muted"> </span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user