diff --git a/models/summary.go b/models/summary.go index 5b97e5a..38f1175 100644 --- a/models/summary.go +++ b/models/summary.go @@ -26,6 +26,7 @@ type Summary struct { type SummaryItem struct { ID uint `json:"-" gorm:"primary_key"` SummaryID uint `json:"-"` + Type uint8 `json:"-"` Key string `json:"key"` Total time.Duration `json:"total"` } diff --git a/routes/summary.go b/routes/summary.go index e9c4e81..2f49baf 100644 --- a/routes/summary.go +++ b/routes/summary.go @@ -76,7 +76,7 @@ func (h *SummaryHandler) Get(w http.ResponseWriter, r *http.Request) { cacheKey := getHash([]time.Time{from, to}, user) if cachedSummary, ok := h.Cache.Get(cacheKey); !ok { // Cache Miss - summary, err = h.SummarySrvc.GetSummary(from, to, user) // 'to' is always constant + summary, err = h.SummarySrvc.CreateSummary(from, to, user) // 'to' is always constant if err != nil { w.WriteHeader(http.StatusInternalServerError) return diff --git a/services/aggregation.go b/services/aggregation.go index 2cc2141..4e1f44e 100644 --- a/services/aggregation.go +++ b/services/aggregation.go @@ -58,7 +58,7 @@ func (srv *AggregationService) Start(interval time.Duration) { func (srv *AggregationService) summaryWorker(jobs <-chan *AggregationJob, summaries chan<- *models.Summary) { for job := range jobs { - if summary, err := srv.SummaryService.GetSummary(job.From, job.To, &models.User{ID: job.UserID}); err != nil { + if summary, err := srv.SummaryService.CreateSummary(job.From, job.To, &models.User{ID: job.UserID}); err != nil { log.Printf("Failed to generate summary (%v, %v, %s) – %v.", job.From, job.To, job.UserID, err) } else { summaries <- summary diff --git a/services/summary.go b/services/summary.go index 34dcf2a..ffb637b 100644 --- a/services/summary.go +++ b/services/summary.go @@ -23,7 +23,8 @@ type Interval struct { End time.Time } -func (srv *SummaryService) GetSummary(from, to time.Time, user *models.User) (*models.Summary, error) { +// TODO: Rename methods to clarify difference between generating a new summary from old summaries and heartbeats, like this method, and only retrieving a persisted summary from database, like GetByUserWithin +func (srv *SummaryService) CreateSummary(from, to time.Time, user *models.User) (*models.Summary, error) { existingSummaries, err := srv.GetByUserWithin(user, from, to) if err != nil { return nil, err @@ -135,25 +136,25 @@ func mergeSummaries(summaries []*models.Summary) (*models.Summary, error) { } func mergeSummaryItems(existing *[]models.SummaryItem, new *[]models.SummaryItem) []models.SummaryItem { - items := make(map[string]time.Duration) + items := make(map[string]*models.SummaryItem) // Build map from existing for _, item := range *existing { - items[item.Key] = item.Total + items[item.Key] = &item } for _, item := range *new { - if _, ok := items[item.Key]; !ok { - items[item.Key] = item.Total + if it, ok := items[item.Key]; !ok { + items[item.Key] = &item } else { - items[item.Key] += item.Total + (*it).Total += item.Total } } var i int itemList := make([]models.SummaryItem, len(items)) for k, v := range items { - itemList[i] = models.SummaryItem{Key: k, Total: v} + itemList[i] = models.SummaryItem{Key: k, Total: v.Total, Type: v.Type} i++ } @@ -178,6 +179,10 @@ func (srv *SummaryService) GetByUserWithin(user *models.User, from, to time.Time Where(&models.Summary{UserID: user.ID}). Where("from_time >= ?", from). Where("to_time <= ?", to). + Preload("Projects", "type = ?", models.SummaryProject). + Preload("Languages", "type = ?", models.SummaryLanguage). + Preload("Editors", "type = ?", models.SummaryEditor). + Preload("OperatingSystems", "type = ?", models.SummaryOS). Find(&summaries).Error; err != nil { return nil, err } @@ -238,6 +243,7 @@ func (srv *SummaryService) aggregateBy(heartbeats []*models.Heartbeat, summaryTy items = append(items, models.SummaryItem{ Key: k, Total: v / time.Second, + Type: summaryType, }) }