fix: Restore all files lost during destructive rebase
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>
This commit is contained in:
216
school-service/internal/handlers/grade_handlers.go
Normal file
216
school-service/internal/handlers/grade_handlers.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/breakpilot/school-service/internal/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GetClassGrades returns grades for a class
|
||||
func (h *Handler) GetClassGrades(c *gin.Context) {
|
||||
classID := c.Param("classId")
|
||||
semesterStr := c.DefaultQuery("semester", "1")
|
||||
|
||||
semester, err := strconv.Atoi(semesterStr)
|
||||
if err != nil || semester < 1 || semester > 2 {
|
||||
semester = 1
|
||||
}
|
||||
|
||||
grades, err := h.gradeService.GetGradeOverview(c.Request.Context(), classID, semester)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get grades: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, grades)
|
||||
}
|
||||
|
||||
// GetStudentGrades returns all grades for a student
|
||||
func (h *Handler) GetStudentGrades(c *gin.Context) {
|
||||
studentID := c.Param("studentId")
|
||||
|
||||
grades, err := h.gradeService.GetStudentGrades(c.Request.Context(), studentID)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get grades: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, grades)
|
||||
}
|
||||
|
||||
// UpdateOralGrade updates the oral grade for a student
|
||||
func (h *Handler) UpdateOralGrade(c *gin.Context) {
|
||||
studentID := c.Param("studentId")
|
||||
subjectID := c.Param("subjectId")
|
||||
|
||||
var req models.UpdateOralGradeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
grade, err := h.gradeService.UpdateOralGrade(c.Request.Context(), studentID, subjectID, &req)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to update oral grade: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, grade)
|
||||
}
|
||||
|
||||
// CalculateFinalGrades calculates final grades for a class
|
||||
func (h *Handler) CalculateFinalGrades(c *gin.Context) {
|
||||
var req struct {
|
||||
ClassID string `json:"class_id" binding:"required"`
|
||||
Semester int `json:"semester" binding:"required,min=1,max=2"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.gradeService.CalculateFinalGrades(c.Request.Context(), req.ClassID, req.Semester); err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to calculate grades: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Grades calculated successfully"})
|
||||
}
|
||||
|
||||
// TransferApprovedGrades transfers approved exam results to grade overview
|
||||
func (h *Handler) TransferApprovedGrades(c *gin.Context) {
|
||||
teacherID := getUserID(c)
|
||||
if teacherID == "" {
|
||||
respondError(c, http.StatusUnauthorized, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.gradeService.TransferApprovedGrades(c.Request.Context(), teacherID); err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to transfer grades: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Grades transferred successfully"})
|
||||
}
|
||||
|
||||
// LockFinalGrade locks a final grade
|
||||
func (h *Handler) LockFinalGrade(c *gin.Context) {
|
||||
studentID := c.Param("studentId")
|
||||
subjectID := c.Param("subjectId")
|
||||
semesterStr := c.DefaultQuery("semester", "1")
|
||||
|
||||
semester, err := strconv.Atoi(semesterStr)
|
||||
if err != nil || semester < 1 || semester > 2 {
|
||||
semester = 1
|
||||
}
|
||||
|
||||
if err := h.gradeService.LockFinalGrade(c.Request.Context(), studentID, subjectID, semester); err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to lock grade: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Grade locked"})
|
||||
}
|
||||
|
||||
// UpdateGradeWeights updates the grade weights
|
||||
func (h *Handler) UpdateGradeWeights(c *gin.Context) {
|
||||
studentID := c.Param("studentId")
|
||||
subjectID := c.Param("subjectId")
|
||||
|
||||
var req struct {
|
||||
WrittenWeight int `json:"written_weight" binding:"required,min=0,max=100"`
|
||||
OralWeight int `json:"oral_weight" binding:"required,min=0,max=100"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
respondError(c, http.StatusBadRequest, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.WrittenWeight+req.OralWeight != 100 {
|
||||
respondError(c, http.StatusBadRequest, "Weights must sum to 100")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.gradeService.UpdateGradeWeights(c.Request.Context(), studentID, subjectID, req.WrittenWeight, req.OralWeight); err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to update weights: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Weights updated"})
|
||||
}
|
||||
|
||||
// =============================================
|
||||
// STATISTICS ENDPOINTS
|
||||
// =============================================
|
||||
|
||||
// GetClassStatistics returns grade statistics for a class
|
||||
// GET /api/v1/school/statistics/:classId
|
||||
func (h *Handler) GetClassStatistics(c *gin.Context) {
|
||||
classID := c.Param("classId")
|
||||
semesterStr := c.DefaultQuery("semester", "0") // 0 = both semesters
|
||||
|
||||
semester, _ := strconv.Atoi(semesterStr)
|
||||
|
||||
stats, err := h.gradeService.GetClassStatistics(c.Request.Context(), classID, semester)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, stats)
|
||||
}
|
||||
|
||||
// GetSubjectStatistics returns grade statistics for a specific subject in a class
|
||||
// GET /api/v1/school/statistics/:classId/subject/:subjectId
|
||||
func (h *Handler) GetSubjectStatistics(c *gin.Context) {
|
||||
classID := c.Param("classId")
|
||||
subjectID := c.Param("subjectId")
|
||||
semesterStr := c.DefaultQuery("semester", "0")
|
||||
|
||||
semester, _ := strconv.Atoi(semesterStr)
|
||||
|
||||
stats, err := h.gradeService.GetSubjectStatistics(c.Request.Context(), classID, subjectID, semester)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, stats)
|
||||
}
|
||||
|
||||
// GetStudentStatistics returns grade statistics for a specific student
|
||||
// GET /api/v1/school/statistics/student/:studentId
|
||||
func (h *Handler) GetStudentStatistics(c *gin.Context) {
|
||||
studentID := c.Param("studentId")
|
||||
|
||||
stats, err := h.gradeService.GetStudentStatistics(c.Request.Context(), studentID)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get statistics: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, stats)
|
||||
}
|
||||
|
||||
// GetNotenspiegel returns the grade distribution for a class or exam
|
||||
// GET /api/v1/school/statistics/:classId/notenspiegel
|
||||
func (h *Handler) GetNotenspiegel(c *gin.Context) {
|
||||
classID := c.Param("classId")
|
||||
subjectID := c.Query("subject_id")
|
||||
examID := c.Query("exam_id")
|
||||
semesterStr := c.DefaultQuery("semester", "0")
|
||||
|
||||
semester, _ := strconv.Atoi(semesterStr)
|
||||
|
||||
notenspiegel, err := h.gradeService.GetNotenspiegel(c.Request.Context(), classID, subjectID, examID, semester)
|
||||
if err != nil {
|
||||
respondError(c, http.StatusInternalServerError, "Failed to get Notenspiegel: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondSuccess(c, notenspiegel)
|
||||
}
|
||||
Reference in New Issue
Block a user