|
6 | 6 | "fmt" |
7 | 7 | "sort" |
8 | 8 | "time" |
| 9 | + |
| 10 | + "github.com/teambition/rrule-go" |
9 | 11 | ) |
10 | 12 |
|
11 | 13 | type ClassesService struct { |
@@ -185,3 +187,113 @@ func (svc *ClassesService) GetMissingAttendanceForFacility(args *models.QueryCon |
185 | 187 |
|
186 | 188 | return items, nil |
187 | 189 | } |
| 190 | + |
| 191 | +func (svc *ClassesService) GetTodaysSchedule(args *models.QueryContext, facilityID *uint) ([]models.TodaysScheduleItem, error) { |
| 192 | + classes, err := svc.db.GetActiveClassesWithEvents(args, facilityID) |
| 193 | + if err != nil { |
| 194 | + return nil, err |
| 195 | + } |
| 196 | + if len(classes) == 0 { |
| 197 | + return []models.TodaysScheduleItem{}, nil |
| 198 | + } |
| 199 | + |
| 200 | + loc, err := time.LoadLocation(args.Timezone) |
| 201 | + if err != nil { |
| 202 | + loc = time.UTC |
| 203 | + } |
| 204 | + nowLocal := time.Now().In(loc) |
| 205 | + startOfToday := time.Date(nowLocal.Year(), nowLocal.Month(), nowLocal.Day(), 0, 0, 0, 0, loc) |
| 206 | + endOfToday := startOfToday.AddDate(0, 0, 1) |
| 207 | + |
| 208 | + items := make([]models.TodaysScheduleItem, 0) |
| 209 | + for _, class := range classes { |
| 210 | + startDt := class.StartDt.In(loc) |
| 211 | + if startDt.After(endOfToday) { |
| 212 | + continue |
| 213 | + } |
| 214 | + if class.EndDt != nil { |
| 215 | + endDt := class.EndDt.In(loc) |
| 216 | + if endDt.Before(startOfToday) { |
| 217 | + continue |
| 218 | + } |
| 219 | + } |
| 220 | + |
| 221 | + for _, event := range class.Events { |
| 222 | + rule, err := event.GetRRuleWithTimezone(args.Timezone) |
| 223 | + if err != nil { |
| 224 | + continue |
| 225 | + } |
| 226 | + firstOccurrence := rule.After(time.Time{}, false) |
| 227 | + canonicalHour, canonicalMinute := getCanonicalHourAndMinute([]time.Time{firstOccurrence}, args.Timezone) |
| 228 | + overrideStartTimes := make(map[string]struct{}) |
| 229 | + for _, override := range event.Overrides { |
| 230 | + if override.IsCancelled { |
| 231 | + continue |
| 232 | + } |
| 233 | + overrideOptions, err := rrule.StrToROption(override.OverrideRrule) |
| 234 | + if err != nil { |
| 235 | + continue |
| 236 | + } |
| 237 | + overrideOptions.Dtstart = overrideOptions.Dtstart.In(time.UTC) |
| 238 | + overrideRule, err := rrule.NewRRule(*overrideOptions) |
| 239 | + if err != nil { |
| 240 | + continue |
| 241 | + } |
| 242 | + overrideOccurrences := overrideRule.Between(startOfToday.UTC(), endOfToday.UTC(), true) |
| 243 | + for _, occ := range overrideOccurrences { |
| 244 | + overrideStartTimes[occ.UTC().Format(time.RFC3339Nano)] = struct{}{} |
| 245 | + } |
| 246 | + } |
| 247 | + eventInstances := database.GenerateEventInstances(event, startOfToday, endOfToday) |
| 248 | + for _, inst := range eventInstances { |
| 249 | + if inst.IsCancelled { |
| 250 | + continue |
| 251 | + } |
| 252 | + localStart := inst.StartTime.In(loc) |
| 253 | + localOcc := localStart |
| 254 | + if _, isOverride := overrideStartTimes[inst.StartTime.UTC().Format(time.RFC3339Nano)]; !isOverride { |
| 255 | + localOcc = time.Date( |
| 256 | + localStart.Year(), |
| 257 | + localStart.Month(), |
| 258 | + localStart.Day(), |
| 259 | + canonicalHour, |
| 260 | + canonicalMinute, |
| 261 | + 0, |
| 262 | + 0, |
| 263 | + loc, |
| 264 | + ) |
| 265 | + } |
| 266 | + if localOcc.Before(startOfToday) || !localOcc.Before(endOfToday) { |
| 267 | + continue |
| 268 | + } |
| 269 | + facilityName := "" |
| 270 | + if class.Facility != nil { |
| 271 | + facilityName = class.Facility.Name |
| 272 | + } |
| 273 | + items = append(items, models.TodaysScheduleItem{ |
| 274 | + ClassID: class.ID, |
| 275 | + ClassName: class.Name, |
| 276 | + InstructorName: class.InstructorName, |
| 277 | + FacilityID: class.FacilityID, |
| 278 | + FacilityName: facilityName, |
| 279 | + EventID: inst.EventID, |
| 280 | + Date: localOcc.Format("2006-01-02"), |
| 281 | + StartTime: localOcc.Format("15:04"), |
| 282 | + Room: inst.Room, |
| 283 | + }) |
| 284 | + } |
| 285 | + } |
| 286 | + } |
| 287 | + |
| 288 | + sort.Slice(items, func(i, j int) bool { |
| 289 | + if items[i].Date == items[j].Date { //sorting by date, time, then by name |
| 290 | + if items[i].StartTime == items[j].StartTime { |
| 291 | + return items[i].ClassName < items[j].ClassName |
| 292 | + } |
| 293 | + return items[i].StartTime < items[j].StartTime |
| 294 | + } |
| 295 | + return items[i].Date < items[j].Date |
| 296 | + }) |
| 297 | + |
| 298 | + return items, nil |
| 299 | +} |
0 commit comments