nerdtrack/internal/tracker/tracker.go

133 lines
2.6 KiB
Go
Raw Permalink Normal View History

2021-12-05 17:46:53 +03:00
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
}