A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
210 lines
5.7 KiB
Go
210 lines
5.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/breakpilot/school-service/internal/models"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// Attendance Handlers
|
|
|
|
// CreateAttendance creates an attendance record
|
|
func (h *Handler) CreateAttendance(c *gin.Context) {
|
|
var req models.CreateAttendanceRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
attendance, err := h.gradebookService.CreateAttendance(c.Request.Context(), &req)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to create attendance: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondCreated(c, attendance)
|
|
}
|
|
|
|
// GetClassAttendance returns attendance for a class
|
|
func (h *Handler) GetClassAttendance(c *gin.Context) {
|
|
classID := c.Param("classId")
|
|
startDateStr := c.Query("start_date")
|
|
endDateStr := c.Query("end_date")
|
|
|
|
var startDate, endDate *time.Time
|
|
if startDateStr != "" {
|
|
t, err := time.Parse("2006-01-02", startDateStr)
|
|
if err == nil {
|
|
startDate = &t
|
|
}
|
|
}
|
|
if endDateStr != "" {
|
|
t, err := time.Parse("2006-01-02", endDateStr)
|
|
if err == nil {
|
|
endDate = &t
|
|
}
|
|
}
|
|
|
|
attendance, err := h.gradebookService.GetClassAttendance(c.Request.Context(), classID, startDate, endDate)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to get attendance: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondSuccess(c, attendance)
|
|
}
|
|
|
|
// GetStudentAttendance returns attendance for a student
|
|
func (h *Handler) GetStudentAttendance(c *gin.Context) {
|
|
studentID := c.Param("studentId")
|
|
|
|
attendance, err := h.gradebookService.GetStudentAttendance(c.Request.Context(), studentID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to get attendance: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondSuccess(c, attendance)
|
|
}
|
|
|
|
// DeleteAttendance deletes an attendance record
|
|
func (h *Handler) DeleteAttendance(c *gin.Context) {
|
|
attendanceID := c.Param("id")
|
|
|
|
if err := h.gradebookService.DeleteAttendance(c.Request.Context(), attendanceID); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to delete attendance: "+err.Error())
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Attendance deleted"})
|
|
}
|
|
|
|
// BulkCreateAttendance creates attendance for multiple students
|
|
func (h *Handler) BulkCreateAttendance(c *gin.Context) {
|
|
classID := c.Param("classId")
|
|
|
|
var req struct {
|
|
Date string `json:"date" binding:"required"`
|
|
Records []struct {
|
|
StudentID string `json:"student_id" binding:"required"`
|
|
Status models.AttendanceStatus `json:"status" binding:"required"`
|
|
Periods int `json:"periods"`
|
|
Reason string `json:"reason"`
|
|
} `json:"records" binding:"required"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
records := make([]struct {
|
|
StudentID string
|
|
Status models.AttendanceStatus
|
|
Periods int
|
|
Reason string
|
|
}, len(req.Records))
|
|
|
|
for i, r := range req.Records {
|
|
records[i] = struct {
|
|
StudentID string
|
|
Status models.AttendanceStatus
|
|
Periods int
|
|
Reason string
|
|
}{
|
|
StudentID: r.StudentID,
|
|
Status: r.Status,
|
|
Periods: r.Periods,
|
|
Reason: r.Reason,
|
|
}
|
|
}
|
|
|
|
if err := h.gradebookService.BulkCreateAttendance(c.Request.Context(), classID, req.Date, records); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to create attendance: "+err.Error())
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Attendance created"})
|
|
}
|
|
|
|
// Gradebook Entry Handlers
|
|
|
|
// CreateGradebookEntry creates a gradebook entry
|
|
func (h *Handler) CreateGradebookEntry(c *gin.Context) {
|
|
var req models.CreateGradebookEntryRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
entry, err := h.gradebookService.CreateGradebookEntry(c.Request.Context(), &req)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to create entry: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondCreated(c, entry)
|
|
}
|
|
|
|
// GetGradebookEntries returns entries for a class
|
|
func (h *Handler) GetGradebookEntries(c *gin.Context) {
|
|
classID := c.Param("classId")
|
|
entryTypeStr := c.Query("entry_type")
|
|
startDateStr := c.Query("start_date")
|
|
endDateStr := c.Query("end_date")
|
|
|
|
var entryType *string
|
|
if entryTypeStr != "" {
|
|
entryType = &entryTypeStr
|
|
}
|
|
|
|
var startDate, endDate *time.Time
|
|
if startDateStr != "" {
|
|
t, err := time.Parse("2006-01-02", startDateStr)
|
|
if err == nil {
|
|
startDate = &t
|
|
}
|
|
}
|
|
if endDateStr != "" {
|
|
t, err := time.Parse("2006-01-02", endDateStr)
|
|
if err == nil {
|
|
endDate = &t
|
|
}
|
|
}
|
|
|
|
entries, err := h.gradebookService.GetGradebookEntries(c.Request.Context(), classID, entryType, startDate, endDate)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to get entries: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondSuccess(c, entries)
|
|
}
|
|
|
|
// GetStudentEntries returns gradebook entries for a student
|
|
func (h *Handler) GetStudentEntries(c *gin.Context) {
|
|
studentID := c.Param("studentId")
|
|
|
|
entries, err := h.gradebookService.GetStudentEntries(c.Request.Context(), studentID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to get entries: "+err.Error())
|
|
return
|
|
}
|
|
|
|
respondSuccess(c, entries)
|
|
}
|
|
|
|
// DeleteGradebookEntry deletes a gradebook entry
|
|
func (h *Handler) DeleteGradebookEntry(c *gin.Context) {
|
|
entryID := c.Param("id")
|
|
|
|
if err := h.gradebookService.DeleteGradebookEntry(c.Request.Context(), entryID); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "Failed to delete entry: "+err.Error())
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Entry deleted"})
|
|
}
|