1
This commit is contained in:
206
app.py
206
app.py
@@ -1,5 +1,5 @@
|
||||
|
||||
from flask import Flask, request, jsonify, render_template_string, redirect
|
||||
from flask import Flask, request, jsonify, render_template_string, redirect, render_template
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
@@ -21,8 +21,8 @@ class Student(db.Model):
|
||||
current_room = db.Column(db.String(64))
|
||||
previous_room = db.Column(db.String(64))
|
||||
expected_return = db.Column(db.String(64))
|
||||
|
||||
state = db.Column(db.String(32), default="IN_ROOM")
|
||||
expected_room = db.Column(db.String(64))
|
||||
state = db.Column(db.String(32), default="OUT")
|
||||
|
||||
last_scan = db.Column(db.DateTime)
|
||||
last_reader = db.Column(db.String(64))
|
||||
@@ -36,11 +36,13 @@ class Event(db.Model):
|
||||
timestamp = db.Column(db.DateTime)
|
||||
|
||||
|
||||
class Bathroom(db.Model):
|
||||
class Room(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
room = db.Column(db.String(64), unique=True)
|
||||
count = db.Column(db.Integer, default=0)
|
||||
max = db.Column(db.Integer, default=2)
|
||||
bathroom = db.Column(db.Boolean, default=True)
|
||||
bathroom_id = db.Column(db.String)
|
||||
|
||||
|
||||
class Anomaly(db.Model):
|
||||
@@ -54,10 +56,10 @@ class Anomaly(db.Model):
|
||||
# UTIL
|
||||
# --------------------------------------------------
|
||||
|
||||
COOLDOWN = 3
|
||||
COOLDOWN = 5
|
||||
|
||||
def now():
|
||||
return datetime.now(timezone.utc)
|
||||
return datetime.now()
|
||||
|
||||
|
||||
def recent_scan(student):
|
||||
@@ -129,61 +131,187 @@ def process_scan(student, room):
|
||||
@app.route("/scan", methods=["POST"])
|
||||
def scan():
|
||||
data = request.json
|
||||
|
||||
action = data["action"]
|
||||
print(action)
|
||||
student = Student.query.filter_by(uid=data["uid"]).first()
|
||||
if not student:
|
||||
student = Student(uid=data["uid"], name="Unknown")
|
||||
db.session.add(student)
|
||||
db.session.commit()
|
||||
|
||||
process_scan(student, data["room"])
|
||||
else:
|
||||
student = Student.query.filter_by(uid=data["uid"]).first()
|
||||
location = data["location_id"]
|
||||
room = Room.query.filter_by(room=location).first()
|
||||
student.last_reader = location
|
||||
student.last_scan = now()
|
||||
if action == "":
|
||||
if student.state == "out" and "door" in location: # Entering school
|
||||
student.state = "hallway"
|
||||
if student.state == "hallway" and "door" in location: # Leaving school
|
||||
student.state = "out"
|
||||
if student.state == "hallway" and "classroom" in location: # Entering a classroom
|
||||
student.current_room = location
|
||||
student.state = "in class"
|
||||
room.count = room.count + 1
|
||||
if student.state == "in class" and "classroom" in location: # leaving a classroom should also have time check when schedules are implemtned if time is wrong do an anomaly
|
||||
student.state = "hallway"
|
||||
room.count = room.count - 1
|
||||
# anomaly
|
||||
|
||||
|
||||
|
||||
elif action == "bathroom" :
|
||||
room.bathroom = False
|
||||
student.state = "hallway"
|
||||
student.expected_room = room.bathroom_id
|
||||
student.expected_return = location
|
||||
|
||||
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"status": "ok"})
|
||||
|
||||
@app.route("/lights/bathroom/<id>", methods=["GET"])
|
||||
def lightsBathroom(id):
|
||||
|
||||
room = Room.query.filter_by(room=id).first()
|
||||
bathroom = Room.query.filter_by(room=room.bathroom_id).first()
|
||||
if not room:
|
||||
room = Room(room=id)
|
||||
db.session.add(room)
|
||||
db.session.commit()
|
||||
if (room.bathroom and bathroom.count < bathroom.max):
|
||||
code = 202
|
||||
else:
|
||||
code = 200
|
||||
|
||||
|
||||
return jsonify({"status": "ok"}), code
|
||||
# --------------------------------------------------
|
||||
# ADMIN DASHBOARD
|
||||
# --------------------------------------------------
|
||||
|
||||
ADMIN_HTML = """
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://unpkg.com/htmx.org"></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-gray-900 text-white p-6">
|
||||
|
||||
<h1 class="text-2xl font-bold">Admin Dashboard</h1>
|
||||
|
||||
<div hx-get="/admin/students" hx-trigger="load, every 3s" hx-swap="innerHTML"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
@app.route("/admin")
|
||||
def admin():
|
||||
return ADMIN_HTML
|
||||
return render_template("admin/index.html")
|
||||
|
||||
|
||||
@app.route("/admin/students")
|
||||
def admin_students():
|
||||
students = Student.query.all()
|
||||
|
||||
html = ""
|
||||
for s in students:
|
||||
html += f"""
|
||||
<div class='bg-gray-800 p-3 m-2 rounded'>
|
||||
<b>{s.name}</b> ({s.uid})<br>
|
||||
Room: {s.current_room}<br>
|
||||
State: {s.state}<br>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
||||
return render_template(
|
||||
"admin/students.html",
|
||||
students=students
|
||||
)
|
||||
|
||||
|
||||
@app.route("/admin/unknown")
|
||||
def admin_unknown():
|
||||
|
||||
students = Student.query.all()
|
||||
|
||||
return render_template(
|
||||
"admin/unknown_cards.html",
|
||||
students=students
|
||||
)
|
||||
|
||||
|
||||
@app.route("/admin/rooms")
|
||||
def admin_rooms():
|
||||
|
||||
rooms = Room.query.all()
|
||||
|
||||
return render_template(
|
||||
"admin/rooms.html",
|
||||
rooms=rooms
|
||||
)
|
||||
|
||||
|
||||
@app.route("/admin/anomalies")
|
||||
def admin_anomalies():
|
||||
|
||||
anomalies = Anomaly.query.order_by(
|
||||
Anomaly.timestamp.desc()
|
||||
).all()
|
||||
|
||||
return render_template(
|
||||
"admin/anomalies.html",
|
||||
anomalies=anomalies
|
||||
)
|
||||
|
||||
@app.route("/admin/student/assign", methods=["POST"])
|
||||
def assign_student():
|
||||
|
||||
uid = request.form["uid"]
|
||||
name = request.form["name"]
|
||||
|
||||
student = Student.query.filter_by(
|
||||
uid=uid
|
||||
).first()
|
||||
|
||||
student.name = name
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return admin_unknown()
|
||||
|
||||
@app.route("/admin/student/merge", methods=["POST"])
|
||||
def merge_student():
|
||||
|
||||
old_uid = request.form["old_uid"]
|
||||
new_uid = request.form["new_uid"]
|
||||
|
||||
old_student = Student.query.filter_by(
|
||||
uid=old_uid
|
||||
).first()
|
||||
|
||||
new_student = Student.query.filter_by(
|
||||
uid=new_uid
|
||||
).first()
|
||||
|
||||
if not old_student or not new_student:
|
||||
return "Missing student", 404
|
||||
|
||||
# move all events
|
||||
|
||||
events = Event.query.filter_by(
|
||||
uid=new_uid
|
||||
).all()
|
||||
|
||||
for e in events:
|
||||
e.uid = old_uid
|
||||
|
||||
db.session.delete(new_student)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return admin_unknown()
|
||||
|
||||
@app.route(
|
||||
"/admin/room/update/<int:id>",
|
||||
methods=["POST"]
|
||||
)
|
||||
def update_room(id):
|
||||
|
||||
room = Room.query.get(id)
|
||||
|
||||
room.max = int(
|
||||
request.form["max"]
|
||||
)
|
||||
|
||||
room.bathroom_id = request.form[
|
||||
"bathroom_id"
|
||||
]
|
||||
|
||||
room.tracks_bathroom = (
|
||||
"tracks_bathroom"
|
||||
in request.form
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return admin_rooms()
|
||||
# --------------------------------------------------
|
||||
# TEACHER DASHBOARD
|
||||
# --------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user