From 45f855636f69e9f937cbaf24caedf64938940c73 Mon Sep 17 00:00:00 2001 From: "Ferdinard Arthur (arthurf3)" Date: Fri, 29 Nov 2024 16:55:42 +0000 Subject: [PATCH] Add files via upload --- __init__.py | 22 ++ helpers.py | 53 +++ models.py | 75 ++++ requirments.txt | 18 + routes.py | 356 ++++++++++++++++++ run.py | 8 + templates/403.html | 30 ++ templates/admin.html | 112 ++++++ templates/caregiver.html | 113 ++++++ templates/edit_app.html | 55 +++ templates/edit_patient_details.html | 49 +++ templates/index.html | 181 +++++++++ templates/index2.html | 165 ++++++++ templates/patient.html | 122 ++++++ templates/pending_caregiver_verification.html | 39 ++ templates/pending_verification.html | 39 ++ templates/verify_users.html | 45 +++ 17 files changed, 1482 insertions(+) create mode 100644 __init__.py create mode 100644 helpers.py create mode 100644 models.py create mode 100644 requirments.txt create mode 100644 routes.py create mode 100644 run.py create mode 100644 templates/403.html create mode 100644 templates/admin.html create mode 100644 templates/caregiver.html create mode 100644 templates/edit_app.html create mode 100644 templates/edit_patient_details.html create mode 100644 templates/index.html create mode 100644 templates/index2.html create mode 100644 templates/patient.html create mode 100644 templates/pending_caregiver_verification.html create mode 100644 templates/pending_verification.html create mode 100644 templates/verify_users.html diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..92fb864 --- /dev/null +++ b/__init__.py @@ -0,0 +1,22 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_socketio import SocketIO, emit +import os + + + +app = Flask(__name__) + +app.secret_key = os.getenv('SECRET_KEY') + +app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATEABASE_URL') + + +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + + +db = SQLAlchemy(app) + +from . import routes +app.register_blueprint(routes.bp) +socketio = SocketIO(app) diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..ea0d493 --- /dev/null +++ b/helpers.py @@ -0,0 +1,53 @@ +from flask import redirect, url_for, session, jsonify, request +from functools import wraps + +ROLES = { + 1 : 'admin', + 2 : 'caregiver', + 3 : 'patient' +} + +ROLES_REV = { + 'admin' : 1, + 'caregiver' : 2, + 'patient' : 3 +} +ROLES_URL = { + 'admin' : '/', + 'caregiver' : '/caregiver_dashboard', + 'patient' : '/patient_dashboard' +} + + + +def role_required(role): + """Decorator to restrict access based on user role.""" + def decorator(func): + @wraps(func) + def wrapped_view(*args, **kwargs): + if 'id' not in session: + return redirect('/') + user_role = session.get('role') + if user_role != role: + + if request.is_json: + return jsonify({"error": "Access denied"}), 403 + + return redirect('/unauthorized_access') + return func(*args, **kwargs) + return wrapped_view + return decorator + +def roles_required(*roles): + """Decorator to allow multiple roles access to a route.""" + def decorator(func): + @wraps(func) + def wrapped_view(*args, **kwargs): + user_role = session.get('role') + if user_role not in roles: + if request.is_json: + return jsonify({"error": "Access denied"}), 403 + return redirect(url_for('unauthorized_access')) + return func(*args, **kwargs) + return wrapped_view + return decorator diff --git a/models.py b/models.py new file mode 100644 index 0000000..5eb17dc --- /dev/null +++ b/models.py @@ -0,0 +1,75 @@ +from . import db +from datetime import datetime + + +class User(db.Model): + __tablename__ = 'users' + + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(80), unique=True, nullable=False) + email = db.Column(db.String(120), unique=True, nullable=False) + password_hash = db.Column(db.String(128), nullable=False) + role = db.Column(db.String(50), nullable=False, default="patient") + created_at = db.Column(db.DateTime, default=datetime.now) + verified = db.Column(db.Boolean, default = False) + + def __repr__(self): + return f"" + + +class Patient(db.Model): + __tablename__ = 'patients' + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(120), nullable=False) + address = db.Column(db.String(255), nullable=True) + medical_records = db.Column(db.Text, nullable=True) + user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) + caregiver_id = db.Column(db.Integer, db.ForeignKey('caregivers.id'), nullable=True) + + def __repr__(self): + return f"" + + +class Caregiver(db.Model): + __tablename__ = 'caregivers' + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(120), nullable=False) + availability = db.Column(db.Boolean, default=True) + user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) + + patients = db.relationship('Patient', backref='caregiver', lazy=True) + def __repr__(self): + return f"" + +class Appointment(db.Model): + __tablename__ = 'appointments' + + id = db.Column(db.Integer, primary_key=True) + patient_id = db.Column(db.Integer, db.ForeignKey('patients.id'), nullable=False) + caregiver_id = db.Column(db.Integer, db.ForeignKey('caregivers.id'), nullable=False) + appointment_date = db.Column(db.DateTime, nullable=False) + updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) + + patient = db.relationship('Patient', backref='appointments', lazy=True) + caregiver = db.relationship('Caregiver', backref='appointments', lazy=True) + + def __repr__(self): + return f"" + + +class Notification(db.Model): + __tablename__ = 'notifications' + + id = db.Column(db.Integer, primary_key=True) + recipient_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) + message = db.Column(db.String(255), nullable=False) + is_read = db.Column(db.Boolean, default=False) + created_at = db.Column(db.DateTime, default=datetime.now) + + recipient = db.relationship('User', backref='notifications', lazy=True) + + def __repr__(self): + return f"" + diff --git a/requirments.txt b/requirments.txt new file mode 100644 index 0000000..6b5bddf --- /dev/null +++ b/requirments.txt @@ -0,0 +1,18 @@ +bidict==0.23.1 +blinker==1.9.0 +click==8.1.7 +Flask==3.1.0 +Flask-SocketIO==5.4.1 +Flask-SQLAlchemy==3.1.1 +h11==0.14.0 +itsdangerous==2.2.0 +Jinja2==3.1.4 +MarkupSafe==3.0.2 +python-dotenv==1.0.1 +python-engineio==4.10.1 +python-socketio==5.11.4 +simple-websocket==1.1.0 +SQLAlchemy==2.0.36 +typing_extensions==4.12.2 +Werkzeug==3.1.3 +wsproto==1.2.0 diff --git a/routes.py b/routes.py new file mode 100644 index 0000000..1d64014 --- /dev/null +++ b/routes.py @@ -0,0 +1,356 @@ +from flask import render_template, Blueprint, request, session, redirect, jsonify +from werkzeug.security import generate_password_hash, check_password_hash +from datetime import datetime +from .models import * +from . import db +from .helpers import * +import bleach +import re + +bp = Blueprint('main', __name__) + +# Helper Functions for Validation +def is_valid_email(email): + return re.match(r"[^@]+@[^@]+\.[^@]+", email) + +def is_valid_password(password): + return len(password) >= 8 and any(char.isdigit() for char in password) and any(char.isalpha() for char in password) + +def is_valid_date(date_str): + try: + datetime.strptime(date_str, "%Y-%m-%d %H:%M") + return True + except ValueError: + return False + +def sanitize_input(input_str): + """Sanitize input using bleach to prevent XSS attacks.""" + if input_str: + # Allow only specific tags (e.g., , , , , ) + allowed_tags = ['b', 'i', 'u', 'em', 'strong'] + return bleach.clean(input_str, tags=allowed_tags, strip=True) # Strip any unwanted tags and attributes + return input_str + +@bp.route('/') +def index(): + if 'id' not in session: + return render_template('index2.html', title='Home') + else: + u = User.query.filter_by(id=session['id']).first() + if u.role == 'admin': + return redirect('/admin_dash') + elif u.role == 'caregiver': + return redirect('/caregiver_dashboard') + elif u.role == 'patient': + return redirect('/patient_dashboard') + else: + session.pop('id', None) + session.pop('role', None) + return redirect('/') + +@bp.route('/remove_caregiver/') +@role_required(1) +def remove_caregiver(patient_id): + if not patient_id.isdigit(): + return jsonify({"message": "Invalid patient ID"}), 400 + p = Patient.query.filter_by(id=int(patient_id)).first() + if not p: + return jsonify({"message": "Patient not found"}), 404 + p.caregiver_id = None + db.session.commit() + return redirect('/admin_dash') + +@bp.route('/admin_dash') +@role_required(1) +def admin_dash(): + if 'id' not in session: + return redirect('/') + u = User.query.filter_by(id=session['id']).first() + + patients = Patient.query.filter_by(caregiver_id=None).all() + verified_patients = [p for p in patients if User.query.filter_by(id=p.user_id).first().verified] + caregivers = Caregiver.query.all() + verified_caregivers = [c for c in caregivers if User.query.filter_by(id=c.user_id).first().verified] + + return render_template('admin.html', patients=verified_patients, caregivers=verified_caregivers) + +@bp.post('/assign_caregiver') +@role_required(1) +def assign_caregiver(): + if 'id' not in session: + return redirect('/') + patient_id = request.form['patientid'] + caregiver_id = request.form['caregiverid'] + + if not patient_id.isdigit() or not caregiver_id.isdigit(): + return jsonify({"message": "Invalid patient or caregiver ID"}), 400 + + p = Patient.query.filter_by(id=int(patient_id)).first() + if not p: + return jsonify({"message": "Patient not found"}), 404 + c = Caregiver.query.filter_by(id=int(caregiver_id)).first() + if not c: + return jsonify({"message": "Caregiver not found"}), 404 + + p.caregiver_id = int(caregiver_id) + db.session.commit() + return redirect('/admin_dash') + +@bp.post('/login') +def login(): + body = request.json + username = body.get('username') + password = body.get('password') + + if not username or not password: + return jsonify({"message": "Username and password are required"}), 400 + + u = User.query.filter_by(username=username).first() + if not u: + return jsonify({"message": "Invalid credentials"}), 401 + + if check_password_hash(u.password_hash, password): + session['id'] = u.id + session['role'] = ROLES_REV[u.role] + redirect_url = ROLES_URL[u.role] + return jsonify({'success': True, 'redirectURL': redirect_url}) + else: + return jsonify({"message": "Error signing in"}), 401 + +@bp.post('/signup') +def sup(): + body = request.json + email = body.get('email') + fullname = body.get('fullname') + password = body.get('password') + role = body.get('role') + username = body.get('username') + + if not all([email, fullname, password, role, username]): + return jsonify({"message": "Missing required fields"}), 400 + + if not is_valid_email(email): + return jsonify({"message": "Invalid email format"}), 400 + + if User.query.filter_by(email=email).first(): + return jsonify({"message": "Email is already taken"}), 409 + + if not is_valid_password(password): + return jsonify({"message": "Password must be at least 8 characters long, and contain both letters and numbers"}), 400 + + if role not in ['caregiver', 'patient']: + return jsonify({"message": "Invalid role"}), 400 + + if User.query.filter_by(username=username).first(): + return jsonify({"message": "Username is already taken"}), 409 + + hashed_password = generate_password_hash(password) + new_user = User(email=sanitize_input(email), username=sanitize_input(username), password_hash=hashed_password, role=role) + db.session.add(new_user) + db.session.commit() + + if role == 'caregiver': + db.session.add(Caregiver(name=sanitize_input(fullname), user_id=new_user.id)) + elif role == 'patient': + db.session.add(Patient(name=sanitize_input(fullname), user_id=new_user.id)) + db.session.commit() + + session['id'] = new_user.id + session['role'] = role + return jsonify({'success': True, 'role': role}) + +def tup(id, role): + if role == 'caregiver': + return Caregiver.query.filter_by(user_id=id).first() + elif role == 'patient': + return Patient.query.filter_by(user_id=id).first() + +@bp.route('/verify_users') +@role_required(1) +def verify_users(): + users = User.query.filter_by(verified=False).all() + user_list = [(u, tup(u.id, u.role)) for u in users] + return render_template('verify_users.html', user_list=user_list) + +@bp.route('/verify_user/') +@role_required(1) +def verify_u(id): + if not id.isdigit(): + return jsonify({"message": "Invalid user ID"}), 400 + u = User.query.filter_by(id=id).first() + if not u: + return jsonify({"message": "User not found"}), 404 + u.verified = True + db.session.commit() + return redirect('/verify_users') + +@bp.route('/delete_user/') +@role_required(1) +def delete_u(id): + if not id.isdigit(): + return jsonify({"message": "Invalid user ID"}), 400 + u = User.query.filter_by(id=id).first() + if not u: + return jsonify({"message": "User not found"}), 404 + + if u.role == 'caregiver': + role = Caregiver.query.filter_by(user_id=u.id).first() + else: + role = Patient.query.filter_by(user_id=u.id).first() + + db.session.delete(role) + db.session.delete(u) + db.session.commit() + return redirect('/verify_users') + +@bp.get('/notifications') +@role_required(3) +def get_unread_notis(): + notis = Notification.query.filter_by(recipient_id=session['id'], is_read=False).all() + messages = [ + {'message': sanitize_input(n.message), 'created_at': n.created_at.strftime("%A, %B %d, %Y at %I:%M %p")} + for n in notis + ] + for n in notis: + n.is_read = True + db.session.commit() + return jsonify(messages) + +@bp.route('/clear_sess',methods=['POST']) +def clear_sess(): + session.pop('id', None) + session.pop('role', None) + return redirect('/') + +@bp.route('/edit_appointment/', methods=['GET', 'POST']) +@role_required(2) +def edit_appointment(id): + if not id.isdigit(): + return jsonify({"message": "Invalid appointment ID"}), 400 + appointment = Appointment.query.filter_by(id=int(id)).first() + if not appointment: + return jsonify({"message": "Appointment not found"}), 404 + + if appointment.caregiver.user_id != session['id']: + return redirect('/unauthorized_access') + + if request.method == 'GET': + if 'id' not in session: + return redirect('/') + user = User.query.filter_by(id=session['id']).first() + appointments = Appointment.query.filter_by(patient_id=appointment.patient_id).all() + return render_template('edit_appointment.html', appointments=appointments, appointment=appointment) + + if request.method == 'POST': + new_date = request.form['date'] + new_time = request.form['time'] + if not is_valid_date(new_date + " " + new_time): + return jsonify({"message": "Invalid input"}), 400 + combined_datetime = datetime.strptime(f"{new_date} {new_time}", "%Y-%m-%d %H:%M") + prev_date = appointment.appointment_date + appointment.appointment_date = combined_datetime + noti = Notification( + recipient_id=appointment.patient.id, + message=f"Your {prev_date.strftime('%A, %B %d, %Y at %I:%M %p')} has been rescheduled for {combined_datetime.strftime('%A, %B %d, %Y at %I:%M %p')}" + ) + db.session.add(noti) + db.session.commit() + return redirect('/') + +# Routes for patient and caregiver dashboards with appropriate validations +# patient_dashboard route +@bp.route('/patient_dashboard') +@role_required(3) +def patient_dashboard(): + if 'id' in session: + u = User.query.filter_by(id=session['id']).first() + p = Patient.query.filter_by(user_id=u.id).first() + + # Check if the user's account is verified + if not u.verified: + return redirect(url_for('pending_verification')) + + caregiver_name = "No caregiver assigned yet" + if p.caregiver_id: + caregiver = Caregiver.query.filter_by(id=p.caregiver_id).first() + caregiver_name = caregiver.name + + user_dets = { + 'name': sanitize_input(p.name), + 'address': sanitize_input(p.address or 'Address not entered'), + 'caregiver': caregiver_name + } + + appointments = Appointment.query.filter_by(patient_id=p.id).all() + return render_template('patient.html', user=user_dets, appointments=appointments) + + + +@bp.post('/schedule_appointment') +@role_required(2) +def schedule_appointment(): + c = Caregiver.query.filter_by(user_id=session['id']).first() + patient_id = request.form['patientid'] + date = request.form['date'] + time = request.form['time'] + if not patient_id.isdigit() or not is_valid_date(date + " " + time): + return jsonify({"message": "Invalid input"}), 400 + combined_datetime = datetime.strptime(f"{date} {time}", "%Y-%m-%d %H:%M") + appointment = Appointment(patient_id=int(patient_id), caregiver_id=c.id, appointment_date=combined_datetime) + patient = Patient.query.filter_by(id=int(patient_id)).first() + notification = Notification( + recipient_id=patient.user_id, + message=f"Appointment booked on {combined_datetime.strftime('%A, %B %d, %Y at %I:%M %p')}" + ) + db.session.add(appointment) + db.session.add(notification) + db.session.commit() + return redirect('/') + +@bp.route('/unauthorized_access') +def unauthorized_access(): + return render_template('403.html') + +@bp.route('/caregiver_dashboard') +@role_required(2) +def caregiver(): + u = User.query.filter_by(id=session['id']).first() + c = Caregiver.query.filter_by(user_id=u.id).first() + appointments = Appointment.query.filter_by(caregiver_id=c.id).all() + if not u.verified: + return redirect(url_for('main.pending_caregiver_verification')) + return render_template('caregiver.html', c=c, apps=appointments) + +@bp.route('/edit_patient_details', methods=['GET', 'POST']) +@role_required(3) # Ensure only patients can access this +def edit_patient_details(): + if 'id' not in session: + return redirect('/') + + u = User.query.filter_by(id=session['id']).first() + if not u: + return redirect('/') + + p = Patient.query.filter_by(user_id=u.id).first() + if not p: + return jsonify({"message": "Patient not found"}), 404 + + if request.method == 'GET': + # Render the form with the current patient details + return render_template('edit_patient_details.html', patient=p) + + if request.method == 'POST': + # Get the new details from the form + new_name = request.form['name'] + new_address = request.form['address'] + + # Update patient details in the database + p.name = sanitize_input(new_name) # Sanitize the input + p.address = sanitize_input(new_address) # Sanitize the input + db.session.commit() + + return redirect('/patient_dashboard') # Redirect back to the patient dashboard + +@bp.route('/pending_caregiver_verification') +def pending_caregiver_verification(): + return render_template('pending_caregiver_verification.html') diff --git a/run.py b/run.py new file mode 100644 index 0000000..1518931 --- /dev/null +++ b/run.py @@ -0,0 +1,8 @@ +from app import app +from dotenv import load_dotenv + + +load_dotenv() + +if __name__ == '__main__': + app.run(debug=True, port=9999) diff --git a/templates/403.html b/templates/403.html new file mode 100644 index 0000000..6ab4824 --- /dev/null +++ b/templates/403.html @@ -0,0 +1,30 @@ + + + + + + Unauthorized Access + + + + +
+

403 Unauthorized

+

+ You are not authorized to access this page. Please make sure you have the correct permissions. +

+ +
+ + +
+ +
+ If you believe this is a mistake, contact support. +
+
+ + + diff --git a/templates/admin.html b/templates/admin.html new file mode 100644 index 0000000..0bcdeb5 --- /dev/null +++ b/templates/admin.html @@ -0,0 +1,112 @@ + + + + + + Admin Dashboard + + + + + +
+
+

Admin Dashboard

+ +
+ +
+
+
+ + +
+ + +
+

User Verification

+

Manage pending user verifications.

+ + Go to Verification Page + +
+ + +
+

Assign Caregivers to Patients

+
+
+ + +
+
+ + +
+ +
+
+ + +
+

Ongoing Assignments

+ + + + + + + + + + {% for c in caregivers %} + {% for p in c.patients %} + + + + + + {% endfor %} + {% endfor %} + +
Patient NameCaregiver NameActions
{{ p.name }}{{ c.name }} + Remove +
+
+ + +
+

Caregiver Availability

+ + + + + + + + + {% for c in caregivers %} + + + + + {% endfor %} + +
Caregiver NameStatus
{{ c.name }}Available
+
+
+ + + diff --git a/templates/caregiver.html b/templates/caregiver.html new file mode 100644 index 0000000..52328f4 --- /dev/null +++ b/templates/caregiver.html @@ -0,0 +1,113 @@ + + + + + + Caregiver Dashboard + + + +
+

Caregiver Dashboard

+ +
+ +
+
+ +
+ +
+

Schedule an Appointment

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ + +
+

Current Appointments

+ + + + + + + + + + + {% for a in apps %} + + + + + + + {% endfor %} + +
Patient NameDateTimeActions
{{ a.patient.name }}{{ a.appointment_date.strftime("%A, %B %d, %Y") }}{{ a.appointment_date.strftime("%I:%M %p") }}Edit
+
+
+ + + + + + + + diff --git a/templates/edit_app.html b/templates/edit_app.html new file mode 100644 index 0000000..abb818b --- /dev/null +++ b/templates/edit_app.html @@ -0,0 +1,55 @@ + + + + + + Update Appointment + + + + +
+

Update Appointment

+ + +
+ +
+ +

{{appointment.appointment_date.strftime("%A, %B %d, %Y at %I:%M %p")}}

+
+ + +
+ + +
+ + +
+ + +
+ + + +
+
+ + + + diff --git a/templates/edit_patient_details.html b/templates/edit_patient_details.html new file mode 100644 index 0000000..7601de4 --- /dev/null +++ b/templates/edit_patient_details.html @@ -0,0 +1,49 @@ + + + + + + Edit Your Details + + + + + +
+

Edit Your Details

+

Update your personal information

+
+ + +
+
+
+ +
+ + +
+ + +
+ + +
+ + +
+ +
+
+
+
+ + +
+ Cancel +
+ + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..01d4419 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,181 @@ + + + + + + Hospital System + + + + +
+

Login

+ + +
+ + +
+ +
+ + + +
+ + +
+ +
+ + +
+ + +
+ +
+

+ Don't have an account? + Sign up here +

+
+
+ + + + + diff --git a/templates/index2.html b/templates/index2.html new file mode 100644 index 0000000..1aeb267 --- /dev/null +++ b/templates/index2.html @@ -0,0 +1,165 @@ + + + + + + Hospital System + + + +
+

Login

+ +
+ + +
+ +
+ + + + +
+ + +
+ + + +
+ + +
+ + + +
+ +
+

+ Don't have an account? + Sign up here +

+
+
+ + + + diff --git a/templates/patient.html b/templates/patient.html new file mode 100644 index 0000000..dfa983b --- /dev/null +++ b/templates/patient.html @@ -0,0 +1,122 @@ + + + + + + Patient Dashboard + + + + + +
+

Patient Dashboard

+

View your personal details, appointments, and notifications

+
+ + +
+

Your Information

+
+
+

Name:

+

{{user['name']}}

+
+
+

Address:

+

{{user['address']}}

+
+
+

Medical Records:

+

No significant medical history

+
+
+

Caregiver Name:

+

{{user['caregiver']}}

+
+
+
+ + + + + +
+

Notifications

+
+ +
+
+ + +
+

Your Appointments

+
+ {% if appointments %} + {% for a in appointments %} +

You have an appointment with {{ a.caregiver.name }} on {{ a.appointment_date.strftime("%A, %B %d, %Y at %I:%M %p") }}

+ {% endfor %} + {% else %} +

No appointments available

+ {% endif %} +
+
+ + +
+
+ +
+
+ + + + diff --git a/templates/pending_caregiver_verification.html b/templates/pending_caregiver_verification.html new file mode 100644 index 0000000..f2ddc63 --- /dev/null +++ b/templates/pending_caregiver_verification.html @@ -0,0 +1,39 @@ + + + + + + Account Verification Pending + + + + + +
+ + +
+ + + +
+ + +

Your Account is Pending Verification

+

Thank you for registering with us! Your account is currently under review by our admin team. We will notify you once it's verified.

+ + +
+
+
Verification in Progress
+
+
+ + +
+ +
+
+ + + diff --git a/templates/pending_verification.html b/templates/pending_verification.html new file mode 100644 index 0000000..5f92538 --- /dev/null +++ b/templates/pending_verification.html @@ -0,0 +1,39 @@ + + + + + + + + Account Verification Pending + + + + + +
+ + +
+ + + +
+ + +

Your Account is Pending Verification

+

Thank you for registering with us! Your account is currently under review by our admin team. We will notify you once it's verified.

+ + +
+
+
Verification in Progress
+
+
+ + + Go to Dashboard +
+ + + diff --git a/templates/verify_users.html b/templates/verify_users.html new file mode 100644 index 0000000..1994f80 --- /dev/null +++ b/templates/verify_users.html @@ -0,0 +1,45 @@ + + + + + + Admin User Management + + + + + +
+

User Management

+ + + +
+ + {%for u in user_list%} +
+
+

{{u[1].name}}

+

Email: {{u[0].email}}

+

Role: {{u[0].role}}

+
+ +
+ {%endfor%} +
+
+ + + +