Skip to main content

Monitor Dashboard

Access the attendance monitoring dashboard to view all attendance records, active users, and absences.
GET /monitor
This endpoint requires admin authentication. Only users with username “admin” can access this endpoint. Regular users are redirected to the home page.

Response

Returns an HTML page (monitor.html) with attendance data.

Dashboard Features

The monitor dashboard displays:
Shows all attendance records with:
  • Username
  • Date of check-in
  • Time of check-in
  • Status (PUNTUAL if before 08:30:00, RETARDO if after)
Displays the most recent location for each user who has ever checked in.
Lists users who have not checked in today (excluding admin).

Implementation Details

The endpoint implementation (app.py:134-175):
@app.route('/monitor')
@login_required
def monitor():
    if current_user.id != 'admin':
        return redirect(url_for('index'))
    
    usuarios = leer_json(USUARIOS_FILE)
    todos_registros = leer_json(REGISTROS_FILE)
    hoy = datetime.datetime.now().strftime("%Y-%m-%d")
    
    asistencia = []
    quienes_registraron_hoy = set()
    
    for reg in todos_registros:
        hora_reg = reg.get('hora', '00:00:00')
        es_retardo = hora_reg > "08:30:00"
        
        asistencia.append({
            "usuario": reg.get('usuario', 'S/N'),
            "fecha": reg.get('fecha', 'S/F'),
            "hora": hora_reg,
            "status": "RETARDO" if es_retardo else "PUNTUAL"
        })
        
        if reg.get('fecha') == hoy:
            quienes_registraron_hoy.add(reg.get('usuario'))

    activos = []
    faltantes = []
    
    for u in usuarios:
        if u['username'] == 'admin': continue
        reg_user = [r for r in todos_registros if r['usuario'] == u['username']]
        if reg_user:
            activos.append(reg_user[-1])
        if u['username'] not in quienes_registraron_hoy:
            faltantes.append(u['username'])

    return render_template('monitor.html', 
                           asistencia=asistencia, 
                           activos=activos, 
                           faltantes=faltantes)

Code Example

curl -X GET http://localhost:5000/monitor \
  -b cookies.txt

Send Reminders

Manually trigger the automated reminder email system. Sends emails to all users who haven’t checked in today.
GET /send-reminders
This endpoint requires authentication. While not explicitly admin-only in the code, it’s intended for administrative use.

Response

Returns a plain text message:
Proceso de recordatorios ejecutado

Email Behavior

The reminder system:
  1. Checks all users in data/usuarios.json
  2. Identifies users who haven’t checked in today
  3. Excludes the admin user from reminders
  4. Sends emails to all identified users

Email Configuration

Emails are sent via Gmail SMTP:

Email Content

Subject: ⚠️ Recordatorio Automático: Inicia tu Turno
Body: Buenos días. Son las 8:00 AM y el sistema aún no detecta tu registro 
      de hoy. Por favor inicia tu monitoreo.

Implementation Details

The endpoint implementation (app.py:177-182):
@app.route('/send-reminders')
@login_required
def send_reminders():
    # Reutilizamos la función de envío para el botón manual
    enviar_recordatorio_automatizado()
    return "Proceso de recordatorios ejecutado"

Automated Schedule

The system automatically runs this reminder function at 8:00 AM daily using APScheduler:
scheduler = BackgroundScheduler(daemon=True)
scheduler.add_job(enviar_recordatorio_automatizado, 'cron', hour=8, minute=0)
scheduler.start()

Code Example

curl -X GET http://localhost:5000/send-reminders \
  -b cookies.txt

Generate PDF Report

Generate a comprehensive PDF attendance report with all records and tardiness statistics.
GET /reporte-pdf
This endpoint requires authentication. Any authenticated user can generate reports.

Response

  • Content-Type: application/pdf
  • Disposition: attachment; filename="reporte_asistencia.pdf"
  • Body: Binary PDF file

Report Contents

The generated PDF includes:
Header
Report title with generation timestamp in format: REPORTE DE ASISTENCIA - GENERADO: YYYY-MM-DD HH:MM:SS
Attendance Table
Table with columns:
  • Maestro (username)
  • Fecha (date)
  • Hora (time)
  • Estado (PUNTUAL or RETARDO)
Summary Statistics
Section showing total accumulated tardiness count per user

Implementation Details

The endpoint implementation (app.py:184-231):
@app.route('/reporte-pdf')
@login_required
def reporte_pdf():
    registros = leer_json(REGISTROS_FILE)
    buffer = BytesIO()
    p = canvas.Canvas(buffer, pagesize=letter)
    p.setTitle("Reporte de Asistencia Maestros")
    
    p.drawString(100, 750, f"REPORTE DE ASISTENCIA - GENERADO: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    p.line(100, 745, 520, 745)
    
    y = 710
    p.drawString(100, y, "Maestro")
    p.drawString(200, y, "Fecha")
    p.drawString(300, y, "Hora")
    p.drawString(400, y, "Estado")
    y -= 25
    
    stats = {}
    
    for r in registros:
        hora = r.get('hora', '00:00:00')
        estado = "RETARDO" if hora > "08:30:00" else "PUNTUAL"
        p.drawString(100, y, str(r.get('usuario', 'S/N')))
        p.drawString(200, y, str(r.get('fecha', 'S/F')))
        p.drawString(300, y, str(hora))
        p.drawString(400, y, estado)
        
        if estado == "RETARDO":
            usr = r.get('usuario', 'S/N')
            stats[usr] = stats.get(usr, 0) + 1
        
        y -= 15
        if y < 80: 
            p.showPage()
            y = 750

    y -= 40
    p.drawString(100, y, "RESUMEN TOTAL DE RETARDOS ACUMULADOS:")
    p.line(100, y-5, 380, y-5)
    y -= 25
    for user, count in stats.items():
        p.drawString(120, y, f"• {user}: {count} retardos.")
        y -= 15

    p.save()
    buffer.seek(0)
    return send_file(buffer, as_attachment=True, download_name="reporte_asistencia.pdf", mimetype='application/pdf')

Report Features

  • Multi-page support: Automatically creates new pages when content exceeds page height
  • Page size: Letter (8.5” x 11”)
  • Library: ReportLab PDF generation
  • Statistics: Counts total tardiness per user across all dates

Code Example

curl -X GET http://localhost:5000/reporte-pdf \
  -b cookies.txt \
  -o reporte_asistencia.pdf

Tardiness Rules

A record is marked as “RETARDO” if the check-in time is after 08:30:00. The comparison is performed as a string comparison: hora > "08:30:00".

Build docs developers (and LLMs) love