From 5637c65977e4f174dc247da7a1f8627dd326b551 Mon Sep 17 00:00:00 2001 From: liugq Date: Fri, 24 Feb 2023 19:32:10 +0800 Subject: [PATCH 1/3] add view layout api --- main.go | 1 + model/layout.go | 19 ++++ plugin/api/init.go | 2 + plugin/api/layout/api.go | 22 +++++ plugin/api/layout/layout.go | 176 ++++++++++++++++++++++++++++++++++++ 5 files changed, 220 insertions(+) create mode 100644 model/layout.go create mode 100644 plugin/api/layout/api.go create mode 100644 plugin/api/layout/layout.go diff --git a/main.go b/main.go index 88be737e..50b2be8a 100644 --- a/main.go +++ b/main.go @@ -133,6 +133,7 @@ func main() { orm.RegisterSchemaWithIndexName(insight.Dashboard{}, "dashboard") orm.RegisterSchemaWithIndexName(task1.Task{}, "task") orm.RegisterSchemaWithIndexName(task1.Log{}, "task-log") + orm.RegisterSchemaWithIndexName(model.Layout{}, "layout") api.RegisterSchema() if global.Env().SetupRequired() { diff --git a/model/layout.go b/model/layout.go new file mode 100644 index 00000000..75222f0c --- /dev/null +++ b/model/layout.go @@ -0,0 +1,19 @@ +/* Copyright © INFINI Ltd. All rights reserved. + * Web: https://infinilabs.com + * Email: hello#infini.ltd */ + +package model + +import "infini.sh/framework/core/orm" + +type Layout struct { + orm.ORMObjectBase + Name string `json:"name" elastic_mapping:"name: { type: text }"` + Description string `json:"description" elastic_mapping:"description: { type: text }"` + Creator struct { + Name string `json:"name"` + Id string `json:"id"` + } `json:"creator"` + ViewID string `json:"view_id" elastic_mapping:"view_id: { type: keyword }"` + Config interface{} `json:"config" elastic_mapping:"config: { type: object, enabled:false }"` +} \ No newline at end of file diff --git a/plugin/api/init.go b/plugin/api/init.go index aff72102..a6a897fd 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -6,6 +6,7 @@ import ( "infini.sh/console/plugin/api/gateway" "infini.sh/console/plugin/api/index_management" "infini.sh/console/plugin/api/insight" + "infini.sh/console/plugin/api/layout" "infini.sh/framework/core/api" "infini.sh/framework/core/api/rbac/enum" "path" @@ -66,4 +67,5 @@ func Init(cfg *config.AppConfig) { gateway.InitAPI() insight.InitAPI() + layout.InitAPI() } diff --git a/plugin/api/layout/api.go b/plugin/api/layout/api.go new file mode 100644 index 00000000..af6f0b40 --- /dev/null +++ b/plugin/api/layout/api.go @@ -0,0 +1,22 @@ +/* Copyright © INFINI Ltd. All rights reserved. + * Web: https://infinilabs.com + * Email: hello#infini.ltd */ + +package layout + +import ( + "infini.sh/framework/core/api" +) + +type LayoutAPI struct { + api.Handler +} + +func InitAPI() { + layoutAPI := LayoutAPI{} + api.HandleAPIMethod(api.GET, "/layout/:layout_id", layoutAPI.getLayout) + api.HandleAPIMethod(api.POST, "/layout", layoutAPI.RequireLogin(layoutAPI.createLayout)) + api.HandleAPIMethod(api.PUT, "/layout/:layout_id", layoutAPI.updateLayout) + api.HandleAPIMethod(api.DELETE, "/layout/:layout_id", layoutAPI.deleteLayout) + api.HandleAPIMethod(api.GET, "/layout/_search", layoutAPI.searchLayout) +} diff --git a/plugin/api/layout/layout.go b/plugin/api/layout/layout.go new file mode 100644 index 00000000..7703a3c8 --- /dev/null +++ b/plugin/api/layout/layout.go @@ -0,0 +1,176 @@ +/* Copyright © INFINI Ltd. All rights reserved. + * Web: https://infinilabs.com + * Email: hello#infini.ltd */ + +package layout + +import ( + "fmt" + log "github.com/cihub/seelog" + "infini.sh/console/model" + "infini.sh/framework/core/api/rbac" + httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/orm" + "infini.sh/framework/core/util" + "net/http" + "strconv" + "strings" +) + +func (h *LayoutAPI) createLayout(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + var obj = &model.Layout{} + err := h.DecodeJSON(req, obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + obj.ID = util.GetUUID() + user, err := rbac.FromUserContext(req.Context()) + if err != nil { + log.Error(err) + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + if user != nil { + obj.Creator.Name = user.Username + obj.Creator.Id = user.UserId + } + ctx := &orm.Context{ + Refresh: "wait_for", + } + err = orm.Create(ctx, obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + + h.WriteCreatedOKJSON(w, obj.ID) + +} + +func (h *LayoutAPI) getLayout(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("layout_id") + + obj := model.Layout{} + obj.ID = id + + exists, err := orm.Get(&obj) + if !exists || err != nil { + h.WriteJSON(w, util.MapStr{ + "_id": id, + "found": false, + }, http.StatusNotFound) + return + } + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + + h.WriteGetOKJSON(w, id, obj) +} + +func (h *LayoutAPI) updateLayout(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("layout_id") + oldLayout := model.Layout{} + + oldLayout.ID = id + exists, err := orm.Get(&oldLayout) + if !exists || err != nil { + h.WriteJSON(w, util.MapStr{ + "_id": id, + "result": "not_found", + }, http.StatusNotFound) + return + } + + create := oldLayout.Created + obj := model.Layout{} + err = h.DecodeJSON(req, &obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + + //protect + obj.ID = id + obj.Created = create + obj.Creator = oldLayout.Creator + ctx := &orm.Context{ + Refresh: "wait_for", + } + err = orm.Update(ctx, &obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + + h.WriteUpdatedOKJSON(w, obj.ID) +} + +func (h *LayoutAPI) deleteLayout(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("layout_id") + + obj := model.Layout{} + obj.ID = id + + exists, err := orm.Get(&obj) + if !exists || err != nil { + h.WriteJSON(w, util.MapStr{ + "_id": id, + "result": "not_found", + }, http.StatusNotFound) + return + } + + ctx := &orm.Context{ + Refresh: "wait_for", + } + err = orm.Delete(ctx, &obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + + h.WriteDeletedOKJSON(w, id) +} + +func (h *LayoutAPI) searchLayout(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + + var ( + keyword = h.GetParameterOrDefault(req, "keyword", "") + queryDSL = `{"query":{"bool":{"must":[%s]}}, "size": %d, "from": %d}` + strSize = h.GetParameterOrDefault(req, "size", "20") + strFrom = h.GetParameterOrDefault(req, "from", "0") + mustBuilder = &strings.Builder{} + ) + if keyword != "" { + mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) + } + size, _ := strconv.Atoi(strSize) + if size <= 0 { + size = 20 + } + from, _ := strconv.Atoi(strFrom) + if from < 0 { + from = 0 + } + + q := orm.Query{} + queryDSL = fmt.Sprintf(queryDSL, mustBuilder.String(), size, from) + q.RawQuery = []byte(queryDSL) + + err, res := orm.Search(&model.Layout{}, &q) + if err != nil { + log.Error(err) + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + h.Write(w, res.Raw) +} \ No newline at end of file From f1c18797b0db07ed04a0ccc46c1e69bdc72728ec Mon Sep 17 00:00:00 2001 From: liugq Date: Mon, 27 Feb 2023 18:04:07 +0800 Subject: [PATCH 2/3] add query arg view_id for layout search api --- plugin/api/layout/layout.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugin/api/layout/layout.go b/plugin/api/layout/layout.go index 7703a3c8..b2e27579 100644 --- a/plugin/api/layout/layout.go +++ b/plugin/api/layout/layout.go @@ -148,9 +148,16 @@ func (h *LayoutAPI) searchLayout(w http.ResponseWriter, req *http.Request, ps ht queryDSL = `{"query":{"bool":{"must":[%s]}}, "size": %d, "from": %d}` strSize = h.GetParameterOrDefault(req, "size", "20") strFrom = h.GetParameterOrDefault(req, "from", "0") + viewID = h.GetParameterOrDefault(req, "view_id", "") mustBuilder = &strings.Builder{} ) + if viewID != "" { + mustBuilder.WriteString(fmt.Sprintf(`{"term":{"view_id":{"value":"%s"}}}`, viewID)) + } if keyword != "" { + if mustBuilder.Len() > 0 { + mustBuilder.WriteString(",") + } mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) } size, _ := strconv.Atoi(strSize) From 662205c5408e8bff1520b1a0ece5e97fa86b5dd6 Mon Sep 17 00:00:00 2001 From: liugq Date: Tue, 28 Feb 2023 12:27:26 +0800 Subject: [PATCH 3/3] add layout api permission --- plugin/api/layout/api.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugin/api/layout/api.go b/plugin/api/layout/api.go index af6f0b40..1109f782 100644 --- a/plugin/api/layout/api.go +++ b/plugin/api/layout/api.go @@ -6,6 +6,7 @@ package layout import ( "infini.sh/framework/core/api" + "infini.sh/framework/core/api/rbac/enum" ) type LayoutAPI struct { @@ -14,9 +15,9 @@ type LayoutAPI struct { func InitAPI() { layoutAPI := LayoutAPI{} - api.HandleAPIMethod(api.GET, "/layout/:layout_id", layoutAPI.getLayout) - api.HandleAPIMethod(api.POST, "/layout", layoutAPI.RequireLogin(layoutAPI.createLayout)) - api.HandleAPIMethod(api.PUT, "/layout/:layout_id", layoutAPI.updateLayout) - api.HandleAPIMethod(api.DELETE, "/layout/:layout_id", layoutAPI.deleteLayout) - api.HandleAPIMethod(api.GET, "/layout/_search", layoutAPI.searchLayout) + api.HandleAPIMethod(api.GET, "/layout/:layout_id", layoutAPI.RequirePermission(layoutAPI.getLayout, enum.PermissionLayoutRead)) + api.HandleAPIMethod(api.POST, "/layout", layoutAPI.RequirePermission(layoutAPI.createLayout, enum.PermissionLayoutWrite)) + api.HandleAPIMethod(api.PUT, "/layout/:layout_id", layoutAPI.RequirePermission(layoutAPI.updateLayout, enum.PermissionLayoutWrite)) + api.HandleAPIMethod(api.DELETE, "/layout/:layout_id", layoutAPI.RequirePermission(layoutAPI.deleteLayout, enum.PermissionLayoutWrite)) + api.HandleAPIMethod(api.GET, "/layout/_search", layoutAPI.RequirePermission(layoutAPI.searchLayout, enum.PermissionLayoutRead)) }