Professor feedback mechanism for providing personalized comments on student forum and exam submissions
The feedback system enables professors to review student submissions and provide personalized comments on each activity, which students can then view in their profile.
# main.py:411-472@app.get("/expediente_completo/{email}")async def expediente_completo(email: str): if email == "[email protected]": return { "foro1": None, "foro2": None, "foro3": None, "foro4": None, "foro5": None, "foro6": None, "examen1": None, "examen2": None } conexion = conectar_bd() cursor = conexion.cursor(cursor_factory=RealDictCursor) # Fetch all forum submissions cursor.execute("SELECT * FROM respuestas_foro1 WHERE email = %s", (email,)) foro1 = cursor.fetchone() cursor.execute("SELECT * FROM respuestas_foro2 WHERE email = %s", (email,)) foro2 = cursor.fetchone() cursor.execute("SELECT * FROM respuestas_foro3 WHERE email = %s", (email,)) foro3 = cursor.fetchone() cursor.execute("SELECT * FROM respuestas_foro4 WHERE email = %s", (email,)) foro4 = cursor.fetchone() cursor.execute("SELECT * FROM respuestas_foro5 WHERE email = %s", (email,)) foro5 = cursor.fetchone() cursor.execute("SELECT * FROM respuestas_foro6 WHERE email = %s", (email,)) foro6 = cursor.fetchone() # Fetch exam submissions cursor.execute("SELECT * FROM examen1 WHERE email = %s", (email,)) examen1 = cursor.fetchone() cursor.execute("SELECT * FROM examen2 WHERE email = %s", (email,)) examen2 = cursor.fetchone() # Convert binary image data to base64 if present convertir_bytes(foro1) convertir_bytes(foro2) convertir_bytes(foro3) convertir_bytes(foro4) convertir_bytes(foro5) convertir_bytes(foro6) return { "foro1": foro1, "foro2": foro2, "foro3": foro3, "foro4": foro4, "foro5": foro5, "foro6": foro6, "examen1": examen1, "examen2": examen2 }
Image Data Conversion
The convertir_bytes() function converts binary image data stored in PostgreSQL BYTEA columns to base64-encoded data URLs:
# main.py:395-408def convertir_bytes(registro): if not registro: return claves = list(registro.keys()) for clave in claves: valor = registro[clave] if isinstance(valor, memoryview): valor = bytes(valor) if isinstance(valor, (bytes, bytearray)): encoded = base64.b64encode(valor).decode("utf-8") if 'imagen' in clave.lower(): registro[clave] = f"data:image/jpeg;base64,{encoded}" else: registro[clave] = encoded
This is essential for Foro 5, which stores uploaded images.
POST /guardar_feedbackContent-Type: application/json{ "email_alumno": "[email protected]", "actividad": "foro1", "comentario": "Excelente análisis de la DMO. Considera profundizar en los factores genéticos que mencionaste. Calificación: 9/10"}
1
Professor Selects Student
From the student list at /lista_estudiantes
2
View Student Expedient
Loads /expediente_completo/{email} to see all submissions
3
Write Feedback
For each activity (foro1, examen1, etc.), professor can write comments
4
Submit Feedback
POST to /guardar_feedback with student email, activity name, and comment
Students fetch their feedback from the profile page:
# main.py:729-742@app.get("/obtener_feedback/{email}")async def obtener_feedback(email: str): conexion = conectar_bd() if not conexion: raise HTTPException(500, "Error BD") try: cursor = conexion.cursor(cursor_factory=RealDictCursor) cursor.execute( "SELECT * FROM feedback WHERE email_alumno = %s ORDER BY fecha DESC", (email,) ) lista = cursor.fetchall() # Convert to dictionary keyed by activity name feedback_dict = {} for item in lista: feedback_dict[item['actividad']] = item['comentario'] return feedback_dict finally: conexion.close()
Example Response:
{ "foro1": "Excelente análisis de la DMO. Considera profundizar en los factores genéticos. Calificación: 9/10", "foro2": "Buen trabajo con la tabla de datos. La interpretación es correcta.", "examen1": "Muy bien en las preguntas teóricas. El juego de parejas fue perfecto. Puntaje: 8/8"}
The endpoint returns a dictionary where keys are activity names and values are the most recent feedback comment for that activity. If a student has multiple feedback entries for one activity (unlikely), only the most recent is shown due to ORDER BY fecha DESC and dictionary key overwriting.
Students can view a limited expedient of their own work:
# main.py:475-530@app.get("/expediente_completo_alumno/{email}")async def expediente_completo(email: str): if email == "[email protected]": return { "foro1": None, "foro2": None, "foro3": None, "foro4": None, "foro5": None, "foro6": None, "examen1": None, "examen2": None } conexion = conectar_bd() cursor = conexion.cursor(cursor_factory=RealDictCursor) # Only fetch specific fields (e.g., r2 from each activity) cursor.execute("SELECT r2 FROM respuestas_foro1 WHERE email = %s", (email,)) foro1 = cursor.fetchone() cursor.execute("SELECT r2 FROM respuestas_foro2 WHERE email = %s", (email,)) foro2 = cursor.fetchone() cursor.execute("SELECT r2 FROM respuestas_foro4 WHERE email = %s", (email,)) foro4 = cursor.fetchone() cursor.execute("SELECT r2 FROM respuestas_foro3 WHERE email = %s", (email,)) foro3 = cursor.fetchone() cursor.execute("SELECT r5 FROM respuestas_foro5 WHERE email = %s", (email,)) foro5 = cursor.fetchone() cursor.execute("SELECT r2 FROM examen1 WHERE email = %s", (email,)) examen1 = cursor.fetchone() cursor.execute("SELECT r2 FROM examen2 WHERE email = %s", (email,)) examen2 = cursor.fetchone() cursor.execute("SELECT r2 FROM respuestas_foro6 WHERE email = %s", (email,)) foro6 = cursor.fetchone() return { "foro1": foro1, "foro2": foro2, "foro3": foro3, "foro4": foro4, "foro5": foro5, "foro6": foro6, "examen1": examen1, "examen2": examen2 }
The student expedient endpoint (/expediente_completo_alumno/{email}) returns only partial data (specific response fields like r2 or r5), whereas the professor expedient (/expediente_completo/{email}) returns all fields. This limits what students can see of their own submissions.
Professors can use the feedback system to provide grades, suggestions, and encouragement. Students benefit from personalized guidance on each activity they complete.