1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

feat: implement summaries compat endpoint (resolve #44)

fix: fix all time view model
This commit is contained in:
Ferdinand Mütsch
2020-09-11 23:24:51 +02:00
parent a8009e107d
commit 21567e7601
12 changed files with 326 additions and 44 deletions

View File

@ -1,13 +1,36 @@
package v1
import (
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/utils"
"time"
)
// https://wakatime.com/developers#all_time_since_today
type AllTimeViewModel struct {
Data *AllTimeViewModelData `json:"data"`
type WakatimeAllTime struct {
Data *wakatimeAllTimeData `json:"data"`
}
type AllTimeViewModelData struct {
Seconds float32 `json:"seconds"` // total number of seconds logged since account created
Text string `json:"text"` // total time logged since account created as human readable string>
IsUpToDate bool `json:"is_up_to_date"` // true if the stats are up to date; when false, a 202 response code is returned and stats will be refreshed soon>
type wakatimeAllTimeData struct {
TotalSeconds float32 `json:"total_seconds"` // total number of seconds logged since account created
Text string `json:"text"` // total time logged since account created as human readable string>
IsUpToDate bool `json:"is_up_to_date"` // true if the stats are up to date; when false, a 202 response code is returned and stats will be refreshed soon>
}
func NewAllTimeFrom(summary *models.Summary, filters *Filters) *WakatimeAllTime {
var total time.Duration
if key := filters.Project; key != "" {
total = summary.TotalTimeByKey(models.SummaryProject, key)
} else {
total = summary.TotalTime()
}
return &WakatimeAllTime{
Data: &wakatimeAllTimeData{
TotalSeconds: float32(total.Seconds()),
Text: utils.FmtWakatimeDuration(total),
IsUpToDate: true,
},
}
}

View File

@ -0,0 +1,5 @@
package v1
type Filters struct {
Project string
}

View File

@ -0,0 +1,147 @@
package v1
import (
"fmt"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/utils"
"math"
"time"
)
// https://wakatime.com/developers#summaries
// https://pastr.de/v/736450
type WakatimeSummaries struct {
Data []*wakatimeSummariesData `json:"data"`
End time.Time `json:"end"`
Start time.Time `json:"start"`
}
type wakatimeSummariesData struct {
Categories []*wakatimeSummariesEntry `json:"categories"`
Dependencies []*wakatimeSummariesEntry `json:"dependencies"`
Editors []*wakatimeSummariesEntry `json:"editors"`
Languages []*wakatimeSummariesEntry `json:"languages"`
Machines []*wakatimeSummariesEntry `json:"machines"`
OperatingSystems []*wakatimeSummariesEntry `json:"operating_systems"`
Projects []*wakatimeSummariesEntry `json:"projects"`
GrandTotal *wakatimeSummariesGrandTotal `json:"grand_total"`
Range *wakatimeSummariesRange `json:"range"`
}
type wakatimeSummariesEntry struct {
Digital string `json:"digital"`
Hours int `json:"hours"`
Minutes int `json:"minutes"`
Name string `json:"name"`
Percent float64 `json:"percent"`
Seconds int `json:"seconds"`
Text string `json:"text"`
TotalSeconds float64 `json:"total_seconds"`
}
type wakatimeSummariesGrandTotal struct {
Digital string `json:"digital"`
Hours int `json:"hours"`
Minutes int `json:"minutes"`
Text string `json:"text"`
TotalSeconds float64 `json:"total_seconds"`
}
type wakatimeSummariesRange struct {
Date string `json:"date"`
End time.Time `json:"end"`
Start time.Time `json:"start"`
Text string `json:"text"`
Timezone string `json:"timezone"`
}
func NewSummariesFrom(summaries []*models.Summary, filters *Filters) *WakatimeSummaries {
data := make([]*wakatimeSummariesData, len(summaries))
minDate, maxDate := time.Now().Add(1*time.Second), time.Time{}
for i, s := range summaries {
data[i] = newDataFrom(s)
if s.FromTime.Before(minDate) {
minDate = s.FromTime
}
if s.ToTime.After(maxDate) {
maxDate = s.ToTime
}
}
return &WakatimeSummaries{
Data: data,
End: maxDate,
Start: minDate,
}
}
func newDataFrom(s *models.Summary) *wakatimeSummariesData {
zone, _ := time.Now().Zone()
total := s.TotalTime()
totalHrs, totalMins := int(total.Hours()), int((total - time.Duration(total.Hours())*time.Hour).Minutes())
data := &wakatimeSummariesData{
Categories: make([]*wakatimeSummariesEntry, 0),
Dependencies: make([]*wakatimeSummariesEntry, 0),
Editors: make([]*wakatimeSummariesEntry, len(s.Editors)),
Languages: make([]*wakatimeSummariesEntry, len(s.Languages)),
Machines: make([]*wakatimeSummariesEntry, len(s.Machines)),
OperatingSystems: make([]*wakatimeSummariesEntry, len(s.OperatingSystems)),
Projects: make([]*wakatimeSummariesEntry, len(s.Projects)),
GrandTotal: &wakatimeSummariesGrandTotal{
Digital: fmt.Sprintf("%d:%d", totalHrs, totalMins),
Hours: totalHrs,
Minutes: totalMins,
Text: utils.FmtWakatimeDuration(total),
TotalSeconds: total.Seconds(),
},
Range: &wakatimeSummariesRange{
Date: time.Now().Format(time.RFC3339),
End: s.ToTime,
Start: s.FromTime,
Text: "",
Timezone: zone,
},
}
for i, e := range s.Projects {
data.Projects[i] = convertEntry(e, s.TotalTimeBy(models.SummaryProject))
}
for i, e := range s.Editors {
data.Editors[i] = convertEntry(e, s.TotalTimeBy(models.SummaryEditor))
}
for i, e := range s.Languages {
data.Languages[i] = convertEntry(e, s.TotalTimeBy(models.SummaryLanguage))
}
for i, e := range s.OperatingSystems {
data.OperatingSystems[i] = convertEntry(e, s.TotalTimeBy(models.SummaryOS))
}
for i, e := range s.Machines {
data.Machines[i] = convertEntry(e, s.TotalTimeBy(models.SummaryMachine))
}
return data
}
func convertEntry(e *models.SummaryItem, entityTotal time.Duration) *wakatimeSummariesEntry {
// this is a workaround, since currently, the total time of a summary item is mistakenly represented in seconds
// TODO: fix some day, while migrating persisted summary items
total := e.Total * time.Second
hrs := int(total.Hours())
mins := int((total - time.Duration(hrs)*time.Hour).Minutes())
secs := int((total - time.Duration(hrs)*time.Hour - time.Duration(mins)*time.Minute).Seconds())
return &wakatimeSummariesEntry{
Digital: fmt.Sprintf("%d:%d:%d", hrs, mins, secs),
Hours: hrs,
Minutes: mins,
Name: e.Key,
Percent: math.Round((total.Seconds()/entityTotal.Seconds())*1e4) / 100,
Seconds: secs,
Text: utils.FmtWakatimeDuration(total),
TotalSeconds: total.Seconds(),
}
}

View File

@ -125,7 +125,6 @@ func (s *Summary) TotalTime() time.Duration {
var timeSum time.Duration
mappedItems := s.MappedItems()
// calculate total duration from any of the present sets of items
for _, t := range s.Types() {
if items := mappedItems[t]; len(*items) > 0 {
@ -136,15 +135,26 @@ func (s *Summary) TotalTime() time.Duration {
}
}
return timeSum
return timeSum * time.Second
}
func (s *Summary) TotalTimeBy(entityType uint8, key string) time.Duration {
func (s *Summary) TotalTimeBy(entityType uint8) time.Duration {
var timeSum time.Duration
mappedItems := s.MappedItems()
if items := mappedItems[entityType]; len(*items) > 0 {
for _, item := range *items {
timeSum += item.Total
}
}
// calculate total duration from any of the present sets of items
return timeSum * time.Second
}
func (s *Summary) TotalTimeByKey(entityType uint8, key string) time.Duration {
var timeSum time.Duration
mappedItems := s.MappedItems()
if items := mappedItems[entityType]; len(*items) > 0 {
for _, item := range *items {
if item.Key != key {
@ -154,5 +164,5 @@ func (s *Summary) TotalTimeBy(entityType uint8, key string) time.Duration {
}
}
return timeSum
return timeSum * time.Second
}