Marco-Zheng opened a new issue #2100: URL: https://github.com/apache/apisix-dashboard/issues/2100
### Issue description It's not bug for that case, but i have a question for add new menu for apisix dashboard, i intend to add authority realm, then add role module under handler  secondly, i add role.NewHandler under `route.go` ``` factories := []handler.RegisterFactory{ route.NewHandler, ssl.NewHandler, ..., role.NewHandler, } ``` add below role relevant code under storehub.go ``` const ( HubKeyConsumer HubKey = "consumer" HubKeyRoute HubKey = "route" HubKeyService HubKey = "service" HubKeySsl HubKey = "ssl" HubKeyUpstream HubKey = "upstream" HubKeyScript HubKey = "script" HubKeyGlobalRule HubKey = "global_rule" HubKeyServerInfo HubKey = "server_info" HubKeyPluginConfig HubKey = "plugin_config" HubKeyRole HubKey = "role" ) var ( storeHub = map[HubKey]*GenericStore{} ) func InitStore(key HubKey, opt GenericStoreOption) error { hubsNeedCheck := map[HubKey]bool{ HubKeyConsumer: true, HubKeyRoute: true, HubKeySsl: true, HubKeyService: true, HubKeyUpstream: true, HubKeyGlobalRule: true, HubKeyRole: true, } .... } ``` but when i run main.go, the error occured ``` panic: no store with key: role goroutine 1 [running]: github.com/apisix/manager-api/internal/core/store.GetStore(0x1fdc57e, 0x4, 0x0) /Users/marco/Downloads/workspace/apisix-dashboard/api/internal/core/store/storehub.go:84 +0x1e5 github.com/apisix/manager-api/internal/handler/system/role.NewHandler(0x0, 0x0, 0x0, 0x0) /Users/marco/Downloads/workspace/apisix-dashboard/api/internal/handler/system/role/role.go:40 +0x4a github.com/apisix/manager-api/internal.SetUpRouter(0x0) /Users/marco/Downloads/workspace/apisix-dashboard/api/internal/route.go:86 +0x867 github.com/apisix/manager-api/cmd.manageAPI(0x0, 0x0) /Users/marco/Downloads/workspace/apisix-dashboard/api/cmd/root.go:133 +0x648 github.com/apisix/manager-api/cmd.glob..func1(0x25ed9a0, 0x262d5d0, 0x0, 0x0, 0x0, 0x0) /Users/marco/Downloads/workspace/apisix-dashboard/api/cmd/root.go:52 +0x2a github.com/spf13/cobra.(*Command).execute(0x25ed9a0, 0xc0000321d0, 0x0, 0x0, 0x0, 0x0) /Users/marco/go/pkg/mod/github.com/spf13/[email protected]/command.go:762 +0xb70 github.com/spf13/cobra.(*Command).ExecuteC(0x25ed9a0, 0x25ed9a0, 0x0, 0x0) /Users/marco/go/pkg/mod/github.com/spf13/[email protected]/command.go:852 +0x6d2 github.com/spf13/cobra.(*Command).Execute(0x25ed9a0, 0x0, 0x0) /Users/marco/go/pkg/mod/github.com/spf13/[email protected]/command.go:800 +0x3b github.com/apisix/manager-api/cmd.Execute() /Users/marco/Downloads/workspace/apisix-dashboard/api/cmd/root.go:80 +0x3f main.main() /Users/marco/Downloads/workspace/apisix-dashboard/api/main.go:24 +0x25 Process exiting with code: 0 ``` ### Expected behavior program can run successfully and expose `/apisix/admin/roles` interface ### How to Reproduce 1、add below code under handler ``` /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package role import ( "reflect" "strings" "time" "github.com/gin-gonic/gin" "github.com/shiningrush/droplet" "github.com/shiningrush/droplet/wrapper" wgin "github.com/shiningrush/droplet/wrapper/gin" "github.com/apisix/manager-api/internal/core/entity" "github.com/apisix/manager-api/internal/core/store" "github.com/apisix/manager-api/internal/handler" ) type Handler struct { roleStore store.Interface } func NewHandler() (handler.RouteRegister, error) { return &Handler{ roleStore: store.GetStore(store.HubKeyRole), }, nil } func (h *Handler) ApplyRoute(r *gin.Engine) { r.GET("/apisix/admin/roles/:role_name", wgin.Wraps(h.Get, wrapper.InputType(reflect.TypeOf(GetInput{})))) r.GET("/apisix/admin/roles", wgin.Wraps(h.List, wrapper.InputType(reflect.TypeOf(ListInput{})))) r.PUT("/apisix/admin/roles/:role_name", wgin.Wraps(h.Set, wrapper.InputType(reflect.TypeOf(SetInput{})))) r.PUT("/apisix/admin/roles", wgin.Wraps(h.Set, wrapper.InputType(reflect.TypeOf(SetInput{})))) r.DELETE("/apisix/admin/roles/:role_names", wgin.Wraps(h.BatchDelete, wrapper.InputType(reflect.TypeOf(BatchDeleteInput{})))) } type GetInput struct { RoleName string `auto_read:"role_name,path" validate:"required"` } func (h *Handler) Get(c droplet.Context) (interface{}, error) { input := c.Input().(*GetInput) r, err := h.roleStore.Get(c.Context(), input.RoleName) if err != nil { return handler.SpecCodeResponse(err), err } return r, nil } type ListInput struct { RoleName string `auto_read:"role_name,query"` store.Pagination } func (h *Handler) List(c droplet.Context) (interface{}, error) { input := c.Input().(*ListInput) ret, err := h.roleStore.List(c.Context(), store.ListInput{ Predicate: func(obj interface{}) bool { if input.RoleName != "" { return strings.Contains(obj.(*entity.Role).RoleName, input.RoleName) } return true }, Less: func(i, j interface{}) bool { iBase := i.(*entity.Role) jBase := j.(*entity.Role) if iBase.CreateTime != jBase.CreateTime { return iBase.CreateTime < jBase.CreateTime } if iBase.UpdateTime != jBase.UpdateTime { return iBase.UpdateTime < jBase.UpdateTime } return iBase.RoleName < jBase.RoleName }, PageSize: input.PageSize, PageNumber: input.PageNumber, }) if err != nil { return nil, err } return ret, nil } type SetInput struct { entity.Role RoleName string `auto_read:"role_name,path"` } func (h *Handler) Set(c droplet.Context) (interface{}, error) { input := c.Input().(*SetInput) if input.RoleName != "" { input.Role.RoleName = input.RoleName } // Because the ID of role has been removed, // `BaseInfo` is no longer embedded in role's struct, // So we need to maintain create_time and update_time separately for role savedRole, _ := h.roleStore.Get(c.Context(), input.Role.RoleName) input.Role.CreateTime = time.Now().Unix() input.Role.UpdateTime = time.Now().Unix() if savedRole != nil { input.Role.CreateTime = savedRole.(*entity.Role).CreateTime } ret, err := h.roleStore.Update(c.Context(), &input.Role, true) if err != nil { return handler.SpecCodeResponse(err), err } return ret, nil } type BatchDeleteInput struct { UserNames string `auto_read:"role_names,path"` } func (h *Handler) BatchDelete(c droplet.Context) (interface{}, error) { input := c.Input().(*BatchDeleteInput) if err := h.roleStore.BatchDelete(c.Context(), strings.Split(input.UserNames, ",")); err != nil { return handler.SpecCodeResponse(err), err } return nil, nil } ``` 2、 i add role.NewHandler under `route.go` 3、add below role relevant code under storehub.go ``` const ( HubKeyConsumer HubKey = "consumer" HubKeyRoute HubKey = "route" HubKeyService HubKey = "service" HubKeySsl HubKey = "ssl" HubKeyUpstream HubKey = "upstream" HubKeyScript HubKey = "script" HubKeyGlobalRule HubKey = "global_rule" HubKeyServerInfo HubKey = "server_info" HubKeyPluginConfig HubKey = "plugin_config" HubKeyRole HubKey = "role" ) var ( storeHub = map[HubKey]*GenericStore{} ) func InitStore(key HubKey, opt GenericStoreOption) error { hubsNeedCheck := map[HubKey]bool{ HubKeyConsumer: true, HubKeyRoute: true, HubKeySsl: true, HubKeyService: true, HubKeyUpstream: true, HubKeyGlobalRule: true, HubKeyRole: true, } .... } ``` ### Screenshots  ### Environment - apisix-dashboard version, if have: 2.7 ### Additional context _No response_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
