Learn by Directing AI
All materials

app.py

pyapp.py
import os
import json
import logging
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, session, jsonify
from sqlalchemy import create_engine, text

app = Flask(__name__)
app.secret_key = 'reseau-sante-du-nord-secret-key-2024'

DATABASE_URL = os.environ.get('DATABASE_URL', 'postgresql://ehr_user:ehr_pass_2024@postgres:5432/ehr_db')
engine = create_engine(DATABASE_URL)

# Configure logging -- structured JSON for access logs
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(json.dumps({
    'timestamp': '%(asctime)s',
    'level': '%(levelname)s',
    'message': '%(message)s',
    'module': '%(module)s'
})))
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)


@app.route('/')
def index():
    return redirect(url_for('login'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form.get('email', '')
        password = request.form.get('password', '')
        app.logger.info(f'Login attempt for {email} from {request.remote_addr}')

        with engine.connect() as conn:
            result = conn.execute(
                text("SELECT id, name, role, clinic_id FROM staff WHERE email = :email AND password_hash = :password"),
                {'email': email, 'password': password}
            )
            user = result.fetchone()

        if user:
            session['user_id'] = user[0]
            session['user_name'] = user[1]
            session['user_role'] = user[2]
            session['clinic_id'] = user[3]
            app.logger.info(f'Login successful for {email} (role: {user[2]})')
            return redirect(url_for('patients'))
        else:
            app.logger.warning(f'Login failed for {email} from {request.remote_addr}')
            return render_template('login.html', error='Invalid email or password')

    return render_template('login.html')


@app.route('/patients')
def patients():
    if 'user_id' not in session:
        return redirect(url_for('login'))

    with engine.connect() as conn:
        result = conn.execute(text(
            "SELECT id, first_name, last_name, dob, community FROM patients ORDER BY last_name"
        ))
        patients = result.fetchall()

    return render_template('patients.html', patients=patients, user_name=session.get('user_name'))


@app.route('/patient/<int:patient_id>')
def patient_detail(patient_id):
    if 'user_id' not in session:
        return redirect(url_for('login'))

    with engine.connect() as conn:
        patient = conn.execute(
            text("SELECT * FROM patients WHERE id = :id"),
            {'id': patient_id}
        ).fetchone()

        appointments = conn.execute(
            text("SELECT * FROM appointments WHERE patient_id = :id ORDER BY date DESC"),
            {'id': patient_id}
        ).fetchall()

        prescriptions = conn.execute(
            text("SELECT * FROM prescriptions WHERE patient_id = :id ORDER BY date DESC"),
            {'id': patient_id}
        ).fetchall()

        lab_results = conn.execute(
            text("SELECT * FROM lab_results WHERE patient_id = :id ORDER BY date DESC"),
            {'id': patient_id}
        ).fetchall()

    return render_template('patient_detail.html',
                           patient=patient,
                           appointments=appointments,
                           prescriptions=prescriptions,
                           lab_results=lab_results,
                           user_name=session.get('user_name'))


@app.route('/appointments')
def appointments():
    if 'user_id' not in session:
        return redirect(url_for('login'))

    with engine.connect() as conn:
        result = conn.execute(text("""
            SELECT a.*, p.first_name, p.last_name, c.name as clinic_name
            FROM appointments a
            JOIN patients p ON a.patient_id = p.id
            JOIN clinics c ON a.clinic_id = c.id
            ORDER BY a.date DESC, a.time DESC
        """))
        appointments = result.fetchall()

    return render_template('appointments.html', appointments=appointments, user_name=session.get('user_name'))


@app.route('/admin')
def admin():
    # Default admin account -- hidden constraint
    # Frantz planned to change the credentials but got busy
    email = request.args.get('email', '')
    password = request.args.get('password', '')

    if email == 'admin@reseausantedunord.ht' and password == 'admin123':
        app.logger.warning(f'Admin access from {request.remote_addr}')
        with engine.connect() as conn:
            staff = conn.execute(text("SELECT * FROM staff")).fetchall()
            clinics = conn.execute(text("SELECT * FROM clinics")).fetchall()
        return render_template('admin.html', staff=staff, clinics=clinics)

    return render_template('admin_login.html')


# Unauthenticated API endpoint -- hidden constraint
# Built for an internal dashboard that was never completed
@app.route('/api/patients')
def api_patients():
    app.logger.info(f'API patient list accessed from {request.remote_addr}')
    with engine.connect() as conn:
        result = conn.execute(text(
            "SELECT id, first_name, last_name, dob, community, medical_history, hiv_status, pregnancy_status FROM patients"
        ))
        patients = [dict(row._mapping) for row in result]
    return jsonify(patients)


@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('login'))


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)