aboutsummaryrefslogtreecommitdiff
path: root/internal/tracker/tracker.go
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2021-12-05 17:46:53 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2021-12-05 17:46:53 +0300
commitbcdbe68ecde049ef62343584bcc26840322c4864 (patch)
tree4a02b4da5db29ab3f3526ff475db859293a97646 /internal/tracker/tracker.go
Initial commit
Diffstat (limited to 'internal/tracker/tracker.go')
-rw-r--r--internal/tracker/tracker.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/internal/tracker/tracker.go b/internal/tracker/tracker.go
new file mode 100644
index 0000000..6d9f058
--- /dev/null
+++ b/internal/tracker/tracker.go
@@ -0,0 +1,132 @@
+package tracker
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/spf13/afero"
+)
+
+var (
+ ErrEntryAlreadyExists = fmt.Errorf("entry with this title already exists")
+ ErrActivityNotFound = fmt.Errorf("there is no activity with given id")
+)
+
+type Tracker struct {
+ fs afero.Fs
+ document *Document
+}
+
+const FileName = "gotrack.json"
+
+func New(fs afero.Fs) (*Tracker, error) {
+ t := &Tracker{fs: fs}
+ if err := t.load(); err != nil {
+ return nil, err
+ }
+ return t, nil
+}
+
+func (t *Tracker) Add(title string, tags []string, contexts []string) (int, error) {
+ for _, activity := range t.document.Activities {
+ if strings.ToLower(strings.Trim(activity.Title, " ")) == strings.ToLower(strings.Trim(title, " ")) {
+ return 0, ErrEntryAlreadyExists
+ }
+ }
+ activity := Activity{
+ ID: t.document.LastKey + 1,
+ Title: title,
+ Tags: tags,
+ Context: contexts,
+ Spans: []*Span{},
+ }
+
+ t.document = &Document{
+ LastKey: activity.ID,
+ Activities: append(t.document.Activities, &activity),
+ }
+
+ return t.document.LastKey, t.save()
+}
+
+func (t *Tracker) Start(id int, comment string) error {
+ if err := t.Stop(id); err != nil {
+ return err
+ }
+ span := &Span{
+ Start: time.Now(),
+ Comment: comment,
+ }
+ activity := t.Activity(id)
+ activity.Spans = append(activity.Spans, span)
+ return t.save()
+}
+
+func (t *Tracker) Stop(id int) error {
+ activity := t.Activity(id)
+ if activity == nil {
+ return ErrActivityNotFound
+ }
+ if span := activity.Started(); span != nil {
+ t := time.Now()
+ span.Stop = &t
+ }
+ return t.save()
+}
+
+func (t *Tracker) List(all bool) []*Activity {
+ if all {
+ return t.document.Activities
+ }
+ return filterActivities(t.document.Activities, func(a *Activity) bool {
+ return a.Started() != nil
+ })
+}
+
+func (t *Tracker) Activity(id int) *Activity {
+ for _, activity := range t.document.Activities {
+ if activity.ID == id {
+ return activity
+ }
+ }
+ return nil
+}
+
+func (t *Tracker) load() (err error) {
+ t.document = new(Document)
+ f, err := t.fs.Open(FileName)
+ defer func() {
+ err = f.Close()
+ }()
+ if err != nil {
+ f, err = t.fs.Create(FileName)
+ if err != nil {
+ return err
+ }
+ return nil
+ }
+ return json.NewDecoder(f).Decode(t.document)
+}
+
+func (t *Tracker) save() (err error) {
+ f, err := t.fs.Create(FileName)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ err = f.Close()
+ }()
+ return json.NewEncoder(f).Encode(t.document)
+}
+
+func filterActivities(list []*Activity, filter func(activity *Activity) bool) []*Activity {
+ var filtered []*Activity
+ for _, activity := range list {
+ if filter(activity) {
+ filtered = append(filtered, activity)
+ }
+ }
+ return filtered
+}