From c2b3152a01ef256ef7baefe13e7949dece321618 Mon Sep 17 00:00:00 2001 From: velvettear Date: Thu, 2 Feb 2023 12:48:05 +0100 Subject: [PATCH] improvements and fixes --- README.md | 5 +++-- config.yml | 1 + internal/api/server.go | 15 ++++++++++++--- internal/tools/constants.go | 2 +- internal/tools/datetime.go | 8 ++++++++ internal/workday/workday.go | 35 +++++++++++++++++++++++++++++++++-- 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3611614..3b7c584 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ simple workday recording with a basic rest api | method | url | arguments | description | | ------ | --- | --------- | ----------- | -| `get` | /csv| from=DD.MM.YYYY
to=DD.MM.YYYY | get recordings (in range) as csv | -| `get` | /json| from=DD.MM.YYYY
to=DD.MM.YYYY | get recordings (in range) as json | +| `get` | /csv| from=DD.MM.YYYY
to=DD.MM.YYYY | get recordings (for specified range) as csv | +| `get` | /json| from=DD.MM.YYYY
to=DD.MM.YYYY | get recordings (for specified range) as json | | `get` | /today | | get aggregated recordings for today as json (if any) | +| `get` | /overtime | | get aggregated overtime (for specified range) | | `post` | /start | | start a new recording | | `post` | /stop | | stop the current recording (if any) | diff --git a/config.yml b/config.yml index 8e7db46..328f14a 100644 --- a/config.yml +++ b/config.yml @@ -13,6 +13,7 @@ report: - "Pause-Beginn" - "Pause-Ende" - "Pause-Dauer" + - "Saldo" users: exampleuser: diff --git a/internal/api/server.go b/internal/api/server.go index 9dc29ae..7aed1f7 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -30,7 +30,7 @@ func handleRequests(writer http.ResponseWriter, request *http.Request) { requestMethod := strings.ToLower(request.Method) user, authorized := isAuthorized(request) if !authorized { - log.Info("denying unauthorized '"+requestMethod+"' request", "path: "+requestPath) + log.Info("denying unauthorized '"+requestMethod+"' request", "path: '"+requestPath+"'") writer.WriteHeader(404) writer.Write([]byte("error: basic authorization failed\n")) return @@ -43,10 +43,10 @@ func handleRequests(writer http.ResponseWriter, request *http.Request) { handled = handlePost(user, writer, request) } if handled { - log.Debug("handled '"+requestMethod+"' request", "path: "+requestPath, "user: "+user) + log.Debug("handled '"+requestMethod+"' request", "path: '"+requestPath+"'", "user: '"+user+"'") return } - log.Debug("ignoring '"+requestMethod+"' request", "path: "+requestPath, "user: "+user) + log.Debug("ignoring '"+requestMethod+"' request", "path: '"+requestPath+"'", "user: '"+user+"'") writer.WriteHeader(501) writer.Write([]byte("error: endpoint '" + requestPath + "' not implemented\n")) } @@ -78,6 +78,15 @@ func handleGet(user string, writer http.ResponseWriter, request *http.Request) b } writer.WriteHeader(200) writer.Write([]byte(json + "\n")) + case "/overtime": + from, to := getTimespan(request.URL.Query()) + overtime := workday.GetOvertime(from, to, user) + if len(overtime) == 0 { + writer.WriteHeader(404) + break + } + writer.WriteHeader(200) + writer.Write([]byte(overtime + "\n")) case "/json": from, to := getTimespan(request.URL.Query()) json, error := workday.ToJSON(from, to, user) diff --git a/internal/tools/constants.go b/internal/tools/constants.go index afaecce..f42dfdc 100644 --- a/internal/tools/constants.go +++ b/internal/tools/constants.go @@ -3,4 +3,4 @@ package tools import "time" var ZeroDate = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) -var ReportHeaders = []string{"date", "workday start", "workday end", "workday duration", "pause start", "pause end", "pause duration"} +var ReportHeaders = []string{"date", "workday start", "workday end", "workday duration", "pause start", "pause end", "pause duration", "balance"} diff --git a/internal/tools/datetime.go b/internal/tools/datetime.go index e7131f4..cc62909 100644 --- a/internal/tools/datetime.go +++ b/internal/tools/datetime.go @@ -48,6 +48,11 @@ func TimeToHHMMSS(time time.Time) string { } func DurationToHHMMSS(duration time.Duration) string { + negative := false + if duration < 0 { + duration = duration * -1 + negative = true + } durationSeconds := duration.Seconds() durationHours := int(durationSeconds / 3600) if durationHours > 0 { @@ -71,6 +76,9 @@ func DurationToHHMMSS(duration time.Duration) string { for len(tmpDuration) < 8 { tmpDuration = "0" + tmpDuration } + if negative { + tmpDuration = "-" + tmpDuration + } return tmpDuration } diff --git a/internal/workday/workday.go b/internal/workday/workday.go index b978616..ff56676 100644 --- a/internal/workday/workday.go +++ b/internal/workday/workday.go @@ -22,7 +22,8 @@ func ToCSV(from time.Time, to time.Time, user string) string { tools.DurationToHHMMSS(workday.Duration) + ";" + tools.TimeToHHMMSS(workday.Pause.Start) + ";" + tools.TimeToHHMMSS(workday.Pause.Stop) + ";" + - tools.DurationToHHMMSS(workday.Pause.Duration) + tools.DurationToHHMMSS(workday.Pause.Duration) + ";" + + tools.DurationToHHMMSS(workday.Balance) } return report } @@ -50,6 +51,9 @@ func ToJSON(from time.Time, to time.Time, user string) (string, error) { } workdayJson.Pause = pauseJson } + if !workday.isOpen() { + workdayJson.Balance = tools.DurationToHHMMSS(workday.Balance) + } jsonWorkdays = append(jsonWorkdays, workdayJson) } bytes, error := json.Marshal(jsonWorkdays) @@ -73,10 +77,25 @@ func (workday *Workday) ToJSON(user string) (string, error) { } workdayJson.Pause = pauseJson } + if !workday.isOpen() { + workdayJson.Balance = tools.DurationToHHMMSS(workday.Balance) + } bytes, error := json.Marshal(workdayJson) return string(bytes), error } +func GetOvertime(from time.Time, to time.Time, user string) string { + workdays := getInRange(from, to, user) + if len(workdays) == 0 { + return "" + } + var overtime time.Duration + for _, workday := range workdays { + overtime += workday.Balance + } + return tools.DurationToHHMMSS(overtime) +} + func GetToday(user string) (Workday, error) { var workday Workday firstTimestamp := database.GetFirstTimestamp(user, time.Now()) @@ -94,6 +113,7 @@ func GetToday(user string) (Workday, error) { } else { workday.Duration = workday.Stop.Sub(workday.Start) } + workday.Balance = workday.Duration - time.Hour*8 return workday, nil } @@ -135,6 +155,7 @@ func aggregatedTimestampsToWorkdays(aggregatedTimestamps map[string][]database.T Start: tmpStart, Stop: tmpEnd, Duration: duration, + Balance: duration - time.Hour*8, } workday.insertFakePause() workdays = append(workdays, workday) @@ -154,13 +175,21 @@ func (workday *Workday) isOpen() bool { return workday.Stop == tools.ZeroDate } +func (workday *Workday) calculateBalance() { + workday.Balance = workday.Duration - time.Hour*8 +} + func (workday *Workday) insertFakePause() { var pause Pause + pauseLength := time.Minute * 30 + if workday.Duration.Hours() >= 10 { + pauseLength = time.Minute * 60 + } deviationStart := rand.Intn(15-(-15)) + (-15) pause.Start = workday.Start.Add(workday.Duration / 2) pause.Start = pause.Start.Add(time.Minute * time.Duration(deviationStart)) deviationEnd := rand.Intn(300) - pause.Stop = pause.Start.Add(time.Minute * 30).Add(time.Second * time.Duration(deviationEnd)) + pause.Stop = pause.Start.Add(pauseLength).Add(time.Second * time.Duration(deviationEnd)) pause.Duration = pause.Stop.Sub(pause.Start) workday.Pause = pause workday.Stop = workday.Stop.Add(workday.Pause.Duration) @@ -173,6 +202,7 @@ type Workday struct { Stop time.Time Duration time.Duration Pause Pause + Balance time.Duration } type Pause struct { @@ -189,6 +219,7 @@ type workdayJson struct { Duration string Open bool Pause pauseJson + Balance string } type pauseJson struct {