From 6f9cdd9917d0891f229d7995b04c7e9d8e12163f Mon Sep 17 00:00:00 2001 From: Frank Horrigan Date: Sun, 26 Jan 2020 02:49:40 +1000 Subject: [PATCH 1/5] Add column existence check to smart --- packages/smart/smart.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/smart/smart.go b/packages/smart/smart.go index 29405f0fc..5dd2a774c 100644 --- a/packages/smart/smart.go +++ b/packages/smart/smart.go @@ -723,6 +723,10 @@ func (sc *SmartContract) AccessColumns(table string, columns *[]string, update b colname := converter.Sanitize(col, `->`) if strings.Contains(colname, `->`) { colname = colname[:strings.Index(colname, `->`)] + } else if _, ok := cols[colname]; "id" != colname && !ok { + err = fmt.Errorf(eColumnNotExist, colname) + logger.WithFields(log.Fields{"type": consts.DBError, "error": err}).Errorf("getting column") + return err } colList[i] = colname } From c585136a29bb2edaed2fc0b72991f5ce7e388ddf Mon Sep 17 00:00:00 2001 From: Frank Horrigan Date: Sun, 26 Jan 2020 02:49:57 +1000 Subject: [PATCH 2/5] Add dbfind, register route --- packages/api/dbfind.go | 121 ++++++++++++++++++++++++++++++++++++ packages/api/dbfind_test.go | 62 ++++++++++++++++++ packages/api/route.go | 1 + 3 files changed, 184 insertions(+) create mode 100644 packages/api/dbfind.go create mode 100644 packages/api/dbfind_test.go diff --git a/packages/api/dbfind.go b/packages/api/dbfind.go new file mode 100644 index 000000000..210497203 --- /dev/null +++ b/packages/api/dbfind.go @@ -0,0 +1,121 @@ +// Copyright (C) 2017, 2018, 2019 EGAAS S.A. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package api + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/AplaProject/go-apla/packages/conf" + "github.com/AplaProject/go-apla/packages/converter" + "github.com/AplaProject/go-apla/packages/model" + "github.com/AplaProject/go-apla/packages/smart" + "github.com/AplaProject/go-apla/packages/types" + "github.com/AplaProject/go-apla/packages/utils/tx" + "github.com/gorilla/mux" +) + +type dbFindResult struct { + List []interface{} +} + +type dbfindForm struct { + ID int64 `schema:"id"` + Order string `schema:"order"` + Columns string `schema:"columns"` + paginatorForm +} + +func (f *dbfindForm) Validate(r *http.Request) error { + if err := f.paginatorForm.Validate(r); err != nil { + return err + } + + if len(f.Columns) > 0 { + f.Columns = converter.EscapeName(f.Columns) + } + + return nil +} + +func getDbFindHandler(w http.ResponseWriter, r *http.Request) { + form := &dbfindForm{} + if err := parseForm(r, form); err != nil { + errorResponse(w, err, http.StatusBadRequest) + return + } + + params := mux.Vars(r) + client := getClient(r) + tableName := strings.ToLower(params["table"]) + sc := smart.SmartContract{ + OBS: conf.Config.IsSupportingOBS(), + VM: smart.GetVM(), + TxSmart: tx.SmartContract{ + Header: tx.Header{ + EcosystemID: client.EcosystemID, + KeyID: client.KeyID, + NetworkID: conf.Config.NetworkID, + }, + }, + } + + // Check table existence + prefix := client.Prefix() + table := &model.Table{} + table.SetTablePrefix(prefix) + if found, err := table.Get(nil, tableName); !found || nil != err { + errorResponse(w, errTableNotFound.Errorf(tableName)) + return + } + + // Check columns existence and access permissions + if _, _, _, err := sc.CheckAccess(tableName, form.Columns, client.EcosystemID); err != nil { + // if _, err := smart.GetColumns(form.Columns); err != nil { + errorResponse(w, errBannded.Errorf(err)) + return + } + + // Unmarshall where clause if there is any + var formWhere map[string]interface{} + cols, err := table.GetColumns(nil, tableName, "") + fmt.Printf("%+v %+v\n", cols, err) + + cols, err = table.GetColumns(nil, tableName, form.Columns) + fmt.Printf("%+v %+v\n", cols, err) + + if whereValue := r.FormValue("where"); 0 < len(whereValue) { + if err := json.Unmarshal([]byte(r.FormValue("where")), &formWhere); err != nil { + errorResponse(w, err, http.StatusBadRequest) + return + } + } + whereClause := types.LoadMap(formWhere) + + // Perform the actual request + _, ret, err := smart.DBSelect(&sc, tableName, form.Columns, form.ID, form.Order, form.Offset, form.Limit, whereClause) + if err != nil { + errorResponse(w, err) + return + } + + result := new(dbFindResult) + result.List = ret + jsonResponse(w, result) +} diff --git a/packages/api/dbfind_test.go b/packages/api/dbfind_test.go new file mode 100644 index 000000000..75fa693dc --- /dev/null +++ b/packages/api/dbfind_test.go @@ -0,0 +1,62 @@ +// Copyright (C) 2017, 2018, 2019 EGAAS S.A. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +package api + +import ( + "fmt" + "net/url" + "testing" +) + +func TestDbFind(t *testing.T) { + if err := keyLogin(1); err != nil { + t.Error(err) + return + } + var ret dbFindResult + + // Query table that is known to be existing + if err := sendPost("dbfind/keys", &url.Values{}, &ret); nil != err { + t.Error(err) + return + } + if length := len(ret.List); 0 == length { + t.Error(fmt.Errorf(`The number of records %d = 0`, length)) + return + } + + // Query table that doesn't exist + if err := sendPost("dbfind/QA_not_existing_table", &url.Values{}, &ret); nil != err { + if err.Error() != `404 {"error":"E_TABLENOTFOUND","msg":"Table qa_not_existing_table has not been found"}` { + t.Error(err) + return + } + } + + // Query table with specified columns + if err := sendPost("dbfind/keys", &url.Values{"Columns": {"id, account"}}, &ret); nil != err { + t.Error(err) + } + + // Query table with specified columns that are known to be missing + if err := sendPost("dbfind/keys", &url.Values{"Columns": {"id,account,id_non_existing"}}, &ret); nil != err { + if err.Error() != `400 {"error":"E_SERVER","msg":"column id_non_existing doesn't exist"}` { + t.Error(err) + return + } + } +} diff --git a/packages/api/route.go b/packages/api/route.go index acd6de62a..9e406a66c 100644 --- a/packages/api/route.go +++ b/packages/api/route.go @@ -69,6 +69,7 @@ func (m Mode) SetCommonRoutes(r Router) { api.HandleFunc("/interface/block/{name}", authRequire(getBlockInterfaceRowHandler)).Methods("GET") api.HandleFunc("/table/{name}", authRequire(getTableHandler)).Methods("GET") api.HandleFunc("/tables", authRequire(getTablesHandler)).Methods("GET") + api.HandleFunc("/dbfind/{table}", authRequire(getDbFindHandler)).Methods("POST") api.HandleFunc("/test/{name}", getTestHandler).Methods("GET", "POST") api.HandleFunc("/version", getVersionHandler).Methods("GET") api.HandleFunc("/config/{option}", getConfigOptionHandler).Methods("GET") From 7a2bbf50b869d01b8e982d6890b2cf54a920395b Mon Sep 17 00:00:00 2001 From: Frank Horrigan Date: Sun, 26 Jan 2020 02:57:22 +1000 Subject: [PATCH 3/5] Remove unused check --- packages/api/dbfind.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/api/dbfind.go b/packages/api/dbfind.go index 210497203..2b64a8b40 100644 --- a/packages/api/dbfind.go +++ b/packages/api/dbfind.go @@ -85,13 +85,6 @@ func getDbFindHandler(w http.ResponseWriter, r *http.Request) { return } - // Check columns existence and access permissions - if _, _, _, err := sc.CheckAccess(tableName, form.Columns, client.EcosystemID); err != nil { - // if _, err := smart.GetColumns(form.Columns); err != nil { - errorResponse(w, errBannded.Errorf(err)) - return - } - // Unmarshall where clause if there is any var formWhere map[string]interface{} cols, err := table.GetColumns(nil, tableName, "") From 023bc99ca993fc70fa28c61b21df79d67aa36712 Mon Sep 17 00:00:00 2001 From: Frank Horrigan Date: Sun, 26 Jan 2020 03:00:06 +1000 Subject: [PATCH 4/5] Remove debug stuff --- packages/api/dbfind.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/api/dbfind.go b/packages/api/dbfind.go index 2b64a8b40..5da49463c 100644 --- a/packages/api/dbfind.go +++ b/packages/api/dbfind.go @@ -18,7 +18,6 @@ package api import ( "encoding/json" - "fmt" "net/http" "strings" @@ -87,12 +86,6 @@ func getDbFindHandler(w http.ResponseWriter, r *http.Request) { // Unmarshall where clause if there is any var formWhere map[string]interface{} - cols, err := table.GetColumns(nil, tableName, "") - fmt.Printf("%+v %+v\n", cols, err) - - cols, err = table.GetColumns(nil, tableName, form.Columns) - fmt.Printf("%+v %+v\n", cols, err) - if whereValue := r.FormValue("where"); 0 < len(whereValue) { if err := json.Unmarshal([]byte(r.FormValue("where")), &formWhere); err != nil { errorResponse(w, err, http.StatusBadRequest) From 50045cb5dcd52388fe0de579c2086d130b33d821 Mon Sep 17 00:00:00 2001 From: Frank Horrigan Date: Sun, 26 Jan 2020 22:24:01 +1000 Subject: [PATCH 5/5] Fix dbfind result serialization, make keys lowercase --- packages/api/dbfind.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/dbfind.go b/packages/api/dbfind.go index 5da49463c..1d0f37e9f 100644 --- a/packages/api/dbfind.go +++ b/packages/api/dbfind.go @@ -31,7 +31,7 @@ import ( ) type dbFindResult struct { - List []interface{} + List []interface{} `json:"list"` } type dbfindForm struct {