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:
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
5
models/compat/v1/common.go
Normal file
5
models/compat/v1/common.go
Normal file
@ -0,0 +1,5 @@
|
||||
package v1
|
||||
|
||||
type Filters struct {
|
||||
Project string
|
||||
}
|
147
models/compat/v1/summaries.go
Normal file
147
models/compat/v1/summaries.go
Normal 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(),
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user