mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat: GET /heartbeat endpoint (resolves #241)
This commit is contained in:
parent
7159df30c2
commit
e7f3432113
9
main.go
9
main.go
@ -2,9 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/lpar/gzipped/v2"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/routes/relay"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net"
|
||||
@ -13,6 +10,10 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/lpar/gzipped/v2"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/routes/relay"
|
||||
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/gorilla/handlers"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
@ -187,6 +188,7 @@ func main() {
|
||||
wakatimeV1StatsHandler := wtV1Routes.NewStatsHandler(userService, summaryService)
|
||||
wakatimeV1UsersHandler := wtV1Routes.NewUsersHandler(userService, heartbeatService)
|
||||
wakatimeV1ProjectsHandler := wtV1Routes.NewProjectsHandler(userService, heartbeatService)
|
||||
wakatimeV1HeartbeatsHandler := wtV1Routes.NewHeartbeatHandler(userService, heartbeatService)
|
||||
shieldV1BadgeHandler := shieldsV1Routes.NewBadgeHandler(summaryService, userService)
|
||||
|
||||
// MVC Handlers
|
||||
@ -241,6 +243,7 @@ func main() {
|
||||
wakatimeV1StatsHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1UsersHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1ProjectsHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1HeartbeatsHandler.RegisterRoutes(apiRouter)
|
||||
shieldV1BadgeHandler.RegisterRoutes(apiRouter)
|
||||
|
||||
// Static Routes
|
||||
|
@ -1,6 +1,8 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/muety/wakapi/models"
|
||||
)
|
||||
|
||||
@ -19,11 +21,34 @@ type HeartbeatEntry struct {
|
||||
IsWrite bool `json:"is_write"`
|
||||
Language string `json:"language"`
|
||||
Project string `json:"project"`
|
||||
Time models.CustomTime `json:"time"`
|
||||
Time float64 `json:"time"`
|
||||
Type string `json:"type"`
|
||||
UserId string `json:"user_id"`
|
||||
MachineNameId string `json:"machine_name_id"`
|
||||
UserAgentId string `json:"user_agent_id"`
|
||||
CreatedAt models.CustomTime `json:"created_at"`
|
||||
ModifiedAt models.CustomTime `json:"created_at"`
|
||||
ModifiedAt models.CustomTime `json:"created_at",omitempty`
|
||||
}
|
||||
|
||||
func ToHeartbeatEntry(entries []*models.Heartbeat) []HeartbeatEntry {
|
||||
out := make([]HeartbeatEntry, len(entries))
|
||||
for i := 0; i < len(entries); i++ {
|
||||
entry := entries[i]
|
||||
out[i] = HeartbeatEntry{
|
||||
Id: strconv.FormatUint(entry.ID, 10),
|
||||
Branch: entry.Branch,
|
||||
Category: entry.Category,
|
||||
Entity: entry.Entity,
|
||||
IsWrite: entry.IsWrite,
|
||||
Language: entry.Language,
|
||||
Project: entry.Project,
|
||||
Time: float64(entry.Time.T().Unix()),
|
||||
Type: entry.Type,
|
||||
UserId: entry.UserID,
|
||||
MachineNameId: entry.Machine,
|
||||
UserAgentId: entry.UserAgent,
|
||||
CreatedAt: entry.CreatedAt,
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
@ -145,6 +145,7 @@ func constructSuccessResponse(n int) *heartbeatResponseVm {
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body models.Heartbeat true "A single heartbeat"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /v1/users/{user}/heartbeats [post]
|
||||
@ -155,6 +156,7 @@ func (h *HeartbeatApiHandler) postAlias1() {}
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body models.Heartbeat true "A single heartbeat"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /compat/wakatime/v1/users/{user}/heartbeats [post]
|
||||
@ -165,6 +167,7 @@ func (h *HeartbeatApiHandler) postAlias2() {}
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body models.Heartbeat true "A single heartbeat"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /users/{user}/heartbeats [post]
|
||||
@ -185,6 +188,7 @@ func (h *HeartbeatApiHandler) postAlias4() {}
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body []models.Heartbeat true "Multiple heartbeats"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /v1/users/{user}/heartbeats.bulk [post]
|
||||
@ -195,6 +199,7 @@ func (h *HeartbeatApiHandler) postAlias5() {}
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body []models.Heartbeat true "Multiple heartbeats"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /compat/wakatime/v1/users/{user}/heartbeats.bulk [post]
|
||||
@ -205,6 +210,7 @@ func (h *HeartbeatApiHandler) postAlias6() {}
|
||||
// @Tags heartbeat
|
||||
// @Accept json
|
||||
// @Param heartbeat body []models.Heartbeat true "Multiple heartbeats"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /users/{user}/heartbeats.bulk [post]
|
||||
|
85
routes/compat/wakatime/v1/heartbeat.go
Normal file
85
routes/compat/wakatime/v1/heartbeat.go
Normal file
@ -0,0 +1,85 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
wakatime "github.com/muety/wakapi/models/compat/wakatime/v1"
|
||||
routeutils "github.com/muety/wakapi/routes/utils"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
)
|
||||
|
||||
type HeartbeatsResult struct {
|
||||
Data []wakatime.HeartbeatEntry `json:"data"`
|
||||
End string `json:"end"`
|
||||
Start string `json:"start"`
|
||||
Timezone string `json:"timezone"`
|
||||
}
|
||||
|
||||
type HeartbeatHandler struct {
|
||||
userSrvc services.IUserService
|
||||
heartbeatSrvc services.IHeartbeatService
|
||||
}
|
||||
|
||||
func NewHeartbeatHandler(userService services.IUserService, heartbeatService services.IHeartbeatService) *HeartbeatHandler {
|
||||
return &HeartbeatHandler{
|
||||
userSrvc: userService,
|
||||
heartbeatSrvc: heartbeatService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HeartbeatHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("").Subrouter()
|
||||
r.Use(
|
||||
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||
)
|
||||
r.Path("/compat/wakatime/v1/users/{user}/heartbeats").Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
// @Summary Get heartbeats of user for specified date
|
||||
// @ID get-heartbeats
|
||||
// @Tags heartbeat
|
||||
// @Param date query string true "Date"
|
||||
// @Param user path string true "Username (or current)"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} v1.HeartbeatEntry
|
||||
// @Failure 400 {string} string "bad date"
|
||||
// @Router /compat/wakatime/v1/users/{user}/heartbeats [get]
|
||||
func (h *HeartbeatHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
user, err := routeutils.CheckEffectiveUser(w, r, h.userSrvc, "current")
|
||||
if err != nil {
|
||||
return // response was already sent by util function
|
||||
}
|
||||
|
||||
params := r.URL.Query()
|
||||
dateParam := params.Get("date")
|
||||
date, err := time.Parse(conf.SimpleDateFormat, dateParam)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("bad date"))
|
||||
return
|
||||
}
|
||||
|
||||
timezone := user.TZ()
|
||||
rangeFrom, rangeTo := utils.StartOfDay(date.In(timezone)), utils.EndOfDay(date.In(timezone))
|
||||
|
||||
heartbeats, err := h.heartbeatSrvc.GetAllWithin(rangeFrom, rangeTo, user)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(conf.ErrInternalServerError))
|
||||
conf.Log().Request(r).Error("failed to retrieve heartbeats - %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
res := HeartbeatsResult{
|
||||
Data: wakatime.ToHeartbeatEntry(heartbeats),
|
||||
Start: rangeFrom.UTC().Format(time.RFC3339),
|
||||
End: rangeTo.UTC().Format(time.RFC3339),
|
||||
Timezone: timezone.String(),
|
||||
}
|
||||
utils.RespondJSON(w, r, http.StatusOK, res)
|
||||
}
|
@ -6,6 +6,9 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
@ -13,8 +16,6 @@ import (
|
||||
"github.com/muety/wakapi/utils"
|
||||
"go.uber.org/atomic"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const OriginWakatime = "wakatime"
|
||||
@ -284,7 +285,7 @@ func mapHeartbeat(
|
||||
OperatingSystem: ua.Os,
|
||||
Machine: ma.Value,
|
||||
UserAgent: ua.Value,
|
||||
Time: entry.Time,
|
||||
Time: models.CustomTime(time.Unix(0, int64(entry.Time*1e9))),
|
||||
Origin: OriginWakatime,
|
||||
OriginId: entry.Id,
|
||||
}).Hashed()
|
||||
|
@ -160,6 +160,48 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"/compat/wakatime/v1/users/{user}/heartbeats": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"heartbeat"
|
||||
],
|
||||
"summary": "Get heartbeats of user for specified date",
|
||||
"operationId": "get-heartbeats",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date",
|
||||
"name": "date",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.HeartbeatEntry"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "bad date",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@ -183,6 +225,13 @@ var doc = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -219,6 +268,13 @@ var doc = `{
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -863,6 +919,13 @@ var doc = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -899,6 +962,13 @@ var doc = `{
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -967,6 +1037,13 @@ var doc = `{
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -1003,6 +1080,13 @@ var doc = `{
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -1094,6 +1178,13 @@ var doc = `{
|
||||
"models.Summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"description": "branches are not persisted, but calculated at runtime in case a project filter is applied",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.SummaryItem"
|
||||
}
|
||||
},
|
||||
"editors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@ -1222,6 +1313,50 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.HeartbeatEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branch": {
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_write": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"language": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_name_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"project": {
|
||||
"type": "string"
|
||||
},
|
||||
"time": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Project": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -1250,6 +1385,12 @@ var doc = `{
|
||||
"v1.StatsData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.SummariesEntry"
|
||||
}
|
||||
},
|
||||
"daily_average": {
|
||||
"type": "number"
|
||||
},
|
||||
@ -1325,6 +1466,12 @@ var doc = `{
|
||||
"v1.SummariesData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.SummariesEntry"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
@ -145,6 +145,48 @@
|
||||
}
|
||||
},
|
||||
"/compat/wakatime/v1/users/{user}/heartbeats": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"heartbeat"
|
||||
],
|
||||
"summary": "Get heartbeats of user for specified date",
|
||||
"operationId": "get-heartbeats",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Date",
|
||||
"name": "date",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.HeartbeatEntry"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "bad date",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@ -168,6 +210,13 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -204,6 +253,13 @@
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -848,6 +904,13 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -884,6 +947,13 @@
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -952,6 +1022,13 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -988,6 +1065,13 @@
|
||||
"$ref": "#/definitions/models.Heartbeat"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Username (or current)",
|
||||
"name": "user",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -1079,6 +1163,13 @@
|
||||
"models.Summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"description": "branches are not persisted, but calculated at runtime in case a project filter is applied",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.SummaryItem"
|
||||
}
|
||||
},
|
||||
"editors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@ -1207,6 +1298,50 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.HeartbeatEntry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branch": {
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_write": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"language": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_name_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"project": {
|
||||
"type": "string"
|
||||
},
|
||||
"time": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Project": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -1235,6 +1370,12 @@
|
||||
"v1.StatsData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.SummariesEntry"
|
||||
}
|
||||
},
|
||||
"daily_average": {
|
||||
"type": "number"
|
||||
},
|
||||
@ -1310,6 +1451,12 @@
|
||||
"v1.SummariesData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branches": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.SummariesEntry"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
@ -54,6 +54,12 @@ definitions:
|
||||
type: object
|
||||
models.Summary:
|
||||
properties:
|
||||
branches:
|
||||
description: branches are not persisted, but calculated at runtime in case
|
||||
a project filter is applied
|
||||
items:
|
||||
$ref: '#/definitions/models.SummaryItem'
|
||||
type: array
|
||||
editors:
|
||||
items:
|
||||
$ref: '#/definitions/models.SummaryItem'
|
||||
@ -142,6 +148,35 @@ definitions:
|
||||
schemaVersion:
|
||||
type: integer
|
||||
type: object
|
||||
v1.HeartbeatEntry:
|
||||
properties:
|
||||
branch:
|
||||
type: string
|
||||
category:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
entity:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
is_write:
|
||||
type: boolean
|
||||
language:
|
||||
type: string
|
||||
machine_name_id:
|
||||
type: string
|
||||
project:
|
||||
type: string
|
||||
time:
|
||||
type: number
|
||||
type:
|
||||
type: string
|
||||
user_agent_id:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
type: object
|
||||
v1.Project:
|
||||
properties:
|
||||
id:
|
||||
@ -160,6 +195,10 @@ definitions:
|
||||
type: object
|
||||
v1.StatsData:
|
||||
properties:
|
||||
branches:
|
||||
items:
|
||||
$ref: '#/definitions/v1.SummariesEntry'
|
||||
type: array
|
||||
daily_average:
|
||||
type: number
|
||||
days_including_holidays:
|
||||
@ -209,6 +248,10 @@ definitions:
|
||||
type: object
|
||||
v1.SummariesData:
|
||||
properties:
|
||||
branches:
|
||||
items:
|
||||
$ref: '#/definitions/v1.SummariesEntry'
|
||||
type: array
|
||||
categories:
|
||||
items:
|
||||
$ref: '#/definitions/v1.SummariesEntry'
|
||||
@ -441,6 +484,33 @@ paths:
|
||||
tags:
|
||||
- wakatime
|
||||
/compat/wakatime/v1/users/{user}/heartbeats:
|
||||
get:
|
||||
operationId: get-heartbeats
|
||||
parameters:
|
||||
- description: Date
|
||||
in: query
|
||||
name: date
|
||||
required: true
|
||||
type: string
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/v1.HeartbeatEntry'
|
||||
"400":
|
||||
description: bad date
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get heartbeats of user for specified date
|
||||
tags:
|
||||
- heartbeat
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
@ -452,6 +522,11 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
@ -474,6 +549,11 @@ paths:
|
||||
items:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
type: array
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
@ -900,6 +980,11 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
@ -922,6 +1007,11 @@ paths:
|
||||
items:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
type: array
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
@ -965,6 +1055,11 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
@ -987,6 +1082,11 @@ paths:
|
||||
items:
|
||||
$ref: '#/definitions/models.Heartbeat'
|
||||
type: array
|
||||
- description: Username (or current)
|
||||
in: path
|
||||
name: user
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
|
@ -965,6 +965,121 @@
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create heartbeats (get heartbeats test)",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// 1640995199 Friday, 31 December 2021 11:59:59 PM (Jan 1st in +1, +2)",
|
||||
"// 1641074399 Saturday, 1 January 2022 9:59:59 PM (Jan 1st in +1, +2)",
|
||||
"// 1641081599 Saturday, 1 January 2022 11:59:59 PM (Jan 2nd in +1, +2)",
|
||||
""
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{WRITEUSER_TOKEN}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "[{\n \"entity\": \"/home/user1/dev/project1/main.go\",\n \"project\": \"wakapi\",\n \"language\": \"Go\",\n \"is_write\": true,\n \"type\": \"file\",\n \"category\": null,\n \"branch\": null,\n \"time\": 1640995199\n},\n{\n \"entity\": \"/home/user1/dev/project1/main.go\",\n \"project\": \"wakapi\",\n \"language\": \"Go\",\n \"is_write\": true,\n \"type\": \"file\",\n \"category\": null,\n \"branch\": null,\n \"time\": 1641074399\n},\n{\n \"entity\": \"/home/user1/dev/project1/main.go\",\n \"project\": \"wakapi\",\n \"language\": \"Go\",\n \"is_write\": true,\n \"type\": \"file\",\n \"category\": null,\n \"branch\": null,\n \"time\": 1641081599\n}]",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{BASE_URL}}/api/heartbeat",
|
||||
"host": [
|
||||
"{{BASE_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"heartbeat"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get heartbeats",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"pm.test(\"Status code is 200\", function () {",
|
||||
" pm.response.to.have.status(200);",
|
||||
"});",
|
||||
"",
|
||||
"pm.test(\"Response body is correct\", function () {",
|
||||
" var jsonData = pm.response.json();",
|
||||
" pm.expect(jsonData.timezone).to.eql(pm.collectionVariables.get('TZ'));",
|
||||
" var date = new Date(\"2022-01-01T00:00:00+0100\")",
|
||||
" pm.expect(new Date(jsonData.start)).to.eql(date);",
|
||||
" pm.expect(new Date(jsonData.end)).to.eql(new Date(date.getTime() + 3600 * 1000 * 24));",
|
||||
" pm.expect(jsonData.data.length).to.eql(2);",
|
||||
"});"
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
],
|
||||
"protocolProfileBehavior": {
|
||||
"disableCookies": true
|
||||
},
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{WRITEUSER_TOKEN}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{BASE_URL}}/api/compat/wakatime/v1/users/current/heartbeats?date=2022-01-01",
|
||||
"host": [
|
||||
"{{BASE_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"compat",
|
||||
"wakatime",
|
||||
"v1",
|
||||
"users",
|
||||
"current",
|
||||
"heartbeats"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "date",
|
||||
"value": "2022-01-01"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1982,7 +2097,7 @@
|
||||
"",
|
||||
"pm.test(\"Correct content\", function () {",
|
||||
" const jsonData = pm.response.json();",
|
||||
" pm.expect(jsonData.data.text).to.eql('0 hrs 2 mins');",
|
||||
" pm.expect(jsonData.data.text).to.eql('0 hrs 8 mins');",
|
||||
"});"
|
||||
],
|
||||
"type": "text/javascript"
|
||||
|
Loading…
Reference in New Issue
Block a user