Edoruin commited on
Commit
2c775a2
·
1 Parent(s): 41f3127

Add students assistance data in PDF file

Browse files
app/main.py CHANGED
@@ -14,9 +14,11 @@ import threading
14
  import time
15
  import base64
16
  import csv
 
17
  import requests
18
  import datetime
19
- from flask import Flask, render_template, request, jsonify, redirect, url_for, flash
 
20
  from flask_socketio import SocketIO, emit
21
  from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
22
  from werkzeug.security import generate_password_hash, check_password_hash
@@ -1114,6 +1116,67 @@ def api_attendance():
1114
 
1115
  return jsonify({"status": "error", "message": "No label provided"}), 400
1116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1117
  @app.route('/repos')
1118
  def repos():
1119
  GIT_TOKEN = os.getenv("GITLAB_TOKEN")
 
14
  import time
15
  import base64
16
  import csv
17
+ import io
18
  import requests
19
  import datetime
20
+ from flask import Flask, render_template, request, jsonify, redirect, url_for, flash, send_file
21
+ from fpdf import FPDF
22
  from flask_socketio import SocketIO, emit
23
  from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
24
  from werkzeug.security import generate_password_hash, check_password_hash
 
1116
 
1117
  return jsonify({"status": "error", "message": "No label provided"}), 400
1118
 
1119
+ class AttendancePDF(FPDF):
1120
+ def header(self):
1121
+ self.set_font('Arial', 'B', 15)
1122
+ self.cell(0, 10, 'MAKER SPACE - REPORTE DE ASISTENCIA', 0, 1, 'C')
1123
+ self.ln(5)
1124
+
1125
+ def footer(self):
1126
+ self.set_y(-15)
1127
+ self.set_font('Arial', 'I', 8)
1128
+ self.cell(0, 10, f'Página {self.page_no()}', 0, 0, 'C')
1129
+
1130
+ @app.route('/export/attendance/<student_id>')
1131
+ @login_required
1132
+ def export_attendance(student_id):
1133
+ # Buscar registros del estudiante
1134
+ all_logs = []
1135
+ if isinstance(face_mgr.faces, dict):
1136
+ all_logs = face_mgr.faces.get("attendance_log", [])
1137
+
1138
+ student_logs = [log for log in all_logs if log.get('student_id') == student_id]
1139
+
1140
+ if not student_logs:
1141
+ flash("No hay registros de asistencia para este estudiante.", "orange")
1142
+ return redirect(request.referrer or url_for('classroom_dashboard'))
1143
+
1144
+ student_name = student_logs[0].get('student_name', 'Estudiante')
1145
+
1146
+ # Crear PDF
1147
+ pdf = AttendancePDF()
1148
+ pdf.add_page()
1149
+ pdf.set_font("Arial", size=12)
1150
+
1151
+ # Info Estudiante
1152
+ pdf.set_font("Arial", 'B', 12)
1153
+ pdf.cell(0, 10, f"Estudiante: {student_name}", 0, 1)
1154
+ pdf.cell(0, 10, f"ID: {student_id}", 0, 1)
1155
+ pdf.ln(5)
1156
+
1157
+ # Tabla (Estilo Excel)
1158
+ pdf.set_fill_color(200, 220, 255)
1159
+ pdf.set_font("Arial", 'B', 10)
1160
+ pdf.cell(40, 10, "Fecha", 1, 0, 'C', 1)
1161
+ pdf.cell(40, 10, "Hora", 1, 0, 'C', 1)
1162
+ pdf.cell(40, 10, "Estado", 1, 0, 'C', 1)
1163
+ pdf.cell(70, 10, "Curso ID", 1, 1, 'C', 1)
1164
+
1165
+ pdf.set_font("Arial", size=10)
1166
+ for log in student_logs:
1167
+ pdf.cell(40, 10, log.get('date', '-'), 1)
1168
+ pdf.cell(40, 10, log.get('time', '-'), 1)
1169
+ pdf.cell(40, 10, log.get('status', 'PRESENTE'), 1)
1170
+ pdf.cell(70, 10, log.get('course_id', '-'), 1, 1)
1171
+
1172
+ output = io.BytesIO()
1173
+ pdf_content = pdf.output()
1174
+ output.write(pdf_content)
1175
+ output.seek(0)
1176
+
1177
+ filename = f"Asistencia_{student_name.replace(' ', '_')}.pdf"
1178
+ return send_file(output, as_attachment=True, download_name=filename, mimetype='application/pdf')
1179
+
1180
  @app.route('/repos')
1181
  def repos():
1182
  GIT_TOKEN = os.getenv("GITLAB_TOKEN")
app/requirements.txt CHANGED
@@ -13,3 +13,4 @@ datasets
13
  huggingface_hub
14
  mediapipe
15
  opencv-python-headless
 
 
13
  huggingface_hub
14
  mediapipe
15
  opencv-python-headless
16
+ fpdf2
app/templates/course_details.html CHANGED
@@ -67,10 +67,17 @@
67
  <tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
68
  <td style="padding: 1rem; font-weight: bold;">{{ student.name }}</td>
69
  <td style="padding: 1rem;">
70
- <span class="badge"
71
- style="background: rgba(16, 185, 129, 0.2); color: #10b981; padding: 0.2rem 0.5rem; border-radius: 0.5rem;">
72
- {{ student.attendance|length }}
73
- </span>
 
 
 
 
 
 
 
74
  </td>
75
  <td style="padding: 1rem;" class="text-dim">
76
  {% if student.attendance %}
 
67
  <tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
68
  <td style="padding: 1rem; font-weight: bold;">{{ student.name }}</td>
69
  <td style="padding: 1rem;">
70
+ <div style="display: flex; align-items: center; gap: 0.5rem;">
71
+ <span class="badge"
72
+ style="background: rgba(16, 185, 129, 0.2); color: #10b981; padding: 0.2rem 0.5rem; border-radius: 0.5rem;">
73
+ {{ student.attendance|length }}
74
+ </span>
75
+ <a href="{{ url_for('export_attendance', student_id=student.id) }}" class="btn glass"
76
+ style="padding: 0.2rem 0.5rem; font-size: 0.8rem; background: rgba(239, 68, 68, 0.1); color: #ef4444;"
77
+ title="Descargar PDF">
78
+ <i class="fas fa-file-pdf"></i> PDF
79
+ </a>
80
+ </div>
81
  </td>
82
  <td style="padding: 1rem;" class="text-dim">
83
  {% if student.attendance %}