diff --git a/cmd/process-inbox/main.go b/cmd/process-inbox/main.go index ad3e0bb..cf0a464 100644 --- a/cmd/process-inbox/main.go +++ b/cmd/process-inbox/main.go @@ -36,4 +36,7 @@ func main() { } } } + if err := taskRepo.CleanUp(); err != nil { + log.Fatal(err) + } } diff --git a/internal/task/repo.go b/internal/task/repo.go index 90f3c9d..4f973cb 100644 --- a/internal/task/repo.go +++ b/internal/task/repo.go @@ -59,3 +59,51 @@ func (tr *TaskRepo) Update(t *Task) error { return nil } + +// Cleanup removes older versions of tasks +func (tr *TaskRepo) CleanUp() error { + // loop through folders, get all tasks + taskSet := make(map[string][]*Task) + + for _, folder := range knownFolders { + tasks, err := tr.FindAll(folder) + if err != nil { + return err + } + + for _, t := range tasks { + if _, ok := taskSet[t.Id]; !ok { + taskSet[t.Id] = []*Task{} + } + taskSet[t.Id] = append(taskSet[t.Id], t) + } + } + + // determine which ones need to be gone + var tobeRemoved []*Task + for _, tasks := range taskSet { + maxUid := uint32(0) + for _, t := range tasks { + if t.Message.Uid > maxUid { + maxUid = t.Message.Uid + } + } + + for _, t := range tasks { + if t.Message.Uid < maxUid { + tobeRemoved = append(tobeRemoved, t) + } + } + } + + //fmt.Printf("removing: %+v\n", tobeRemoved) + + // remove them + for _, t := range tobeRemoved { + if err := tr.mstore.Remove(t.Message); err != nil { + return err + } + } + + return nil +} diff --git a/internal/task/task.go b/internal/task/task.go index 8ba6c8e..0604a5b 100644 --- a/internal/task/task.go +++ b/internal/task/task.go @@ -19,9 +19,18 @@ const ( QUOTE_PREFIX = ">" PREVIOUS_SEPARATOR = "Previous version:" - FIELD_SEPARATOR = ":" - FIELD_ID = "id" - FIELD_ACTION = "action" + + FIELD_SEPARATOR = ":" + SUBJECT_SEPARATOR = " - " + + FIELD_ID = "id" + FIELD_ACTION = "action" + FIELD_PROJECT = "project" + FIELD_DUE = "date" +) + +var ( + knownFolders = []string{FOLDER_INBOX, FOLDER_NEW} ) // Task reperesents a task based on the data stored in a message @@ -33,8 +42,11 @@ type Task struct { // Folder is the same name as the mstore folder Folder string + // Ordinary task attributes Action string + Project string Due Date + Message *mstore.Message // Current indicates whether the task represents an existing message in the mstore @@ -51,6 +63,7 @@ type Task struct { // Keys that exist more than once are merged. The one that appears first in the body takes precedence. A value present in the Body takes precedence over one in the subject. // This enables updating a task by forwarding a topposted message whith new values for fields that the user wants to update. func New(msg *mstore.Message) *Task { + // Id dirty := false id, d := FieldFromBody(FIELD_ID, msg.Body) if id == "" { @@ -61,6 +74,7 @@ func New(msg *mstore.Message) *Task { dirty = true } + // Action action, d := FieldFromBody(FIELD_ACTION, msg.Body) if action == "" { action = FieldFromSubject(FIELD_ACTION, msg.Subject) @@ -72,16 +86,24 @@ func New(msg *mstore.Message) *Task { dirty = true } + // Folder folder := msg.Folder if folder == FOLDER_INBOX { folder = FOLDER_NEW dirty = true } + // Project + project, d := FieldFromBody(FIELD_PROJECT, msg.Body) + if d { + dirty = true + } + return &Task{ Id: id, - Action: action, Folder: folder, + Action: action, + Project: project, Message: msg, Current: true, Dirty: dirty, @@ -89,15 +111,29 @@ func New(msg *mstore.Message) *Task { } func (t *Task) FormatSubject() string { - return t.Action + order := []string{FIELD_PROJECT, FIELD_ACTION} + fields := map[string]string{ + FIELD_PROJECT: t.Project, + FIELD_ACTION: t.Action, + } + + parts := []string{} + for _, f := range order { + if fields[f] != "" { + parts = append(parts, fields[f]) + } + } + + return strings.Join(parts, SUBJECT_SEPARATOR) } func (t *Task) FormatBody() string { body := fmt.Sprintf("\n") - order := []string{FIELD_ID, FIELD_ACTION} + order := []string{FIELD_ID, FIELD_PROJECT, FIELD_ACTION} fields := map[string]string{ - FIELD_ID: t.Id, - FIELD_ACTION: t.Action, + FIELD_ID: t.Id, + FIELD_PROJECT: t.Project, + FIELD_ACTION: t.Action, } keyLen := 0 diff --git a/internal/task/task_test.go b/internal/task/task_test.go index fd54f31..a53af9e 100644 --- a/internal/task/task_test.go +++ b/internal/task/task_test.go @@ -12,7 +12,9 @@ import ( func TestNewFromMessage(t *testing.T) { id := "an id" action := "some action" + project := "project" folder := task.FOLDER_NEW + for _, tc := range []struct { name string message *mstore.Message @@ -27,19 +29,21 @@ func TestNewFromMessage(t *testing.T) { }, }, { - name: "with id, action and folder", + name: "id, action, project and folder", message: &mstore.Message{ Folder: folder, Body: fmt.Sprintf(` id: %s action: %s -`, id, action), +project: %s +`, id, action, project), }, hasId: true, exp: &task.Task{ - Id: id, - Folder: folder, - Action: action, + Id: id, + Folder: folder, + Action: action, + Project: project, }, }, { @@ -127,6 +131,8 @@ Forwarded message: func TestFormatSubject(t *testing.T) { action := "an action" + project := " a project" + for _, tc := range []struct { name string task *task.Task @@ -137,10 +143,20 @@ func TestFormatSubject(t *testing.T) { task: &task.Task{}, }, { - name: "with action", + name: "action", task: &task.Task{Action: action}, exp: action, }, + { + name: "project", + task: &task.Task{Project: project}, + exp: project, + }, + { + name: "action and project", + task: &task.Task{Action: action, Project: project}, + exp: fmt.Sprintf("%s - %s", project, action), + }, } { t.Run(tc.name, func(t *testing.T) { test.Equals(t, tc.exp, tc.task.FormatSubject()) @@ -151,6 +167,8 @@ func TestFormatSubject(t *testing.T) { func TestFormatBody(t *testing.T) { id := "an id" action := "an action" + project := "project" + for _, tc := range []struct { name string task *task.Task @@ -161,21 +179,24 @@ func TestFormatBody(t *testing.T) { task: &task.Task{}, exp: ` id: +project: action: `, }, { name: "filled", task: &task.Task{ - Id: id, - Action: action, + Id: id, + Action: action, + Project: project, Message: &mstore.Message{ Body: "previous body", }, }, exp: ` -id: an id -action: an action +id: an id +project: project +action: an action Previous version: @@ -233,7 +254,7 @@ field: valueb expDirty: true, }, { - name: "with colons", + name: "colons", field: "field", body: "field:: val:ue", expValue: ": val:ue",