diff --git a/api.go b/api.go index e4ab067..142871c 100644 --- a/api.go +++ b/api.go @@ -3,9 +3,15 @@ package moto import ( "git.nobla.cn/golang/kos" "git.nobla.cn/golang/kos/entry/http" - "git.nobla.cn/golang/moto/internal/user" - "git.nobla.cn/golang/moto/internal/user/passport" - "git.nobla.cn/golang/moto/internal/user/types" + "git.nobla.cn/golang/moto/common/db" + "git.nobla.cn/golang/moto/internal/organize" + "git.nobla.cn/golang/moto/internal/organize/passport" + "git.nobla.cn/golang/moto/internal/organize/types" + "git.nobla.cn/golang/moto/version" + "git.nobla.cn/golang/rest" + restTypes "git.nobla.cn/golang/rest/types" + "gorm.io/gorm" + "strconv" ) func (svr *Server) handleLogin(ctx *http.Context) (err error) { @@ -32,7 +38,7 @@ func (svr *Server) handleProfile(ctx *http.Context) (err error) { var ( profile *types.Profile ) - if profile, err = user.Profile(ctx.Context(), ctx.User().ID); err != nil { + if profile, err = organize.Profile(ctx.Context(), ctx.User().ID); err != nil { return ctx.Error(http.ErrTemporaryUnavailable, err.Error()) } return ctx.Success(profile) @@ -42,12 +48,85 @@ func (svr *Server) handleGetConfigure(ctx *http.Context) (err error) { return ctx.Success(map[string]string{}) } +func (svr *Server) handleListSchema(ctx *http.Context) (err error) { + var ( + schemas []*restTypes.Schema + ) + scenario := ctx.Query("scenario") + if scenario == "" { + schemas, err = rest.GetSchemas( + ctx.Request().Context(), + db.WithContext(ctx.Request().Context()), + ctx.User().Get("domain"), + version.ProductName, + ctx.Param("table"), + ) + } else { + schemas, err = rest.VisibleSchemas( + ctx.Request().Context(), + db.WithContext(ctx.Request().Context()), + ctx.User().Get("domain"), + version.ProductName, + ctx.Param("table"), + scenario, + ) + } + if err != nil { + return ctx.Error(http.ErrResourceNotFound, err.Error()) + } else { + return ctx.Success(schemas) + } +} + +func (svr *Server) handleSaveSchema(ctx *http.Context) (err error) { + schemas := make([]*restTypes.Schema, 0) + if err = ctx.Bind(&schemas); err != nil { + return ctx.Error(http.ErrInvalidPayload, err.Error()) + } + domainName := ctx.User().Get("domain") + for i, _ := range schemas { + schemas[i].Domain = domainName + } + if err = db.WithContext(ctx.Request().Context()).Transaction(func(tx *gorm.DB) (errTx error) { + for _, scm := range schemas { + if errTx = tx.Save(scm).Error; errTx != nil { + return + } + } + return + }); err == nil { + return ctx.Success(map[string]interface{}{ + "count": len(schemas), + "state": "success", + }) + } else { + return ctx.Error(http.ErrTemporaryUnavailable, err.Error()) + } +} + +func (svr *Server) handleDeleteSchema(ctx *http.Context) (err error) { + id, _ := strconv.Atoi(ctx.Param("id")) + model := &restTypes.Schema{Id: uint64(id)} + if err = db.WithContext(ctx.Request().Context()).Delete(model).Error; err == nil { + return ctx.Success(map[string]any{ + "id": id, + }) + } else { + return ctx.Error(http.ErrResourceDelete, err.Error()) + } +} + func (svr *Server) routes() { - kos.Http().Use(user.AuthMiddleware) - user.AllowUri("/passport/login") + kos.Http().Use(organize.AuthMiddleware) + organize.AllowUri("/passport/login") kos.Http().Handle(http.MethodPost, "/passport/login", svr.handleLogin) kos.Http().Handle(http.MethodDelete, "/passport/logout", svr.handleLogout) kos.Http().Handle(http.MethodGet, "/user/profile", svr.handleProfile) kos.Http().Handle(http.MethodGet, "/user/configures", svr.handleGetConfigure) + + kos.Http().Handle(http.MethodGet, "/rest/schema/:module/:table", svr.handleListSchema) + kos.Http().Handle(http.MethodPut, "/rest/schema/:module/:table", svr.handleSaveSchema) + kos.Http().Handle(http.MethodDelete, "/rest/schema/:id", svr.handleDeleteSchema) + } diff --git a/common/db/db.go b/common/db/db.go index bb1a67e..ff4f949 100644 --- a/common/db/db.go +++ b/common/db/db.go @@ -5,8 +5,10 @@ import ( "git.nobla.cn/golang/moto/config" "git.nobla.cn/golang/rest/types" "github.com/go-sql-driver/mysql" + lru "github.com/hashicorp/golang-lru/v2" mysqlDriver "gorm.io/driver/mysql" "gorm.io/gorm" + "reflect" "time" ) @@ -14,6 +16,73 @@ var ( db *gorm.DB ) +var ( + cacheInstance, _ = lru.New[string, *cacheEntry](64) +) + +func WithDepend(s string, args ...any) CacheOption { + return func(o *CacheOptions) { + o.dependSQL = s + o.dependArgs = args + } +} + +func TryCache(ctx context.Context, key string, f CachingFunc, cbs ...CacheOption) (value any, err error) { + var ( + ok bool + hasDependValue bool + dependValue any + ) + opts := &CacheOptions{} + for _, cb := range cbs { + cb(opts) + } + //从缓存加载数据 + if value, ok = cacheInstance.Get(key); ok { + entry := value.(*cacheEntry) + if opts.dependSQL == "" { + return entry.storeValue, nil + } + //如果频繁访问,不检查依赖 + if time.Since(entry.lastChecked) < time.Millisecond*500 { + return entry.storeValue, nil + } + //对比依赖值 + if err = WithContext(ctx).Raw(opts.dependSQL, opts.dependArgs...).Scan(&dependValue).Error; err == nil { + hasDependValue = true + if reflect.DeepEqual(entry.compareValue, dependValue) { + entry.lastChecked = time.Now() + return entry.storeValue, nil + } else { + cacheInstance.Remove(key) + } + } + } + //从数据库加载数据 + if value, err = f(WithContext(ctx)); err == nil { + if !hasDependValue { + if err = WithContext(ctx).Raw(opts.dependSQL, opts.dependArgs...).Scan(&dependValue).Error; err == nil { + cacheInstance.Add(key, &cacheEntry{ + compareValue: dependValue, + storeValue: value, + createdAt: time.Now(), + lastChecked: time.Now(), + }) + } + } else { + cacheInstance.Add(key, &cacheEntry{ + compareValue: dependValue, + storeValue: value, + createdAt: time.Now(), + lastChecked: time.Now(), + }) + } + return value, nil + } else { + return nil, err + } +} + func Init(ctx context.Context, cfg config.Database, plugins ...gorm.Plugin) (err error) { dbCfg := &mysql.Config{ Net: "tcp", diff --git a/common/db/types.go b/common/db/types.go new file mode 100644 index 0000000..f5231f5 --- /dev/null +++ b/common/db/types.go @@ -0,0 +1,24 @@ +package db + +import ( + "gorm.io/gorm" + "time" +) + +type ( + CachingFunc func(tx *gorm.DB) (any, error) + + CacheOptions struct { + dependSQL string + dependArgs []any + } + + CacheOption func(o *CacheOptions) + + cacheEntry struct { + storeValue any + compareValue any + createdAt time.Time + lastChecked time.Time + } +) diff --git a/go.mod b/go.mod index fee40a1..0e3ac32 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,10 @@ go 1.22.9 require ( git.nobla.cn/golang/kos v0.1.32 - git.nobla.cn/golang/rest v0.0.1 + git.nobla.cn/golang/rest v0.0.2 github.com/go-sql-driver/mysql v1.8.1 github.com/google/uuid v1.6.0 + github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/mssola/useragent v1.0.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.7 @@ -15,14 +16,21 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-runewidth v0.0.3 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/peterh/liner v1.2.2 // indirect + github.com/rs/xid v1.6.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 455679e..29a8f46 100644 --- a/go.sum +++ b/go.sum @@ -2,16 +2,28 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.nobla.cn/golang/kos v0.1.32 h1:sFVCA7vKc8dPUd0cxzwExOSPX2mmMh2IuwL6cYS1pBc= git.nobla.cn/golang/kos v0.1.32/go.mod h1:35Z070+5oB39WcVrh5DDlnVeftL/Ccmscw2MZFe9fUg= -git.nobla.cn/golang/rest v0.0.1 h1:atEF73F7NuzYGWzO4+H2qHwgtwV+omG1paEj1DJ5RN8= -git.nobla.cn/golang/rest v0.0.1/go.mod h1:tGDOul2GGJtxk6fAeu+YLpMt/Up/TsBonTkygymN/wE= +git.nobla.cn/golang/rest v0.0.2 h1:b5hmGuVb1zXFQ8O2AYCi8628JGftgH2TL5BLftCN1OU= +git.nobla.cn/golang/rest v0.0.2/go.mod h1:tGDOul2GGJtxk6fAeu+YLpMt/Up/TsBonTkygymN/wE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -20,6 +32,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mssola/useragent v1.0.0 h1:WRlDpXyxHDNfvZaPEut5Biveq86Ze4o4EMffyMxmH5o= @@ -32,10 +46,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/organize/department.go b/internal/organize/department.go new file mode 100644 index 0000000..37c269e --- /dev/null +++ b/internal/organize/department.go @@ -0,0 +1,112 @@ +package organize + +import ( + "context" + "fmt" + "git.nobla.cn/golang/moto/common/db" + "git.nobla.cn/golang/moto/models" + "git.nobla.cn/golang/rest/types" + "gorm.io/gorm" + "strings" +) + +func RecursiveDepartment(ctx context.Context, parent string, level int, departments []*models.Department) []*types.TypeValue { + var ( + child []*types.TypeValue + ) + values := make([]*types.TypeValue, 0) + for _, dept := range departments { + if dept.Parent == parent { + values = append(values, &types.TypeValue{ + Label: "|-" + strings.Repeat("--", level) + dept.Name, + Value: dept.ID, + }) + child = RecursiveDepartment(ctx, dept.ID, level+1, departments) + if len(child) > 0 { + for _, row := range child { + values = append(values, row) + } + } + } + } + return values +} + +func RecursiveNestedDepartment(ctx context.Context, parent string, level int, departments []*models.Department) []*types.NestedValue { + values := make([]*types.NestedValue, 0) + for _, dept := range departments { + if dept.Parent == parent { + v := &types.NestedValue{ + Label: dept.Name, + Value: dept.ID, + Children: RecursiveNestedDepartment(ctx, dept.ID, level+1, departments), + } + values = append(values, v) + } + } + return values +} + +func DepartmentUserNested(ctx context.Context, domainName string) []*types.NestedValue { + var ( + err error + value any + users []*models.User + departments []*models.Department + ) + + if value, err = db.TryCache(ctx, fmt.Sprintf("domain:%s:departments", domainName), func(tx *gorm.DB) (any, error) { + departments = make([]*models.Department, 0) + err = tx.Where("domain=?", domainName).Order("created_at ASC").Find(&departments).Error + return departments, err + }, db.WithDepend("SELECT max(`updated_at`) FROM `departments` WHERE `domain`=?", domainName)); err == nil { + departments = value.([]*models.Department) + } else { + return nil + } + + if value, err = db.TryCache(ctx, fmt.Sprintf("domain:%s:users", domainName), func(tx *gorm.DB) (any, error) { + users = make([]*models.User, 0) + err = tx.Where("domain=?", domainName).Order("uid ASC").Find(&users).Error + return users, err + }, db.WithDepend("SELECT max(`updated_at`) FROM `users` WHERE `domain`=?", domainName)); err == nil { + users = value.([]*models.User) + } else { + return nil + } + + depts := RecursiveDepartment(ctx, "", 0, departments) + values := make([]*types.NestedValue, 0) + for _, dept := range depts { + v := &types.NestedValue{ + Label: dept.Label, + Value: dept.Value, + Children: make([]*types.NestedValue, 0), + } + for _, user := range users { + if user.Department == v.Value { + v.Children = append(v.Children, &types.NestedValue{ + Label: fmt.Sprintf("%s(%s)", user.Username, user.UID), + Value: user.UID, + }) + } + } + values = append(values, v) + } + return values +} + +func DepartmentTypes(ctx context.Context, domainName string) []*types.TypeValue { + result, err := db.TryCache(ctx, fmt.Sprintf("domain:%s:department:types", domainName), func(tx *gorm.DB) (any, error) { + values := make([]*models.Department, 0) + if err := db.WithContext(ctx).Where("domain=?", domainName).Find(&values).Error; err == nil { + return RecursiveDepartment(ctx, "", 0, values), nil + } else { + return nil, err + } + }, db.WithDepend("SELECT max(`updated_at`) FROM `departments` WHERE `domain`=?", domainName)) + if err == nil { + return result.([]*types.TypeValue) + } + return nil +} diff --git a/internal/user/middleware.go b/internal/organize/middleware.go similarity index 92% rename from internal/user/middleware.go rename to internal/organize/middleware.go index 8a54389..49b3c24 100644 --- a/internal/user/middleware.go +++ b/internal/organize/middleware.go @@ -1,9 +1,9 @@ -package user +package organize import ( "git.nobla.cn/golang/kos/entry/http" - "git.nobla.cn/golang/moto/internal/user/passport" - "git.nobla.cn/golang/moto/internal/user/types" + "git.nobla.cn/golang/moto/internal/organize/passport" + "git.nobla.cn/golang/moto/internal/organize/types" "os" "strings" ) diff --git a/internal/user/passport/login.go b/internal/organize/passport/login.go similarity index 97% rename from internal/user/passport/login.go rename to internal/organize/passport/login.go index fd0277a..1f22b40 100644 --- a/internal/user/passport/login.go +++ b/internal/organize/passport/login.go @@ -5,7 +5,7 @@ import ( "fmt" "git.nobla.cn/golang/kos/pkg/cache" "git.nobla.cn/golang/moto/common/db" - "git.nobla.cn/golang/moto/internal/user/types" + "git.nobla.cn/golang/moto/internal/organize/types" "git.nobla.cn/golang/moto/models" "github.com/mssola/useragent" "strings" diff --git a/internal/user/passport/types.go b/internal/organize/passport/types.go similarity index 100% rename from internal/user/passport/types.go rename to internal/organize/passport/types.go diff --git a/internal/user/passport/utils.go b/internal/organize/passport/utils.go similarity index 100% rename from internal/user/passport/utils.go rename to internal/organize/passport/utils.go diff --git a/internal/user/profile.go b/internal/organize/profile.go similarity index 86% rename from internal/user/profile.go rename to internal/organize/profile.go index e7ad564..cb1783e 100644 --- a/internal/user/profile.go +++ b/internal/organize/profile.go @@ -1,9 +1,9 @@ -package user +package organize import ( "context" "git.nobla.cn/golang/moto/common/db" - "git.nobla.cn/golang/moto/internal/user/types" + "git.nobla.cn/golang/moto/internal/organize/types" ) func Profile(ctx context.Context, uid string) (profile *types.Profile, err error) { diff --git a/internal/organize/role.go b/internal/organize/role.go new file mode 100644 index 0000000..a10b022 --- /dev/null +++ b/internal/organize/role.go @@ -0,0 +1,21 @@ +package organize + +import ( + "context" + "fmt" + "git.nobla.cn/golang/moto/common/db" + "git.nobla.cn/golang/moto/models" + "git.nobla.cn/golang/rest" + "git.nobla.cn/golang/rest/types" + "gorm.io/gorm" +) + +func RoleTypes(ctx context.Context, domainName string) []*types.TypeValue { + result, err := db.TryCache(ctx, fmt.Sprintf("domain:%s:role:types", domainName), func(tx *gorm.DB) (any, error) { + return rest.ModelTypes(ctx, tx, &models.Role{}, domainName, "name", "id"), nil + }, db.WithDepend("SELECT max(`updated_at`) FROM `roles` WHERE `domain`=?", domainName)) + if err == nil { + return result.([]*types.TypeValue) + } + return nil +} diff --git a/internal/user/types/profile.go b/internal/organize/types/profile.go similarity index 100% rename from internal/user/types/profile.go rename to internal/organize/types/profile.go diff --git a/internal/user/types/tokenize.go b/internal/organize/types/tokenize.go similarity index 100% rename from internal/user/types/tokenize.go rename to internal/organize/types/tokenize.go diff --git a/internal/organize/user.go b/internal/organize/user.go new file mode 100644 index 0000000..b2b3533 --- /dev/null +++ b/internal/organize/user.go @@ -0,0 +1,32 @@ +package organize + +import ( + "context" + "fmt" + "git.nobla.cn/golang/moto/common/db" + "git.nobla.cn/golang/moto/models" + "git.nobla.cn/golang/rest/types" + "gorm.io/gorm" +) + +func UserTypes(ctx context.Context, domainName string) []*types.TypeValue { + result, err := db.TryCache(ctx, fmt.Sprintf("domain:%s:user:types", domainName), func(tx *gorm.DB) (any, error) { + values := make([]*models.User, 0) + err := tx.Where("domain=?", domainName).Order("uid ASC").Find(&values).Error + if err != nil { + return nil, err + } + data := make([]*types.TypeValue, 0, len(values)) + for _, row := range values { + data = append(data, &types.TypeValue{ + Label: fmt.Sprintf("%s(%s)", row.Username, row.UID), + Value: row.UID, + }) + } + return data, nil + }, db.WithDepend("SELECT max(`updated_at`) FROM `users` WHERE `domain`=?", domainName)) + if err == nil { + return result.([]*types.TypeValue) + } + return nil +} diff --git a/server.go b/server.go index d6fa461..72595db 100644 --- a/server.go +++ b/server.go @@ -7,8 +7,9 @@ import ( "git.nobla.cn/golang/moto/common/db" "git.nobla.cn/golang/moto/config" "git.nobla.cn/golang/moto/models" - "git.nobla.cn/golang/moto/version" "git.nobla.cn/golang/rest" + "git.nobla.cn/golang/rest/plugins/identity" + "git.nobla.cn/golang/rest/plugins/validate" "io" "net/http" ) @@ -20,7 +21,7 @@ type Server struct { } func (svr *Server) prepare() (err error) { - if err = db.Init(svr.ctx, svr.cfg.Database); err != nil { + if err = db.Init(svr.ctx, svr.cfg.Database, identity.New(), validate.New()); err != nil { return } values := []any{ @@ -29,15 +30,15 @@ func (svr *Server) prepare() (err error) { &models.Login{}, &models.Department{}, } + rest.SetHttpRouter(svr) for _, item := range values { if err = db.DB().AutoMigrate(item); err != nil { return } - if err = rest.AutoMigrate(svr.ctx, db.DB(), item, rest.WithoutDomain(), rest.WithModuleName(version.ProductName)); err != nil { + if err = rest.AutoMigrate(svr.ctx, db.DB(), item, rest.WithoutDomain(), rest.WithModuleName("rest")); err != nil { return } } - rest.SetHttpRouter(svr) return } diff --git a/web/src/components/fragment/Skeleton.vue b/web/src/components/fragment/Skeleton.vue index ac00181..4d672f3 100644 --- a/web/src/components/fragment/Skeleton.vue +++ b/web/src/components/fragment/Skeleton.vue @@ -17,6 +17,9 @@ const props = defineProps({ }, tableName: { type: String, + }, + apiPrefix: { + type: String, } }) @@ -27,7 +30,7 @@ const loading = ref(false) const crud = ref(new CRUD({ moduleName: props.moduleName, tableName: props.tableName, - apiPrefix: '' + apiPrefix: props.apiPrefix })) onMounted(() => { diff --git a/web/src/components/fragment/Viewer.vue b/web/src/components/fragment/Viewer.vue index a913d58..10502ec 100644 --- a/web/src/components/fragment/Viewer.vue +++ b/web/src/components/fragment/Viewer.vue @@ -25,8 +25,8 @@