This commit is contained in:
Yvan
2026-08-17 15:23:57 +08:00
parent 05b49cd86a
commit 083cc3a9ea
24 changed files with 639 additions and 287 deletions
+15 -18
View File
@@ -18,20 +18,14 @@ func NewAPIService(uc *biz.APIUsecase, settings biz.RuntimeSettings) *APIService
}
func (s *APIService) NormalizeRoutePath(path string) string {
routerPrefix := s.settings.RouterPrefix()
if routerPrefix == "" {
if s.settings == nil {
return path
}
prefix := strings.TrimSuffix(routerPrefix, "/")
normalized := strings.TrimPrefix(path, prefix)
if normalized == "" {
return "/"
}
return normalized
return NormalizeRoutePath(path, s.settings.RouterPrefix())
}
func apiDomain(value *dto.APIRequest) *biz.API {
return &biz.API{ID: value.ID, Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
func (s *APIService) apiDomain(value *dto.APIRequest) *biz.API {
return &biz.API{ID: value.ID, Path: s.NormalizeRoutePath(value.Path), Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}
}
func apiResponse(value *biz.API) *dto.APIResponse {
@@ -87,14 +81,14 @@ func (s *APIService) Groups(ctx context.Context) ([]string, map[string]string, e
}
func (s *APIService) CreateAPIRequest(ctx context.Context, req *dto.APIRequest) (*dto.APIResponse, error) {
value := apiDomain(req)
value := s.apiDomain(req)
if err := s.uc.CreateAPI(ctx, value); err != nil {
return nil, err
}
return apiResponse(value), nil
}
func (s *APIService) UpdateAPIRequest(ctx context.Context, req *dto.APIRequest) error {
return s.uc.UpdateAPI(ctx, apiDomain(req))
return s.uc.UpdateAPI(ctx, s.apiDomain(req))
}
func (s *APIService) FindAPIResponse(ctx context.Context, id uint) (*dto.APIResponse, error) {
value, err := s.uc.FindAPI(ctx, id)
@@ -107,10 +101,10 @@ func (s *APIService) ApplyAPISyncRequest(ctx context.Context, req *dto.ApplyAPIS
added := make([]*biz.API, 0, len(req.NewAPIs))
deleted := make([]*biz.API, 0, len(req.DeleteAPIs))
for i := range req.NewAPIs {
added = append(added, apiDomain(&req.NewAPIs[i]))
added = append(added, s.apiDomain(&req.NewAPIs[i]))
}
for i := range req.DeleteAPIs {
deleted = append(deleted, apiDomain(&req.DeleteAPIs[i]))
deleted = append(deleted, s.apiDomain(&req.DeleteAPIs[i]))
}
return s.uc.ApplyAPISync(ctx, added, deleted)
}
@@ -142,7 +136,7 @@ func (s *APIService) SyncAPIResponses(ctx context.Context, routes []dto.APIReque
// The compatible sync endpoint compares Gin's route table directly, so newly
// discovered routes carry only path and method. Group/description are
// intentionally left empty for the operator to fill in the sync dialog.
items = append(items, apiDomain(&routes[i]))
items = append(items, s.apiDomain(&routes[i]))
}
return s.SyncAPIs(ctx, items)
}
@@ -154,10 +148,13 @@ func (s *APIService) DeleteAPI(ctx context.Context, id uint) error {
return s.uc.DeleteAPI(ctx, id)
}
func (s *APIService) APIRoleIDs(ctx context.Context, path, method string) ([]uint, error) {
return s.uc.APIRoleIDs(ctx, path, method)
return s.uc.APIRoleIDs(ctx, s.NormalizeRoutePath(path), method)
}
func (s *APIService) SetAPIRoles(ctx context.Context, path, method string, ids []uint) error {
return s.uc.SetAPIRoles(ctx, path, method, ids)
return s.uc.SetAPIRoles(ctx, s.NormalizeRoutePath(path), method, ids)
}
func (s *APIService) FreshCasbin(ctx context.Context) error {
return s.uc.FreshCasbin(ctx)
}
func (s *APIService) SyncAPIs(ctx context.Context, routes []*biz.API) (*dto.APISyncResponse, error) {
diff, err := s.uc.SyncAPIs(ctx, routes)
@@ -167,5 +164,5 @@ func (s *APIService) SyncAPIs(ctx context.Context, routes []*biz.API) (*dto.APIS
return &dto.APISyncResponse{NewAPIs: apiResponses(diff.Added), DeleteAPIs: apiResponses(diff.Deleted), IgnoreAPIs: apiResponses(diff.Ignored)}, nil
}
func (s *APIService) SetAPIIgnored(ctx context.Context, path, method string, ignored bool) error {
return s.uc.SetAPIIgnored(ctx, path, method, ignored)
return s.uc.SetAPIIgnored(ctx, s.NormalizeRoutePath(path), method, ignored)
}
+19
View File
@@ -0,0 +1,19 @@
package service
import "strings"
// NormalizeRoutePath removes only a complete configured router prefix. Paths
// such as /administrator must not be shortened when the prefix is /admin.
func NormalizeRoutePath(path, routerPrefix string) string {
prefix := strings.TrimSuffix(strings.TrimSpace(routerPrefix), "/")
if prefix == "" || prefix == "/" {
return path
}
if path == prefix {
return "/"
}
if strings.HasPrefix(path, prefix+"/") {
return strings.TrimPrefix(path, prefix)
}
return path
}
+26
View File
@@ -0,0 +1,26 @@
package service
import "testing"
func TestNormalizeRoutePath(t *testing.T) {
tests := []struct {
name string
path string
prefix string
want string
}{
{name: "empty prefix", path: "/api/login", prefix: "", want: "/api/login"},
{name: "configured prefix", path: "/admin/api/login", prefix: "/admin", want: "/api/login"},
{name: "trailing slash prefix", path: "/admin/api/login", prefix: "/admin/", want: "/api/login"},
{name: "prefix root", path: "/admin", prefix: "/admin", want: "/"},
{name: "prefix boundary", path: "/administrator/api/login", prefix: "/admin", want: "/administrator/api/login"},
{name: "already normalized", path: "/api/login", prefix: "/admin", want: "/api/login"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NormalizeRoutePath(tt.path, tt.prefix); got != tt.want {
t.Fatalf("NormalizeRoutePath(%q, %q) = %q, want %q", tt.path, tt.prefix, got, tt.want)
}
})
}
}
+1 -8
View File
@@ -2,7 +2,6 @@ package service
import (
"context"
"strings"
"kra/internal/biz"
"kra/internal/routeinfo"
@@ -29,13 +28,7 @@ func (s *SystemConfigService) Initialize(ctx context.Context, input *dto.Databas
func (s *SystemConfigService) InitializeRoutes(ctx context.Context, input *dto.DatabaseInitRequest, routes []dto.Route) error {
apis := make([]*biz.API, 0, len(routes))
for _, route := range routes {
path := route.Path
if routerPrefix := s.settings.RouterPrefix(); routerPrefix != "" {
path = strings.TrimPrefix(path, strings.TrimSuffix(routerPrefix, "/"))
if path == "" {
path = "/"
}
}
path := NormalizeRoutePath(route.Path, s.settings.RouterPrefix())
group, description := routeinfo.Metadata(route.Method, path)
apis = append(apis, &biz.API{Path: path, Method: route.Method, APIGroup: group, Description: description})
}