From cf1fd1dfeda65f5c40eff7af28e81bb0187bf3cc Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Wed, 13 Nov 2019 13:17:56 -0700 Subject: [PATCH] Submit a task --- server/ajax/ajax.go | 56 ++++++++++++++----------- server/ajax/list.go | 21 +++++++++- server/ajax/list/list.go | 12 +++++- server/ajax/storage.go | 39 +++++++++++++++--- server/ajax/storage_test.go | 4 +- server/ajax/task.go | 35 +++++++++++++++- server/ajax/task/task.go | 78 ++++++++++++++++++++++++++++++++++- server/ajax/task/task_test.go | 12 ++++++ server/ajax/task_test.go | 20 ++++----- server/routes.go | 2 +- testdata/entrypoint.sh | 23 +++++++++++ testdata/mytinytodo2 | 1 + testdata/run_mtt.sh | 5 +++ 13 files changed, 259 insertions(+), 49 deletions(-) create mode 100755 testdata/entrypoint.sh create mode 160000 testdata/mytinytodo2 create mode 100644 testdata/run_mtt.sh diff --git a/server/ajax/ajax.go b/server/ajax/ajax.go index 8749bac..b7c70e8 100644 --- a/server/ajax/ajax.go +++ b/server/ajax/ajax.go @@ -4,6 +4,7 @@ import ( "local/storage" "local/todo-server/config" "net/http" + "net/url" ) type Ajax struct { @@ -20,56 +21,63 @@ func New() (*Ajax, error) { func (a *Ajax) HandleAjax(w http.ResponseWriter, r *http.Request) { params := r.URL.Query() var foo func(http.ResponseWriter, *http.Request) error - if v := params.Get("loadLists"); v != "" { + if has(params, "loadLists") { foo = a.loadLists - } else if v := params.Get("loadTasks"); v != "" { + } else if has(params, "loadTasks") { foo = a.loadTasks - } else if v := params.Get("newTask"); v != "" { + } else if has(params, "newTask") { foo = a.newTask - } else if v := params.Get("fullNewTask"); v != "" { + } else if has(params, "fullNewTask") { foo = a.newTask - } else if v := params.Get("deleteTask"); v != "" { + } else if has(params, "deleteTask") { foo = a.deleteTask - } else if v := params.Get("completeTask"); v != "" { + } else if has(params, "completeTask") { foo = a.completeTask - } else if v := params.Get("editNote"); v != "" { + } else if has(params, "editNote") { foo = a.editNote - } else if v := params.Get("editTask"); v != "" { + } else if has(params, "editTask") { foo = a.editTask - } else if v := params.Get("changeOrder"); v != "" { + } else if has(params, "changeOrder") { foo = a.changeOrder - } else if v := params.Get("suggestTags"); v != "" { + } else if has(params, "suggestTags") { foo = a.suggestTags - } else if v := params.Get("setPrio"); v != "" { + } else if has(params, "setPrio") { foo = a.setPrio - } else if v := params.Get("tagCloud"); v != "" { + } else if has(params, "tagCloud") { foo = a.tagCloud - } else if v := params.Get("addList"); v != "" { + } else if has(params, "addList") { foo = a.addList - } else if v := params.Get("renameList"); v != "" { + } else if has(params, "renameList") { foo = a.renameList - } else if v := params.Get("deleteList"); v != "" { + } else if has(params, "deleteList") { foo = a.deleteList - } else if v := params.Get("setSort"); v != "" { + } else if has(params, "setSort") { foo = a.setSort - } else if v := params.Get("publishList"); v != "" { + } else if has(params, "publishList") { foo = a.publishList - } else if v := params.Get("moveTask"); v != "" { + } else if has(params, "moveTask") { foo = a.moveTask - } else if v := params.Get("changeListOrder"); v != "" { + } else if has(params, "changeListOrder") { foo = a.changeListOrder - } else if v := params.Get("parseTaskStr"); v != "" { + } else if has(params, "parseTaskStr") { foo = a.parseTaskStr - } else if v := params.Get("clearCompletedInList"); v != "" { + } else if has(params, "clearCompletedInList") { foo = a.clearCompletedInList - } else if v := params.Get("setShowNotesInList"); v != "" { + } else if has(params, "setShowNotesInList") { foo = a.setShowNotesInList - } else if v := params.Get("setHideList"); v != "" { + } else if has(params, "setHideList") { foo = a.setHideList } - if err := foo(w, r); err == storage.ErrNotFound { + if foo == nil { + http.NotFound(w, r) + } else if err := foo(w, r); err == storage.ErrNotFound { http.Error(w, err.Error(), http.StatusNotFound) } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } + +func has(params url.Values, k string) bool { + _, ok := params[k] + return ok +} diff --git a/server/ajax/list.go b/server/ajax/list.go index c3cbe64..27c983b 100644 --- a/server/ajax/list.go +++ b/server/ajax/list.go @@ -1,14 +1,32 @@ package ajax import ( + "encoding/json" "errors" + "local/todo-server/server/ajax/list" "net/http" ) type List struct{} func (a *Ajax) loadLists(w http.ResponseWriter, r *http.Request) error { - return errors.New("not impl") + lists, err := a.storageListLists() + if err != nil { + return err + } + // TODO + lists = append(lists, &list.List{ + ID: "Todo", + UUID: "Todo", + }) + if err := a.storageSetList(lists[0].ID, lists[0]); err != nil { + return err + } + // /TODO + return json.NewEncoder(w).Encode(map[string]interface{}{ + "total": len(lists), + "list": lists, + }) } func (a *Ajax) changeOrder(w http.ResponseWriter, r *http.Request) error { @@ -16,6 +34,7 @@ func (a *Ajax) changeOrder(w http.ResponseWriter, r *http.Request) error { } func (a *Ajax) addList(w http.ResponseWriter, r *http.Request) error { + // {"total":1,"list":[{"id":"21","name":"abc","sort":0,"published":0,"showCompl":0,"showNotes":0,"hidden":0}]} return errors.New("not impl") } diff --git a/server/ajax/list/list.go b/server/ajax/list/list.go index f8e8b57..a614d91 100644 --- a/server/ajax/list/list.go +++ b/server/ajax/list/list.go @@ -1,11 +1,19 @@ -package ajax +package list import ( "errors" "net/http" ) -type List struct{} +type List struct { + ID string `json:"name"` + UUID string `json:"id"` + Sort int `json:"sort"` + Published int `json:"published"` + ShowCompl int `json:"showCompl"` + ShowNotes int `json:"showNotes"` + Hidden int `json:"hidden"` +} func New(r *http.Request) (*List, error) { return &List{}, errors.New("not impl") diff --git a/server/ajax/storage.go b/server/ajax/storage.go index 833d65e..dfc021d 100644 --- a/server/ajax/storage.go +++ b/server/ajax/storage.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/gob" "local/todo-server/server/ajax/form" + "local/todo-server/server/ajax/list" "local/todo-server/server/ajax/task" "net/http" "path" @@ -11,12 +12,40 @@ import ( ) func (a *Ajax) Cur(r *http.Request) (string, string, []string) { - listID, _ := a.storageGetCur() + listID := form.Get(r, "list") taskID := form.Get(r, "id") - tags, _ := a.storageGetCurTags() + tags, _ := r.URL.Query()["t"] return listID, taskID, tags } +func (a *Ajax) storageListLists(filters ...func(t *list.List) bool) ([]*list.List, error) { + results, err := a.DB.List(nil, "", "}") + if err != nil { + return nil, err + } + lists := []*list.List{} + for _, result := range results { + if d, f := path.Split(result); d == "" || f == "" { + continue + } + list := &list.List{ + ID: result, + UUID: result, + } + filtered := true + for _, f := range filters { + if !f(list) { + filtered = false + break + } + } + if filtered { + lists = append(lists, list) + } + } + return lists, nil +} + func (a *Ajax) storageListTasks(listID string, filters ...func(t *task.Task) bool) ([]*task.Task, error) { results, err := a.DB.List(nil, listID+"/", listID+"/}") if err != nil { @@ -60,13 +89,13 @@ func (a *Ajax) storageDelTask(listID, taskID string) error { return a.storageDel(path.Join(listID, taskID)) } -func (a *Ajax) storageGetList(listID string) (*List, error) { - var list List +func (a *Ajax) storageGetList(listID string) (*list.List, error) { + var list list.List err := a.storageGet(listID, &list) return &list, err } -func (a *Ajax) storageSetList(listID string, list *List) error { +func (a *Ajax) storageSetList(listID string, list *list.List) error { return a.storageSet(listID, *list) } diff --git a/server/ajax/storage_test.go b/server/ajax/storage_test.go index f43d466..ca5c4ba 100644 --- a/server/ajax/storage_test.go +++ b/server/ajax/storage_test.go @@ -8,9 +8,9 @@ import ( func TestAjaxStorageCur(t *testing.T) { ajax := mockAjax() - r := httptest.NewRequest("POST", "/?id=abc", nil) + r := httptest.NewRequest("POST", "/?id=abc&list=def", nil) listID, taskID, tags := ajax.Cur(r) - if listID != "list" { + if listID != "def" { t.Error(listID) } if taskID != "abc" { diff --git a/server/ajax/task.go b/server/ajax/task.go index f998adf..30bc1da 100644 --- a/server/ajax/task.go +++ b/server/ajax/task.go @@ -49,11 +49,42 @@ func (a *Ajax) loadTasks(w http.ResponseWriter, r *http.Request) error { } func (a *Ajax) newTask(w http.ResponseWriter, r *http.Request) error { - listID, task, err := a.makeTask(r) + listID, newTask, err := a.makeTask(r) if err != nil { return err } - return a.storageSetTask(listID, task.UUID, task) + if err := a.storageSetTask(listID, newTask.UUID, newTask); err != nil { + return err + } + // {"total":4,"list":[ + // {"id":"3455", + // "title":"redo qvolution", + // "listId":"18", + // "date":"14 Oct 2019 12:56 PM", + // "dateInt":1571079392, + // "dateInline":"14 Oct", + // "dateInlineTitle":"created at 14 Oct 2019 12:56 PM", + // "dateEditedInt":1571079401, + // "dateCompleted":"", + // "dateCompletedInline":"", + // "dateCompletedInlineTitle":"Completed at ", + // "compl":0, + // "prio":"0", + // "note":"", + // "noteText":"", + // "ow":4, + // "tags":"work", + // "tags_ids":"138", + // "duedate":"", + // "dueClass":"", + // "dueStr":"", + // "dueInt":33330000, + // "dueTitle":"Due "} + // ]} + return json.NewEncoder(w).Encode(map[string]interface{}{ + "total": 1, + "list": []*task.Task{newTask}, + }) } func (a *Ajax) makeTask(r *http.Request) (string, *task.Task, error) { diff --git a/server/ajax/task/task.go b/server/ajax/task/task.go index a2945e8..5e3d434 100644 --- a/server/ajax/task/task.go +++ b/server/ajax/task/task.go @@ -1,7 +1,9 @@ package task import ( + "encoding/json" "errors" + "fmt" "local/todo-server/server/ajax/form" "net/http" "regexp" @@ -16,7 +18,7 @@ type Task struct { UUID string Title string Priority int - Tags []string + Tags StrList Created time.Time Edited time.Time @@ -26,12 +28,19 @@ type Task struct { Due time.Time } +type StrList []string + +func (sl StrList) MarshalJSON() ([]byte, error) { + s := strings.Join(sl, ", ") + return json.Marshal(s) +} + func New(r *http.Request) (*Task, error) { task := &Task{ UUID: uuid.New().String(), Title: form.Get(r, "title"), Priority: form.ToInt(form.Get(r, "prio")), - Tags: form.ToStrArr(form.Get(r, "tags")), + Tags: StrList(form.ToStrArr(form.Get(r, "tags"))), Created: time.Now(), Edited: time.Now(), @@ -42,6 +51,71 @@ func New(r *http.Request) (*Task, error) { return task, task.validate() } +func (t *Task) MarshalJSON() ([]byte, error) { + // {"total":4,"list":[ + // {"id":"3455", + // "title":"redo qvolution", + // "listId":"18", + // "date":"14 Oct 2019 12:56 PM", + // "dateInt":1571079392, + // "dateInline":"14 Oct", + // "dateInlineTitle":"created at 14 Oct 2019 12:56 PM", + // "dateEditedInt":1571079401, + // "dateCompleted":"", + // "dateCompletedInline":"", + // "dateCompletedInlineTitle":"Completed at ", + // "compl":0, + // "prio":"0", + // "note":"", + // "noteText":"", + // "ow":4, + // "tags":"work", + // "tags_ids":"138", + // "duedate":"", + // "dueClass":"", + // "dueStr":"", + // "dueInt":33330000, + // "dueTitle":"Due "} + // ]} + fullFormat := "02 Jan 2006 03:04 PM" + shortFormat := "02 Jan" + compl := 0 + if t.Complete { + compl = 1 + } + m := map[string]interface{}{ + "id": t.UUID, + "title": t.Title, + "listId": "list", + "date": t.Created.Format(fullFormat), + "dateInt": t.Created.Unix(), + "dateInline": t.Created.Format(shortFormat), + "dateInlineTitle": fmt.Sprintf("created at %s", t.Created.Format(fullFormat)), + "dateEditedInt": t.Edited.Unix(), + "dateCompleted": "", + "dateCompletedInline": "", + "dateCompletedInlineTitle": "", + "compl": compl, + "prio": t.Priority, + "note": strings.Join(t.Note, "\n"), + "noteText": strings.Join(t.Note, "\n"), + "ow": 0, + "tags": strings.Join([]string(t.Tags), ", "), + "tags_ids": "", + "duedate": t.Due.Format(fullFormat), + "dueClass": "", + "dueStr": t.Due.Format(shortFormat), + "dueInt": t.Due.Unix(), + "dueTitle": "Due ", + } + if t.Complete { + m["dateCompleted"] = t.Completed.Format(fullFormat) + m["dateCompletedInline"] = t.Completed.Format(shortFormat) + m["dateCompletedInlineTitle"] = "Completed at " + } + return json.Marshal(m) +} + func (t *Task) AppendTags(tags []string) { t.touch() t.Tags = append(t.Tags, tags...) diff --git a/server/ajax/task/task_test.go b/server/ajax/task/task_test.go index ea40b64..698a974 100644 --- a/server/ajax/task/task_test.go +++ b/server/ajax/task/task_test.go @@ -57,3 +57,15 @@ func toReq(m map[string]interface{}) *http.Request { b, _ := json.Marshal(m) return httptest.NewRequest("POST", "/paht", bytes.NewReader(b)) } + +func TestJSONMarshal(t *testing.T) { + task := &Task{Tags: []string{"a", "b"}} + b, _ := json.Marshal(task) + var m map[string]interface{} + json.Unmarshal(b, &m) + if v, ok := m["tags"]; !ok { + t.Error(ok, m) + } else if v != "a, b" { + t.Error(v, m) + } +} diff --git a/server/ajax/task_test.go b/server/ajax/task_test.go index ec3cdb5..7793bb8 100644 --- a/server/ajax/task_test.go +++ b/server/ajax/task_test.go @@ -14,7 +14,7 @@ func TestAjaxLoadTasks(t *testing.T) { func() { w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/", nil) + r := httptest.NewRequest("GET", "/?list=list", nil) a.loadTasks(w, r) var result struct { List []string `json:"list"` @@ -32,10 +32,10 @@ func TestAjaxLoadTasks(t *testing.T) { func() { w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/", nil) + r := httptest.NewRequest("GET", "/?list=list", nil) a.loadTasks(w, r) var result struct { - List []task.Task `json:"list"` + List []map[string]interface{} `json:"list"` } if v := w.Code; v != http.StatusOK { t.Error(v) @@ -50,7 +50,7 @@ func TestAjaxLoadTasks(t *testing.T) { func TestAjaxNewTask(t *testing.T) { ajax := mockAjax() w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/", strings.NewReader(`{ + r := httptest.NewRequest("GET", "/?list=list", strings.NewReader(`{ "title":"a" }`)) ajax.newTask(w, r) @@ -68,7 +68,7 @@ func TestAjaxNewTask(t *testing.T) { func TestAjaxMakeTask(t *testing.T) { ajax := mockAjax() - r := httptest.NewRequest("GET", "/", strings.NewReader(`{ + r := httptest.NewRequest("GET", "/?list=list", strings.NewReader(`{ "title":"a" }`)) listID, task, err := ajax.makeTask(r) @@ -87,7 +87,7 @@ func TestAjaxDeleteTask(t *testing.T) { ajax := mockAjax() ajax.storageSetTask("list", "b", &task.Task{Title: "c"}) w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/?id=b", nil) + r := httptest.NewRequest("GET", "/?id=b&list=list", nil) ajax.deleteTask(w, r) if v := w.Code; v != http.StatusOK { t.Error(v) @@ -109,7 +109,7 @@ func TestAjaxCompleteTask(t *testing.T) { ajax.storageSetTask("list", "b", &task.Task{Title: "c"}) for _, state := range []string{"1", "0"} { w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/?id=b&compl="+state, nil) + r := httptest.NewRequest("GET", "/?id=b&list=list&compl="+state, nil) ajax.completeTask(w, r) if v := w.Code; v != http.StatusOK { t.Error(v) @@ -126,7 +126,7 @@ func TestAjaxEditNote(t *testing.T) { ajax := mockAjax() ajax.storageSetTask("list", "b", &task.Task{Title: "c", Note: []string{"hi", "mom"}}) w := httptest.NewRecorder() - r := httptest.NewRequest("POST", "/?id=b&compl=0", strings.NewReader(`{ + r := httptest.NewRequest("POST", "/?id=b&list=list&compl=0", strings.NewReader(`{ "note":"hello world i like tacos" }`)) ajax.editNote(w, r) @@ -144,7 +144,7 @@ func TestAjaxEditTask(t *testing.T) { ajax := mockAjax() ajax.storageSetTask("list", "b", &task.Task{Title: "c", Note: []string{"hi"}}) w := httptest.NewRecorder() - r := httptest.NewRequest("POST", "/?id=b&compl=0", strings.NewReader(`{ + r := httptest.NewRequest("POST", "/?id=b&list=list&compl=0", strings.NewReader(`{ "title": "newtitle", "note":"hello world i like tacos" }`)) @@ -163,7 +163,7 @@ func TestAjaxMoveTask(t *testing.T) { ajax := mockAjax() ajax.storageSetTask("list", "b", &task.Task{Title: "c"}) w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/?id=b&to=listB", strings.NewReader(`{}`)) + r := httptest.NewRequest("GET", "/?id=b&list=list&to=listB", strings.NewReader(`{}`)) ajax.moveTask(w, r) if v := w.Code; v != http.StatusOK { t.Error(v) diff --git a/server/routes.go b/server/routes.go index ae85bce..fb7736c 100644 --- a/server/routes.go +++ b/server/routes.go @@ -23,7 +23,7 @@ func (s *Server) Routes() error { handler: s.phpProxy, }, { - path: fmt.Sprintf("/ajax.php"), + path: fmt.Sprintf("ajax.php"), handler: s.HandleAjax, }, } diff --git a/testdata/entrypoint.sh b/testdata/entrypoint.sh new file mode 100755 index 0000000..4aee4f7 --- /dev/null +++ b/testdata/entrypoint.sh @@ -0,0 +1,23 @@ +#! /bin/sh + +cd /mnt + +apk add --no-cache \ + ca-certificates \ + bash \ + git + +#if [ ! -d ./mytinytodo ]; then +if [ ! -d ./mytinytodo2 ]; then + #wget https://bitbucket.org/maxpozdeev/mytinytodo/downloads/mytinytodo-v1.4.3.zip + #unzip mytinytodo-v1.4.3.zip + git clone https://github.com/ptrckkk/myTinyTodo.git mytinytodo2 +fi + +if [ -z "$(grep invert ./mytinytodo2/themes/default/style.css)" ]; then + echo 'body { filter: invert(80%); background-color: #222; }' >> ./mytinytodo2/themes/default/style.css +fi + +#cd mytinytodo +cd mytinytodo2 +php -S 0.0.0.0:8080 diff --git a/testdata/mytinytodo2 b/testdata/mytinytodo2 new file mode 160000 index 0000000..e21afea --- /dev/null +++ b/testdata/mytinytodo2 @@ -0,0 +1 @@ +Subproject commit e21afea391ecac5c5f5b47639e5ce8cb8b7eb693 diff --git a/testdata/run_mtt.sh b/testdata/run_mtt.sh new file mode 100644 index 0000000..51ca982 --- /dev/null +++ b/testdata/run_mtt.sh @@ -0,0 +1,5 @@ +#! /bin/bash + +cd "$(dirname "$BASH_SOURCE")" +cd mytinytodo2 +php -S 0.0.0.0:38808