package api import "git.golem15.com/jakub/sm-bm-plugin/models" // idOf is the value of an optional id, 0 when it is nil. The API serves only // sessions and readings that have a course, so their course_id is set. func idOf(id *uint) uint { if id == nil { return 0 } return *id } // courseRef is the short form of a course embedded in other records. type courseRef struct { ID uint `json:"id"` Code *string `json:"code"` Name string `json:"name"` Form string `json:"form"` Semester int `json:"semester"` } func newCourseRef(c *models.Course) *courseRef { if c == nil { return nil } return &courseRef{ID: c.ID, Code: c.Code, Name: c.Name, Form: c.Form, Semester: c.Semester} } // courseJSON is a course's own fields. type courseJSON struct { ID uint `json:"id"` Code *string `json:"code"` Name string `json:"name"` Form string `json:"form"` Lecturer *string `json:"lecturer"` Semester int `json:"semester"` ECTS *float64 `json:"ects"` Assessment *string `json:"assessment"` ElectiveGroup *string `json:"elective_group"` Description *string `json:"description"` SyllabusURL *string `json:"syllabus_url"` SortOrder int `json:"sort_order"` } func newCourseJSON(c models.Course) courseJSON { return courseJSON{ ID: c.ID, Code: c.Code, Name: c.Name, Form: c.Form, Lecturer: c.Lecturer, Semester: c.Semester, ECTS: c.ECTS, Assessment: c.Assessment, ElectiveGroup: c.ElectiveGroup, Description: c.Description, SyllabusURL: c.SyllabusURL, SortOrder: c.SortOrder, } } // courseCounts are the per-course counters of /courses and /courses/{id}. type courseCounts struct { Sessions int64 `json:"sessions"` Readings int64 `json:"readings"` ReadingsRead int64 `json:"readings_read"` Materials int64 `json:"materials"` } type courseListJSON struct { courseJSON Counts courseCounts `json:"counts"` } type courseDetailJSON struct { courseJSON Counts courseCounts `json:"counts"` Sessions []sessionJSON `json:"sessions"` Readings []readingJSON `json:"readings"` Materials []materialListJSON `json:"materials"` } // meetingJSON is one zjazd. type meetingJSON struct { ID uint `json:"id"` Number int `json:"number"` StartsOn string `json:"starts_on"` EndsOn string `json:"ends_on"` Notes *string `json:"notes"` SessionsCount int64 `json:"sessions_count"` } func newMeetingJSON(m models.Meeting, sessions int64) meetingJSON { return meetingJSON{ID: m.ID, Number: m.Number, StartsOn: m.StartsOn.String(), EndsOn: m.EndsOn.String(), Notes: m.Notes, SessionsCount: sessions} } // sessionJSON is one class session with its course. type sessionJSON struct { ID uint `json:"id"` CourseID uint `json:"course_id"` MeetingID *uint `json:"meeting_id"` MeetingNumber *int `json:"meeting_number"` StartsAt string `json:"starts_at"` EndsAt string `json:"ends_at"` Room *string `json:"room"` Kind *string `json:"kind"` Notes *string `json:"notes"` IsOnline bool `json:"is_online"` Course *courseRef `json:"course"` } func newSessionJSON(s models.ClassSession) sessionJSON { out := sessionJSON{ ID: s.ID, CourseID: idOf(s.CourseID), MeetingID: s.MeetingID, StartsAt: models.FormatDateTime(s.StartsAt), EndsAt: models.FormatDateTime(s.EndsAt), Room: s.Room, Kind: s.Kind, Notes: s.Notes, IsOnline: s.IsOnline, Course: newCourseRef(s.Course), } if s.Meeting != nil { n := s.Meeting.Number out.MeetingNumber = &n } return out } func newSessionsJSON(rows []models.ClassSession) []sessionJSON { out := make([]sessionJSON, 0, len(rows)) for _, s := range rows { out = append(out, newSessionJSON(s)) } return out } // deadlineJSON is one terminarz entry. type deadlineJSON struct { ID uint `json:"id"` Title string `json:"title"` DueAt string `json:"due_at"` Kind string `json:"kind"` Description *string `json:"description"` CourseID *uint `json:"course_id"` Course *courseRef `json:"course"` } func newDeadlinesJSON(rows []models.Deadline) []deadlineJSON { out := make([]deadlineJSON, 0, len(rows)) for _, d := range rows { out = append(out, deadlineJSON{ ID: d.ID, Title: d.Title, DueAt: models.FormatDateTime(d.DueAt), Kind: d.Kind, Description: d.Description, CourseID: d.CourseID, Course: newCourseRef(d.Course), }) } return out } // readingJSON is one reading with the caller's read state. type readingJSON struct { ID uint `json:"id"` CourseID uint `json:"course_id"` Course *courseRef `json:"course"` Title string `json:"title"` Author *string `json:"author"` Source *string `json:"source"` URL *string `json:"url"` IsRequired bool `json:"is_required"` SortOrder int `json:"sort_order"` ReadAt *string `json:"read_at"` } // tagJSON is one material tag. type tagJSON struct { ID uint `json:"id"` Name string `json:"name"` Slug string `json:"slug"` } func newTagsJSON(tags []models.Tag) []tagJSON { out := make([]tagJSON, 0, len(tags)) for _, t := range tags { out = append(out, tagJSON{ID: t.ID, Name: t.Name, Slug: t.Slug}) } return out } // materialListJSON is a published material in a list. type materialListJSON struct { ID uint `json:"id"` CourseID *uint `json:"course_id"` Course *courseRef `json:"course"` Title string `json:"title"` Type string `json:"type"` Source *string `json:"source"` URL *string `json:"url"` PublishedAt string `json:"published_at"` Tags []tagJSON `json:"tags"` FilesCount int64 `json:"files_count"` } func newMaterialListJSON(m models.Material, files int64) materialListJSON { out := materialListJSON{ ID: m.ID, CourseID: m.CourseID, Course: newCourseRef(m.Course), Title: m.Title, Type: m.Type, Source: m.Source, URL: m.URL, Tags: newTagsJSON(m.Tags), FilesCount: files, } if m.PublishedAt != nil { out.PublishedAt = models.FormatDateTime(*m.PublishedAt) } return out } // materialDetailJSON is a published material with its body and files. type materialDetailJSON struct { materialListJSON Body *string `json:"body"` Files []fileJSON `json:"files"` } // fileJSON is one attached file. type fileJSON struct { ID uint `json:"id"` URL string `json:"url"` Name string `json:"name"` Size int64 `json:"size"` Mime string `json:"mime"` } // readingsSummary is the reading progress block of /dashboard. type readingsSummary struct { Total int64 `json:"total"` Read int64 `json:"read"` RequiredTotal int64 `json:"required_total"` RequiredRead int64 `json:"required_read"` }