From 56c4b22a43d7b037df26e5d968c3454bfa2c222c Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Sat, 10 Jul 2021 12:30:38 +0200 Subject: [PATCH] done command --- cmd/cli/command/command.go | 2 ++ cmd/cli/command/done.go | 39 ++++++++++++++++++++++++ internal/process/update.go | 53 +++++++++++++++++++++++++++++++++ internal/process/update_test.go | 43 ++++++++++++++++++++++++++ internal/storage/local.go | 6 ++++ internal/storage/memory.go | 11 +++++++ internal/storage/memory_test.go | 11 +++++++ internal/storage/sqlite.go | 23 ++++++++++++++ 8 files changed, 188 insertions(+) create mode 100644 cmd/cli/command/done.go create mode 100644 internal/process/update.go create mode 100644 internal/process/update_test.go diff --git a/cmd/cli/command/command.go b/cmd/cli/command/command.go index 9cef918..c4aa38d 100644 --- a/cmd/cli/command/command.go +++ b/cmd/cli/command/command.go @@ -29,6 +29,8 @@ func Parse(args []string, conf *configuration.Configuration) (Command, error) { return NewTomorrow(conf) case "new": return NewNew(conf, cmdArgs) + case "done": + return NewDone(conf, cmdArgs) default: return NewEmpty() } diff --git a/cmd/cli/command/done.go b/cmd/cli/command/done.go new file mode 100644 index 0000000..9bbedae --- /dev/null +++ b/cmd/cli/command/done.go @@ -0,0 +1,39 @@ +package command + +import ( + "git.ewintr.nl/gte/cmd/cli/format" + "git.ewintr.nl/gte/internal/configuration" + "git.ewintr.nl/gte/internal/process" + "git.ewintr.nl/gte/internal/storage" + "git.ewintr.nl/gte/pkg/msend" +) + +// Done updates a task to be marked done +type Done struct { + doner *process.Update +} + +func NewDone(conf *configuration.Configuration, cmdArgs []string) (*Done, error) { + local, err := storage.NewSqlite(conf.Sqlite()) + if err != nil { + return &Done{}, err + } + + disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP())) + fields := process.UpdateFields{"done": "true"} + + updater := process.NewUpdate(local, disp, cmdArgs[0], fields) + + return &Done{ + doner: updater, + }, nil +} + +func (d *Done) Do() string { + err := d.doner.Process() + if err != nil { + return format.FormatError(err) + } + + return "message sent\n" +} diff --git a/internal/process/update.go b/internal/process/update.go new file mode 100644 index 0000000..cbcbc9f --- /dev/null +++ b/internal/process/update.go @@ -0,0 +1,53 @@ +package process + +import ( + "errors" + "fmt" + + "git.ewintr.nl/gte/internal/storage" +) + +var ( + ErrUpdateTask = errors.New("could not update task") +) + +// Update dispatches an updated version of a task +type Update struct { + local storage.LocalRepository + disp *storage.Dispatcher + taskId string + updates UpdateFields +} + +type UpdateFields map[string]string + +func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, updates UpdateFields) *Update { + return &Update{ + local: local, + disp: disp, + taskId: taskId, + updates: updates, + } +} + +func (u *Update) Process() error { + task, err := u.local.FindById(u.taskId) + if err != nil { + return fmt.Errorf("%w: %v", ErrUpdateTask, err) + } + + for k, v := range u.updates { + switch k { + case "done": + if v == "true" { + task.Done = true + } + } + } + + if err := u.disp.Dispatch(task); err != nil { + return fmt.Errorf("%w: %v", ErrUpdateTask, err) + } + + return nil +} diff --git a/internal/process/update_test.go b/internal/process/update_test.go new file mode 100644 index 0000000..ec1a5f3 --- /dev/null +++ b/internal/process/update_test.go @@ -0,0 +1,43 @@ +package process_test + +import ( + "testing" + + "git.ewintr.nl/go-kit/test" + "git.ewintr.nl/gte/internal/process" + "git.ewintr.nl/gte/internal/storage" + "git.ewintr.nl/gte/internal/task" + "git.ewintr.nl/gte/pkg/msend" +) + +func TestUpdate(t *testing.T) { + task1 := &task.Task{ + Id: "id-1", + Project: "project1", + Action: "action1", + Folder: task.FOLDER_PLANNED, + } + local := storage.NewMemory() + out := msend.NewMemory() + disp := storage.NewDispatcher(out) + allTasks := []*task.Task{task1} + + t.Run("done", func(t *testing.T) { + local.SetTasks(allTasks) + updates := process.UpdateFields{ + "done": "true", + } + + update := process.NewUpdate(local, disp, task1.Id, updates) + test.OK(t, update.Process()) + expTask := task1 + expTask.Done = true + expMsg := &msend.Message{ + Subject: expTask.FormatSubject(), + Body: expTask.FormatBody(), + } + test.Assert(t, len(out.Messages) == 1, "amount of messages was not one") + test.Equals(t, expMsg, out.Messages[0]) + + }) +} diff --git a/internal/storage/local.go b/internal/storage/local.go index 90c7244..0684696 100644 --- a/internal/storage/local.go +++ b/internal/storage/local.go @@ -1,14 +1,20 @@ package storage import ( + "errors" "time" "git.ewintr.nl/gte/internal/task" ) +var ( + ErrTaskNotFound = errors.New("task was not found") +) + type LocalRepository interface { LatestSync() (time.Time, error) SetTasks(tasks []*task.Task) error FindAllInFolder(folder string) ([]*task.Task, error) FindAllInProject(project string) ([]*task.Task, error) + FindById(id string) (*task.Task, error) } diff --git a/internal/storage/memory.go b/internal/storage/memory.go index 111004a..b52bdbb 100644 --- a/internal/storage/memory.go +++ b/internal/storage/memory.go @@ -56,3 +56,14 @@ func (m *Memory) FindAllInProject(project string) ([]*task.Task, error) { return tasks, nil } + +func (m *Memory) FindById(id string) (*task.Task, error) { + for _, t := range m.tasks { + if t.Id == id { + return t, nil + } + + } + + return &task.Task{}, ErrTaskNotFound +} diff --git a/internal/storage/memory_test.go b/internal/storage/memory_test.go index 2a53a85..846a6ae 100644 --- a/internal/storage/memory_test.go +++ b/internal/storage/memory_test.go @@ -14,6 +14,7 @@ func TestMemory(t *testing.T) { folder1, folder2 := "folder1", "folder2" project1, project2 := "project1", "project2" task1 := &task.Task{ + Id: "id-1", Folder: folder1, Project: project1, Action: "action1", @@ -22,6 +23,7 @@ func TestMemory(t *testing.T) { }, } task2 := &task.Task{ + Id: "id-2", Folder: folder1, Project: project2, Action: "action2", @@ -30,6 +32,7 @@ func TestMemory(t *testing.T) { }, } task3 := &task.Task{ + Id: "id-3", Folder: folder2, Project: project1, Action: "action3", @@ -75,4 +78,12 @@ func TestMemory(t *testing.T) { } test.Equals(t, exp, act) }) + + t.Run("findbyid", func(t *testing.T) { + mem := storage.NewMemory() + test.OK(t, mem.SetTasks(tasks)) + act, err := mem.FindById("id-2") + test.OK(t, err) + test.Equals(t, task2, act) + }) } diff --git a/internal/storage/sqlite.go b/internal/storage/sqlite.go index 22fc0e5..f8c6ae3 100644 --- a/internal/storage/sqlite.go +++ b/internal/storage/sqlite.go @@ -122,6 +122,29 @@ WHERE project = ?`, project) return tasksFromRows(rows) } +func (s *Sqlite) FindById(id string) (*task.Task, error) { + var folder, action, project, due, recur string + var version int + row := s.db.QueryRow(` +SELECT version, folder, action, project, due, recur +FROM task +WHERE id = ? +LIMIT 1`, id) + if err := row.Scan(&version, &folder, &action, &project, &due, &recur); err != nil { + return &task.Task{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + + return &task.Task{ + Id: id, + Version: version, + Folder: folder, + Action: action, + Project: project, + Due: task.NewDateFromString(due), + Recur: task.NewRecurrer(recur), + }, nil +} + func tasksFromRows(rows *sql.Rows) ([]*task.Task, error) { tasks := []*task.Task{}