introduce localupdate
This commit is contained in:
parent
0a416d60f2
commit
91e5d86ec1
|
@ -5,6 +5,7 @@ import (
|
||||||
"git.ewintr.nl/gte/internal/configuration"
|
"git.ewintr.nl/gte/internal/configuration"
|
||||||
"git.ewintr.nl/gte/internal/process"
|
"git.ewintr.nl/gte/internal/process"
|
||||||
"git.ewintr.nl/gte/internal/storage"
|
"git.ewintr.nl/gte/internal/storage"
|
||||||
|
"git.ewintr.nl/gte/internal/task"
|
||||||
"git.ewintr.nl/gte/pkg/msend"
|
"git.ewintr.nl/gte/pkg/msend"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,13 +21,12 @@ func NewDone(localId int, conf *configuration.Configuration) (*Done, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP()))
|
disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP()))
|
||||||
fields := process.UpdateFields{"done": "true"}
|
|
||||||
localTask, err := local.FindByLocalId(localId)
|
localTask, err := local.FindByLocalId(localId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Done{}, err
|
return &Done{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
updater := process.NewUpdate(local, disp, localTask.Id, fields)
|
updater := process.NewUpdate(local, disp, localTask.Id, task.LocalUpdate{Done: true})
|
||||||
|
|
||||||
return &Done{
|
return &Done{
|
||||||
doner: updater,
|
doner: updater,
|
||||||
|
|
|
@ -47,8 +47,8 @@ func (u *Update) Do() string {
|
||||||
return "message sent\n"
|
return "message sent\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) {
|
func ParseTaskFieldArgs(args []string) (task.LocalUpdate, error) {
|
||||||
result := process.UpdateFields{}
|
lu := task.LocalUpdate{}
|
||||||
|
|
||||||
var action []string
|
var action []string
|
||||||
for _, f := range args {
|
for _, f := range args {
|
||||||
|
@ -56,15 +56,15 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) {
|
||||||
if len(split) == 2 {
|
if len(split) == 2 {
|
||||||
switch split[0] {
|
switch split[0] {
|
||||||
case "project":
|
case "project":
|
||||||
if _, ok := result[task.FIELD_PROJECT]; ok {
|
if lu.Project != "" {
|
||||||
return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT)
|
return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT)
|
||||||
}
|
}
|
||||||
result[task.FIELD_PROJECT] = split[1]
|
lu.Project = split[1]
|
||||||
case "due":
|
case "due":
|
||||||
if _, ok := result[task.FIELD_DUE]; ok {
|
if !lu.Due.IsZero() {
|
||||||
return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE)
|
return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE)
|
||||||
}
|
}
|
||||||
result[task.FIELD_DUE] = split[1]
|
lu.Due = task.NewDateFromString(split[1])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
action = append(action, f)
|
action = append(action, f)
|
||||||
|
@ -72,8 +72,8 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(action) > 0 {
|
if len(action) > 0 {
|
||||||
result[task.FIELD_ACTION] = strings.Join(action, " ")
|
lu.Action = strings.Join(action, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return lu, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,57 +7,54 @@ import (
|
||||||
|
|
||||||
"git.ewintr.nl/go-kit/test"
|
"git.ewintr.nl/go-kit/test"
|
||||||
"git.ewintr.nl/gte/cmd/cli/command"
|
"git.ewintr.nl/gte/cmd/cli/command"
|
||||||
"git.ewintr.nl/gte/internal/process"
|
|
||||||
"git.ewintr.nl/gte/internal/task"
|
"git.ewintr.nl/gte/internal/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseTaskFieldArgs(t *testing.T) {
|
func TestParseTaskFieldArgs(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
expField process.UpdateFields
|
expUpdate task.LocalUpdate
|
||||||
expErr error
|
expErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
expField: process.UpdateFields{
|
expUpdate: task.LocalUpdate{},
|
||||||
task.FIELD_ACTION: "",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "join action",
|
name: "join action",
|
||||||
input: "some things to do",
|
input: "some things to do",
|
||||||
expField: process.UpdateFields{
|
expUpdate: task.LocalUpdate{
|
||||||
task.FIELD_ACTION: "some things to do",
|
Action: "some things to do",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all",
|
name: "all",
|
||||||
input: "project:project do stuff due:2021-08-06",
|
input: "project:project do stuff due:2021-08-06",
|
||||||
expField: process.UpdateFields{
|
expUpdate: task.LocalUpdate{
|
||||||
task.FIELD_ACTION: "do stuff",
|
Action: "do stuff",
|
||||||
task.FIELD_PROJECT: "project",
|
Project: "project",
|
||||||
task.FIELD_DUE: "2021-08-06",
|
Due: task.NewDate(2021, 8, 6),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no action",
|
name: "no action",
|
||||||
input: "due:2021-08-06",
|
input: "due:2021-08-06",
|
||||||
expField: process.UpdateFields{
|
expUpdate: task.LocalUpdate{
|
||||||
task.FIELD_DUE: "2021-08-06",
|
Due: task.NewDate(2021, 8, 6),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "two projects",
|
name: "two projects",
|
||||||
input: "project:project1 project:project2",
|
input: "project:project1 project:project2",
|
||||||
expField: process.UpdateFields{},
|
expUpdate: task.LocalUpdate{},
|
||||||
expErr: command.ErrFieldAlreadyUsed,
|
expErr: command.ErrFieldAlreadyUsed,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
args := strings.Split(tc.input, " ")
|
args := strings.Split(tc.input, " ")
|
||||||
act, err := command.ParseTaskFieldArgs(args)
|
act, err := command.ParseTaskFieldArgs(args)
|
||||||
test.Equals(t, tc.expField, act)
|
test.Equals(t, tc.expUpdate, act)
|
||||||
test.Assert(t, errors.Is(err, tc.expErr), "wrong err")
|
test.Assert(t, errors.Is(err, tc.expErr), "wrong err")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,20 +14,18 @@ var (
|
||||||
|
|
||||||
// Update dispatches an updated version of a task
|
// Update dispatches an updated version of a task
|
||||||
type Update struct {
|
type Update struct {
|
||||||
local storage.LocalRepository
|
local storage.LocalRepository
|
||||||
disp *storage.Dispatcher
|
disp *storage.Dispatcher
|
||||||
taskId string
|
taskId string
|
||||||
updates UpdateFields
|
update task.LocalUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateFields map[string]string
|
func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, update task.LocalUpdate) *Update {
|
||||||
|
|
||||||
func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, updates UpdateFields) *Update {
|
|
||||||
return &Update{
|
return &Update{
|
||||||
local: local,
|
local: local,
|
||||||
disp: disp,
|
disp: disp,
|
||||||
taskId: taskId,
|
taskId: taskId,
|
||||||
updates: updates,
|
update: update,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,21 +34,7 @@ func (u *Update) Process() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrUpdateTask, err)
|
return fmt.Errorf("%w: %v", ErrUpdateTask, err)
|
||||||
}
|
}
|
||||||
|
tsk.Apply(u.update)
|
||||||
for k, v := range u.updates {
|
|
||||||
switch k {
|
|
||||||
case task.FIELD_DONE:
|
|
||||||
if v == "true" {
|
|
||||||
tsk.Done = true
|
|
||||||
}
|
|
||||||
case task.FIELD_DUE:
|
|
||||||
tsk.Due = task.NewDateFromString(v)
|
|
||||||
case task.FIELD_ACTION:
|
|
||||||
tsk.Action = v
|
|
||||||
case task.FIELD_PROJECT:
|
|
||||||
tsk.Project = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.disp.Dispatch(&tsk.Task); err != nil {
|
if err := u.disp.Dispatch(&tsk.Task); err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrUpdateTask, err)
|
return fmt.Errorf("%w: %v", ErrUpdateTask, err)
|
||||||
|
|
|
@ -23,13 +23,13 @@ func TestUpdate(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
updates process.UpdateFields
|
updates task.LocalUpdate
|
||||||
exp *task.Task
|
exp *task.Task
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "done",
|
name: "done",
|
||||||
updates: process.UpdateFields{
|
updates: task.LocalUpdate{
|
||||||
task.FIELD_DONE: "true",
|
Done: true,
|
||||||
},
|
},
|
||||||
exp: &task.Task{
|
exp: &task.Task{
|
||||||
Id: "id-1",
|
Id: "id-1",
|
||||||
|
@ -42,10 +42,10 @@ func TestUpdate(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fields",
|
name: "fields",
|
||||||
updates: process.UpdateFields{
|
updates: task.LocalUpdate{
|
||||||
task.FIELD_PROJECT: "project2",
|
Project: "project2",
|
||||||
task.FIELD_ACTION: "action2",
|
Action: "action2",
|
||||||
task.FIELD_DUE: "2021-08-01",
|
Due: task.NewDate(2021, 8, 1),
|
||||||
},
|
},
|
||||||
exp: &task.Task{
|
exp: &task.Task{
|
||||||
Id: "id-1",
|
Id: "id-1",
|
||||||
|
|
|
@ -1,12 +1,92 @@
|
||||||
package task
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type LocalTask struct {
|
type LocalTask struct {
|
||||||
Task
|
Task
|
||||||
LocalId int
|
LocalId int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lt *LocalTask) Apply(lu LocalUpdate) {
|
||||||
|
if lu.Action != "" {
|
||||||
|
lt.Action = lu.Action
|
||||||
|
}
|
||||||
|
if lu.Project != "" {
|
||||||
|
lt.Project = lu.Project
|
||||||
|
}
|
||||||
|
if lu.Recur != nil {
|
||||||
|
lt.Recur = lu.Recur
|
||||||
|
}
|
||||||
|
if !lu.Due.IsZero() {
|
||||||
|
lt.Due = lu.Due
|
||||||
|
}
|
||||||
|
if lu.Done {
|
||||||
|
lt.Done = lu.Done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ByDue []*LocalTask
|
type ByDue []*LocalTask
|
||||||
|
|
||||||
func (lt ByDue) Len() int { return len(lt) }
|
func (lt ByDue) Len() int { return len(lt) }
|
||||||
func (lt ByDue) Swap(i, j int) { lt[i], lt[j] = lt[j], lt[i] }
|
func (lt ByDue) Swap(i, j int) { lt[i], lt[j] = lt[j], lt[i] }
|
||||||
func (lt ByDue) Less(i, j int) bool { return lt[j].Due.After(lt[i].Due) }
|
func (lt ByDue) Less(i, j int) bool { return lt[j].Due.After(lt[i].Due) }
|
||||||
|
|
||||||
|
type LocalUpdate struct {
|
||||||
|
Action string
|
||||||
|
Project string
|
||||||
|
Due Date
|
||||||
|
Recur Recurrer
|
||||||
|
Done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lu LocalUpdate) Value() (driver.Value, error) {
|
||||||
|
return fmt.Sprintf(`action: %s
|
||||||
|
project: %s
|
||||||
|
recur: %s
|
||||||
|
due: %s
|
||||||
|
done: %t`,
|
||||||
|
lu.Action,
|
||||||
|
lu.Project,
|
||||||
|
lu.Recur.String(),
|
||||||
|
lu.Due.String(),
|
||||||
|
lu.Done), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lu *LocalUpdate) Scan(value interface{}) error {
|
||||||
|
body, err := driver.String.ConvertValue(value)
|
||||||
|
if err != nil {
|
||||||
|
*lu = LocalUpdate{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newLu := LocalUpdate{}
|
||||||
|
for _, line := range strings.Split(body.(string), "\n") {
|
||||||
|
kv := strings.SplitN(line, ":", 2)
|
||||||
|
if len(kv) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k := strings.TrimSpace(kv[0])
|
||||||
|
v := strings.TrimSpace(kv[1])
|
||||||
|
switch k {
|
||||||
|
case "action":
|
||||||
|
newLu.Action = v
|
||||||
|
case "project":
|
||||||
|
newLu.Project = v
|
||||||
|
case "recur":
|
||||||
|
newLu.Recur = NewRecurrer(v)
|
||||||
|
case "due":
|
||||||
|
newLu.Due = NewDateFromString(v)
|
||||||
|
case "done":
|
||||||
|
if v == "true" {
|
||||||
|
newLu.Done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*lu = newLu
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue