package api import ( "git.golem15.com/golem15/summercms/modules/lagoon" "net/http" "git.golem15.com/jakub/sm-bm-plugin/models" "gorm.io/gorm" ) // dashboardJSON is the answer of /dashboard. type dashboardJSON struct { NextSessions []sessionJSON `json:"next_sessions"` UpcomingDeadlines []deadlineJSON `json:"upcoming_deadlines"` CurrentMeeting *meetingJSON `json:"current_meeting"` NextMeeting *meetingJSON `json:"next_meeting"` Readings readingsSummary `json:"readings"` } // Dashboard answers GET /dashboard: the next class sessions (those not yet // over), the deadlines not yet due, the meeting under way today and the next // one, and the caller's reading progress. func (h *Handlers) Dashboard(w http.ResponseWriter, r *http.Request) { userID, ok := h.caller(w, r) if !ok { return } db, ok := h.db(w, r) if !ok { return } now := h.now().UTC() limit := h.dashboardLimit() out := dashboardJSON{} var sessions []models.ClassSession if err := preloadSession(db).Where("ends_at > ?", now).Order("starts_at, id").Limit(limit).Find(&sessions).Error; err != nil { writeOpaque500(w) return } out.NextSessions = newSessionsJSON(sessions) var deadlines []models.Deadline if err := db.Preload("Course").Where("due_at >= ?", now).Order("due_at, id").Limit(limit).Find(&deadlines).Error; err != nil { writeOpaque500(w) return } out.UpcomingDeadlines = newDeadlinesJSON(deadlines) day := lagoon.DateOf(today(h.now())).String() var err error if out.CurrentMeeting, err = meetingWhere(db, "starts_on <= ? AND ends_on >= ?", day, day); err != nil { writeOpaque500(w) return } if out.NextMeeting, err = meetingWhere(db, "starts_on > ?", day); err != nil { writeOpaque500(w) return } err = db.Raw(`SELECT COUNT(*) AS total, COUNT(p.id) AS read, COUNT(*) FILTER (WHERE r.is_required) AS required_total, COUNT(p.id) FILTER (WHERE r.is_required) AS required_read FROM jz_bm_readings r LEFT JOIN jz_bm_reading_progress p ON p.reading_id = r.id AND p.user_id = ?`, userID).Scan(&out.Readings).Error if err != nil { writeOpaque500(w) return } writeData(w, out) } // meetingWhere returns the first meeting by start date that matches the // condition, with its session count, or nil. func meetingWhere(db *gorm.DB, cond string, args ...any) (*meetingJSON, error) { var m models.Meeting res := db.Where(cond, args...).Order("starts_on, number").Limit(1).Find(&m) if res.Error != nil || res.RowsAffected == 0 { return nil, res.Error } var sessions int64 if err := db.Model(&models.ClassSession{}).Where("meeting_id = ?", m.ID).Count(&sessions).Error; err != nil { return nil, err } out := newMeetingJSON(m, sessions) return &out, nil }