87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/calendarapi/internal/models"
|
|
"github.com/calendarapi/internal/repository"
|
|
"github.com/calendarapi/internal/utils"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type AvailabilityService struct {
|
|
queries *repository.Queries
|
|
calendar *CalendarService
|
|
event *EventService
|
|
}
|
|
|
|
func NewAvailabilityService(queries *repository.Queries, calendar *CalendarService, event *EventService) *AvailabilityService {
|
|
return &AvailabilityService{queries: queries, calendar: calendar, event: event}
|
|
}
|
|
|
|
func (s *AvailabilityService) GetBusyBlocks(ctx context.Context, userID uuid.UUID, calendarID uuid.UUID, rangeStart, rangeEnd time.Time) (*models.AvailabilityResponse, error) {
|
|
if _, err := s.calendar.GetRole(ctx, calendarID, userID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pgCalID := utils.ToPgUUID(calendarID)
|
|
events, err := s.queries.ListEventsByCalendarInRange(ctx, repository.ListEventsByCalendarInRangeParams{
|
|
CalendarID: pgCalID,
|
|
EndTime: utils.ToPgTimestamptz(rangeStart),
|
|
StartTime: utils.ToPgTimestamptz(rangeEnd),
|
|
})
|
|
if err != nil {
|
|
return nil, models.ErrInternal
|
|
}
|
|
|
|
recurring, err := s.queries.ListRecurringEventsByCalendar(ctx, repository.ListRecurringEventsByCalendarParams{
|
|
CalendarID: pgCalID,
|
|
StartTime: utils.ToPgTimestamptz(rangeEnd),
|
|
})
|
|
if err != nil {
|
|
return nil, models.ErrInternal
|
|
}
|
|
|
|
var busy []models.BusyBlock
|
|
for _, ev := range events {
|
|
if ev.RecurrenceRule.Valid {
|
|
continue
|
|
}
|
|
busy = append(busy, models.BusyBlock{
|
|
Start: utils.FromPgTimestamptz(ev.StartTime),
|
|
End: utils.FromPgTimestamptz(ev.EndTime),
|
|
EventID: utils.FromPgUUID(ev.ID),
|
|
})
|
|
}
|
|
|
|
for _, ev := range recurring {
|
|
occs := s.event.expandRecurrence(ev, rangeStart, rangeEnd)
|
|
for _, occ := range occs {
|
|
if occ.OccurrenceStartTime != nil {
|
|
busy = append(busy, models.BusyBlock{
|
|
Start: *occ.OccurrenceStartTime,
|
|
End: *occ.OccurrenceEndTime,
|
|
EventID: occ.ID,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Slice(busy, func(i, j int) bool {
|
|
return busy[i].Start.Before(busy[j].Start)
|
|
})
|
|
|
|
if busy == nil {
|
|
busy = []models.BusyBlock{}
|
|
}
|
|
|
|
return &models.AvailabilityResponse{
|
|
CalendarID: calendarID,
|
|
RangeStart: rangeStart,
|
|
RangeEnd: rangeEnd,
|
|
Busy: busy,
|
|
}, nil
|
|
}
|