package handlers import ( "net/http" "time" "github.com/breakpilot/school-service/internal/services" "github.com/gin-gonic/gin" ) // ExportTimetableSolutionCSV streams the lessons of a solution as CSV. // The download filename includes the solution UUID so multiple plans don't // clobber each other when saved to disk. func (h *Handler) ExportTimetableSolutionCSV(c *gin.Context) { uid := getUserID(c) if uid == "" { respondError(c, http.StatusUnauthorized, "User not authenticated") return } solutionID := c.Param("id") lessons, err := h.timetableService.LoadExportLessons(c.Request.Context(), solutionID, uid) if err != nil { respondError(c, http.StatusInternalServerError, "Failed to load lessons: "+err.Error()) return } c.Header("Content-Type", "text/csv; charset=utf-8") c.Header("Content-Disposition", `attachment; filename="stundenplan-`+solutionID+`.csv"`) c.Writer.WriteHeader(http.StatusOK) if err := services.WriteCSV(c.Writer, lessons); err != nil { // Best-effort; headers already flushed. _ = c.Writer.Flush } } // ExportTimetableSolutionICS emits a single-week iCalendar. The reference // Monday defaults to the next Monday from "now"; callers can override via // ?start=YYYY-MM-DD to align to a school year. func (h *Handler) ExportTimetableSolutionICS(c *gin.Context) { uid := getUserID(c) if uid == "" { respondError(c, http.StatusUnauthorized, "User not authenticated") return } solutionID := c.Param("id") weekStart := services.NextMonday(time.Now()) if param := c.Query("start"); param != "" { parsed, err := time.Parse("2006-01-02", param) if err != nil { respondError(c, http.StatusBadRequest, "start must be YYYY-MM-DD") return } weekStart = parsed } sol, err := h.timetableService.GetSolution(c.Request.Context(), solutionID, uid) if err != nil { respondError(c, http.StatusNotFound, "Solution not found") return } lessons, err := h.timetableService.LoadExportLessons(c.Request.Context(), solutionID, uid) if err != nil { respondError(c, http.StatusInternalServerError, "Failed to load lessons: "+err.Error()) return } c.Header("Content-Type", "text/calendar; charset=utf-8") c.Header("Content-Disposition", `attachment; filename="stundenplan-`+solutionID+`.ics"`) c.Writer.WriteHeader(http.StatusOK) if err := services.WriteICS(c.Writer, lessons, weekStart, sol.Name); err != nil { // Same best-effort situation as CSV. _ = c.Writer.Flush } }