Module 7 – Attendance UI & Bulk API
Build a simple web UI to mark attendance for 60-student classes and a bulk API endpoint to accept batch updates.
1. Single-page Attendance UI (HTML + JS)
Copy this file as attendance.html
<!doctype html>
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Attendance</title></head><body>
<h2>Mark Attendance</h2>
<div>
<label>SubjectId:<input id="subject" /></label>
<label>Date:<input id="date" type="date" /></label>
<label>Hour:<input id="hour" type="number" min="1" max="8" /></label>
<button onclick="loadStudents()">Load Students</button>
</div>
<div id="students"></div>
<script>
async function loadStudents(){
const subject = document.getElementById('subject').value;
// call API to fetch students in this semester
const res = await fetch(`/api/students?subjectId=${subject}`);
const students = await res.json();
const container = document.getElementById('students');
container.innerHTML = '';
students.forEach(s => {
const row = document.createElement('div');
row.innerHTML = ` ${s.name} (${s.student_code})`;
container.appendChild(row);
});
}
async function submitBulk(){
const subject = document.getElementById('subject').value;
const date = document.getElementById('date').value;
const hour = parseInt(document.getElementById('hour').value||'1');
const checks = Array.from(document.querySelectorAll('#students input[type=checkbox]'));
const attendance = checks.map(c => ({ studentId: c.getAttribute('data-id'), status: c.checked? 'present' : 'absent'}));
await fetch('/api/attendance/bulk',{ method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ subjectId: subject, date, hour, attendance }) });
alert('Submitted');
}
</script>
<button onclick="submitBulk()">Submit Attendance</button>
</body></html>
2. Bulk API Endpoint (FastAPI)
# file: app/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
import databases
DATABASE_URL = "postgresql://postgres:password@localhost/mcp_db"
db = databases.Database(DATABASE_URL)
app = FastAPI()
class AttRow(BaseModel):
studentId: int
status: str
class BulkIn(BaseModel):
subjectId: int
date: str
hour: int
attendance: List[AttRow]
@app.post('/api/attendance/bulk')
async def bulk_att(payload: BulkIn):
# Basic validation
if not payload.attendance:
raise HTTPException(400,'No attendance rows')
query = "INSERT INTO attendance(subject_id, staff_id, date, hour, student_id, status) VALUES(:subject_id, :staff_id, :date, :hour, :student_id, :status)"
# staff_id will be set based on session - simplified here as NULL
async with db.transaction():
for r in payload.attendance:
await db.execute(query, values={
'subject_id': payload.subjectId,
'staff_id': None,
'date': payload.date,
'hour': payload.hour,
'student_id': r.studentId,
'status': r.status
})
return { 'status': 'success', 'stored': len(payload.attendance) }
Notes
- In production, attach staff_id from authenticated session and validate subject mapping.
- Wrap the bulk insert in a transaction to ensure atomicity.
- For 60 students, this endpoint should handle inserts promptly; consider using COPY or batch inserts for scale.
No comments:
Post a Comment