recurring prototype

This commit is contained in:
Erik Winter 2021-01-31 10:01:03 +01:00
parent e50d624b9c
commit 18d3074633
6 changed files with 200 additions and 15 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
gte-process-inbox
/gte-process-inbox

View File

@ -0,0 +1,45 @@
package main
import (
"log"
"os"
"git.sr.ht/~ewintr/gte/internal/task"
"git.sr.ht/~ewintr/gte/pkg/mstore"
)
func main() {
config := &mstore.ImapConfiguration{
ImapUrl: os.Getenv("IMAP_URL"),
ImapUsername: os.Getenv("IMAP_USERNAME"),
ImapPassword: os.Getenv("IMAP_PASSWORD"),
}
if !config.Valid() {
log.Fatal("please set IMAP_USER, IMAP_PASSWORD, etc environment variables")
}
mailStore, err := mstore.ImapConnect(config)
if err != nil {
log.Fatal(err)
}
defer mailStore.Disconnect()
taskRepo := task.NewRepository(mailStore)
tasks, err := taskRepo.FindAll(task.FOLDER_RECURRING)
if err != nil {
log.Fatal(err)
}
for _, t := range tasks {
if t.RecursToday() {
subject, body, err := t.CreateNextMessage(task.Today)
if err != nil {
log.Fatal(err)
}
if err := mailStore.Add(task.FOLDER_PLANNED, subject, body); err != nil {
log.Fatal(err)
}
}
}
}

View File

@ -96,7 +96,7 @@ func NewDateFromString(date string) Date {
newWeekday = time.Sunday
}
daysToAdd := int(newWeekday) - weekday
daysToAdd := int(newWeekday) - int(weekday)
if daysToAdd <= 0 {
daysToAdd += 7
}
@ -116,11 +116,19 @@ func (d *Date) IsZero() bool {
return d.t.IsZero()
}
func (d *Date) Weekday() int {
return int(d.t.Weekday())
func (d *Date) Time() time.Time {
return d.t
}
func (d *Date) Weekday() time.Weekday {
return d.t.Weekday()
}
func (d *Date) Add(days int) Date {
year, month, day := d.t.Date()
return NewDate(year, int(month), day+days)
}
func (d *Date) After(ud Date) bool {
return d.t.After(ud.Time())
}

View File

@ -1,25 +1,68 @@
package task
import "time"
type Weekday time.Weekday
import (
"strings"
"time"
)
type Period int
type Recurrer interface {
RecursOn(date Date) bool
FirstAfter(date Date) Date
String() string
}
func NewRecurrer(recurStr string) Recurrer {
terms := strings.Split(recurStr, ", ")
if len(terms) < 3 {
return nil
}
startDate, err := time.Parse("2006-01-02", terms[0])
if err != nil {
return nil
}
if terms[1] != "weekly" {
return nil
}
if terms[2] != "wednesday" {
return nil
}
year, month, date := startDate.Date()
return Weekly{
Start: NewDate(year, int(month), date),
Weekday: time.Wednesday,
}
}
// yyyy-mm-dd, weekly, wednesday
type Weekly struct {
Start Date
Weekday Weekday
Weekday time.Weekday
}
func (w *Weekly) FirstAfter(date Date) Date {
func (w Weekly) RecursOn(date Date) bool {
if !w.Start.After(date) {
return false
}
return w.Weekday == date.Weekday()
}
func (w Weekly) FirstAfter(date Date) Date {
//sd := w.Start.Weekday()
return date
}
func (w Weekly) String() string {
return "2021-01-31, weekly, wednesday"
}
/*
type BiWeekly struct {
Start Date
Weekday Weekday
@ -30,3 +73,4 @@ type RecurringTask struct {
Start Date
Recurrer Recurrer
}
*/

View File

@ -0,0 +1,33 @@
package task_test
import (
"testing"
"time"
"git.sr.ht/~ewintr/go-kit/test"
"git.sr.ht/~ewintr/gte/internal/task"
)
func TestNewRecurrer(t *testing.T) {
for _, tc := range []struct {
name string
input string
exp task.Recurrer
}{
{
name: "empty",
},
{
name: "weekly",
input: "2021-01-31, weekly, wednesday",
exp: task.Weekly{
Start: task.NewDate(2021, 1, 31),
Weekday: time.Wednesday,
},
},
} {
t.Run(tc.name, func(t *testing.T) {
test.Equals(t, tc.exp, task.NewRecurrer(tc.input))
})
}
}

View File

@ -12,6 +12,7 @@ import (
var (
ErrOutdatedTask = errors.New("task is outdated")
ErrTaskIsNotRecurring = errors.New("task is not recurring")
)
const (
@ -124,6 +125,13 @@ func New(msg *mstore.Message) *Task {
}
due := NewDateFromString(dueStr)
// Recurrer
recurStr, d := FieldFromBody(FIELD_RECUR, msg.Body)
if d {
dirty = true
}
recur := NewRecurrer(recurStr)
// Folder
folderOld := msg.Folder
folderNew := folderOld
@ -131,11 +139,14 @@ func New(msg *mstore.Message) *Task {
switch {
case newId:
folderNew = FOLDER_NEW
case !newId && due.IsZero():
case !newId && recur != nil:
folderNew = FOLDER_RECURRING
case !newId && recur == nil && due.IsZero():
folderNew = FOLDER_UNPLANNED
case !newId && !due.IsZero():
case !newId && recur == nil && !due.IsZero():
folderNew = FOLDER_PLANNED
}
}
if folderOld != folderNew {
dirty = true
@ -163,6 +174,7 @@ func New(msg *mstore.Message) *Task {
Folder: folderNew,
Action: action,
Due: due,
Recur: recur,
Project: project,
Message: msg,
Current: true,
@ -183,6 +195,13 @@ func (t *Task) FormatSubject() string {
FIELD_DUE: t.Due.String(),
}
if fields[FIELD_DUE] != "" && fields[FIELD_PROJECT] == "" {
fields[FIELD_PROJECT] = " "
}
if fields[FIELD_PROJECT] != "" && fields[FIELD_ACTION] == "" {
fields[FIELD_ACTION] = " "
}
parts := []string{}
for _, f := range order {
if fields[f] != "" {
@ -194,15 +213,21 @@ func (t *Task) FormatSubject() string {
}
func (t *Task) FormatBody() string {
body := fmt.Sprintf("\n")
order := []string{FIELD_ACTION, FIELD_DUE, FIELD_PROJECT, FIELD_VERSION, FIELD_ID}
order := []string{FIELD_ACTION}
fields := map[string]string{
FIELD_ID: t.Id,
FIELD_VERSION: strconv.Itoa(t.Version),
FIELD_PROJECT: t.Project,
FIELD_ACTION: t.Action,
FIELD_DUE: t.Due.String(),
}
if t.IsRecurrer() {
order = append(order, FIELD_RECUR)
fields[FIELD_RECUR] = t.Recur.String()
} else {
order = append(order, FIELD_DUE)
fields[FIELD_DUE] = t.Due.String()
}
order = append(order, []string{FIELD_PROJECT, FIELD_VERSION, FIELD_ID}...)
keyLen := 0
for _, f := range order {
@ -211,6 +236,7 @@ func (t *Task) FormatBody() string {
}
}
body := fmt.Sprintf("\n")
for _, f := range order {
key := f + FIELD_SEPARATOR
for i := len(key); i <= keyLen; i++ {
@ -226,6 +252,35 @@ func (t *Task) FormatBody() string {
return body
}
func (t *Task) IsRecurrer() bool {
return t.Recur != nil
}
func (t *Task) RecursToday() bool {
if !t.IsRecurrer() {
return false
}
return true
return t.Recur.RecursOn(Today)
}
func (t *Task) CreateNextMessage(date Date) (string, string, error) {
if !t.IsRecurrer() {
return "", "", ErrTaskIsNotRecurring
}
tempTask := &Task{
Id: uuid.New().String(),
Version: 1,
Action: t.Action,
Project: t.Project,
Due: t.Recur.FirstAfter(date),
}
return tempTask.FormatSubject(), tempTask.FormatBody(), nil
}
func FieldFromBody(field, body string) (string, bool) {
value := ""
dirty := false