user handling

This commit is contained in:
2025-12-15 23:07:19 +01:00
parent f6f2d20eb8
commit b0f19eb72e
15 changed files with 573 additions and 127 deletions

105
web.py
View File

@@ -1,7 +1,6 @@
from flask import Flask, abort, request, flash, redirect, get_flashed_messages
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from jinja2 import FileSystemLoader, Template
import plotly.express as px
from jinja2 import FileSystemLoader
from plotly.subplots import make_subplots
import plotly.graph_objects as go
@@ -35,6 +34,18 @@ env = app.create_jinja_environment()
DISPLAYEDTYPES = 2
TDLATE = datetime.timedelta(hours=8)
def handle_user_login(username: str, password: str):
user_data = DatabaseConnect().user_by_username(username)
if user_data:
user_id, _, salt, key, _ = user_data
if user_handling.verify_password(salt, key, password.encode()):
user = components.User(user_id, username)
login_user(user)
DatabaseConnect().emit_log(3, f"User {username} logged in successfully.")
return True
DatabaseConnect().emit_log(2, f"Failed login attempt for user {username}.")
return False
@app.route("/login", methods=["GET", "POST"])
def login():
@@ -42,17 +53,9 @@ def login():
username = request.form["username"]
password = request.form["password"]
user_data = DatabaseConnect().user_by_username(username)
if user_data:
user_id, _, salt, key = user_data
if user_handling.verify_password(salt, key, password.encode()):
user = components.User(user_id, username)
login_user(user)
DatabaseConnect().emit_log(3, f"User {username} logged in successfully.")
return redirect("/")
DatabaseConnect().emit_log(2, f"Failed login attempt for user {username}.")
flash("Invalid username or password.")
if handle_user_login(username, password):
return redirect("/")
flash("Invalid username or password.")
return templating.LoginPage(env, current_user, roominfo=gather_room_info()).render()
@app.route("/logout")
@@ -63,15 +66,13 @@ def logout():
@app.route("/")
def index():
rooms_info = gather_room_info()
out_html = templating.LandingPage(env, current_user,rooms_info)
return out_html.render()
def gather_room_info():
rooms_info = []
for room in DatabaseConnect().view_valid_rooms(current_user.id):
for room in DatabaseConnect().view_all_rooms() if DatabaseConnect().is_admin(current_user.id) else DatabaseConnect().view_valid_rooms(current_user.id):
sensor_info = []
sensors_avail = DatabaseConnect().get_sensors_in_room_id(room[2])
for i in range(DISPLAYEDTYPES):
@@ -96,14 +97,21 @@ def gather_room_info():
@app.route('/room/<room_name>')
def room_page(room_name=None):
if not DatabaseConnect().user_has_room_perms(current_user.id,room_name):
if not (DatabaseConnect().user_has_room_perms(current_user.id,room_name) or DatabaseConnect().is_admin(current_user.id)):
abort(403)
roominfos = gather_room_info()
current_room = next((x for x in roominfos if x.shortcode == room_name), None)
#TODO: if statement to failsafe room with no sensors
sensor_list = DatabaseConnect().get_sensors_in_room_shortname(room_name)
if not sensor_list:
return templating.EmptyRoom(
env,
current_user,
roominfos,
current_room
).render()
fig = make_subplots(rows=1, cols=len(sensor_list))
lastest_readings = []
for idx, (sensorID, sensor_type) in enumerate(sensor_list):
@@ -115,10 +123,22 @@ def room_page(room_name=None):
lst[0][0],
f"{lst[0][1]:.2f}{DatabaseConnect().get_unit_for_type(sensor_type) or ''}"
))
x = []
y = []
last = None
for i in lst:
if last is not None and (last - i[0]) > TDLATE:
x.append(None)
y.append(last + datetime.timedelta(seconds=1))
x.append(i[0])
y.append(i[1])
last = i[0]
fig.add_trace(
go.Scatter(
x = [x[0] for x in lst],
y = [x[1] for x in lst],
connectgaps=False,
x = x,
y = y,
name=DatabaseConnect().get_sensor_type(sensorID)),
row = 1,
col = idx + 1
@@ -135,6 +155,51 @@ def room_page(room_name=None):
fig.to_html(full_html=False, include_plotlyjs='cdn')
).render()
@app.route("/users", methods=["GET","POST"])
def user_management():
if request.method == "POST":
# no options allowed for logged out users
if current_user.id == 1:
abort(403)
if "old_password" in request.form:
# password change request
old_password = request.form["old_password"]
new_password = request.form["new_password"]
if handle_user_login(current_user.username, old_password):
salt, key = user_handling.new_password(new_password.encode())
DatabaseConnect().change_user_password(current_user.id, salt, key)
flash("Password changed successfully.")
return redirect("/users")
else:
flash("Old password incorrect.")
return redirect("/users")
else:
if not DatabaseConnect().is_admin(current_user.id):
abort(403)
elif "new_username" in request.form:
new_username = request.form["new_username"]
new_password = request.form["new_password"]
is_admin = request.form.get("is_admin") == "on"
salt, key = user_handling.new_password(new_password.encode())
DatabaseConnect().create_user(new_username, salt, key, is_admin)
flash(f"Created user {new_username}.")
return redirect("/users")
elif "delete" in request.form:
value = int(request.form["delete"])
if value == current_user.id:
flash("Cannot delete currently logged in user.")
return redirect("/users")
DatabaseConnect().delete_user(value)
flash(f"Deleted user ID {value}.")
return redirect("/users")
else:
abort(400)
else:
users = DatabaseConnect().display_users()
admin = DatabaseConnect().is_admin(current_user.id)
return templating.UserManagementPage(env, current_user, gather_room_info(), users, admin).render()
if __name__ == "__main__":
app.run(debug=True)