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..1109f782 --- /dev/null +++ b/plugin/api/layout/api.go @@ -0,0 +1,23 @@ +/* Copyright © INFINI Ltd. All rights reserved. + * Web: https://infinilabs.com + * Email: hello#infini.ltd */ + +package layout + +import ( + "infini.sh/framework/core/api" + "infini.sh/framework/core/api/rbac/enum" +) + +type LayoutAPI struct { + api.Handler +} + +func InitAPI() { + layoutAPI := LayoutAPI{} + 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)) +} diff --git a/plugin/api/layout/layout.go b/plugin/api/layout/layout.go new file mode 100644 index 00000000..b2e27579 --- /dev/null +++ b/plugin/api/layout/layout.go @@ -0,0 +1,183 @@ +/* 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") + 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) + 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