补充应用CRUD测试

This commit is contained in:
yumaojun03 2025-06-22 16:29:42 +08:00
parent f018f28390
commit c1f263ab84
8 changed files with 119 additions and 36 deletions

View File

@ -11,7 +11,7 @@
database = "devcloud_go18"
username = "root"
password = "123456"
auto_migrate = true
auto_migrate = false
debug = true
[mongo]

View File

@ -1,18 +1,17 @@
package policy
import (
"encoding/json"
"fmt"
"time"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/role"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/user"
"github.com/infraboard/mcube/v2/ioc/config/datasource"
"github.com/infraboard/mcube/v2/ioc/config/validator"
"github.com/infraboard/mcube/v2/tools/pretty"
"github.com/infraboard/modules/iam/apps"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func NewPolicy() *Policy {
@ -82,10 +81,11 @@ type ResourceScope struct {
Scope map[string][]string `json:"scope" bson:"scope" gorm:"column:scope;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
}
// 辅助函数:将字符串切片转换为 JSON 数组字符串
func toJsonArray(arr []string) string {
b, _ := json.Marshal(arr)
return string(b)
func (l *ResourceScope) SetScope(key string, value []string) {
if l.Scope == nil {
l.Scope = map[string][]string{}
}
l.Scope[key] = value
}
func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
@ -93,23 +93,27 @@ func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
query = query.Where("namespace = ?", r.NamespaceId)
}
switch datasource.Get().Provider {
case datasource.PROVIDER_POSTGRES:
for key, values := range r.Scope {
for k, v := range r.Scope {
// 创建一个临时 JSON 对象 {"key": ["value1", "value2"]}
jsonCondition := fmt.Sprintf(`{"%s": %s}`, k, toJsonArray(v))
query = query.Where("label @> ?", jsonCondition)
}
query = query.Where("label -->>? IN ?", key, values)
for key, values := range r.Scope {
if len(values) == 0 {
continue
}
case datasource.PROVIDER_MYSQL:
// 过滤条件, Label
for key, values := range r.Scope {
query = query.Where("label->>? IN (?)", "$."+key, values)
}
}
// 构建"标签不存在"条件
notHasKey := clause.Not(datatypes.JSONQuery("label").HasKey(key))
// 构建"标签值匹配"条件
var valueMatches []clause.Expression
for _, val := range values {
valueMatches = append(valueMatches,
datatypes.JSONQuery("label").Equals(val, key))
}
// 组合条件:标签不存在 OR 标签值匹配
query = query.Where(clause.Or(
notHasKey,
clause.Or(valueMatches...),
))
}
return query
}
@ -128,3 +132,10 @@ type ResourceLabel struct {
// 访问范围, 需要提前定义scope, 比如环境, 后端开发小组,开发资源
Label map[string]string `json:"label" bson:"label" gorm:"column:label;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
}
func (l *ResourceLabel) SetLabel(key, value string) {
if l.Label == nil {
l.Label = map[string]string{}
}
l.Label[key] = value
}

View File

@ -1,3 +1,9 @@
# 应用管理
应用的核心是代码, 围绕这应用的核心代码, SCM的仓库地址管理
应用的核心是代码, 围绕这应用的核心代码, SCM的仓库地址管理
## 应用CRUD
最麻烦的基于标签的动态匹配(核心权限)

View File

@ -4,8 +4,10 @@ import (
"context"
"122.51.31.227/go-course/go18/devcloud/mpaas/apps/application"
"github.com/infraboard/mcube/v2/exception"
"github.com/infraboard/mcube/v2/ioc/config/datasource"
"github.com/infraboard/mcube/v2/types"
"gorm.io/gorm"
)
// CreateApplication implements application.Service.
@ -27,7 +29,7 @@ func (i *ApplicationServiceImpl) CreateApplication(ctx context.Context, in *appl
func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *application.QueryApplicationRequest) (*types.Set[*application.Application], error) {
set := types.New[*application.Application]()
query := datasource.DBFromCtx(ctx).Model(&application.Application{})
query := in.GormResourceFilter(datasource.DBFromCtx(ctx).Model(&application.Application{}))
if in.Id != "" {
query = query.Where("id = ?", in.Id)
}
@ -64,16 +66,40 @@ func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *appli
}
// DescribeApplication implements application.Service.
func (i *ApplicationServiceImpl) DescribeApplication(context.Context, *application.DescribeApplicationRequest) (*application.Application, error) {
panic("unimplemented")
func (i *ApplicationServiceImpl) DescribeApplication(ctx context.Context, in *application.DescribeApplicationRequest) (*application.Application, error) {
query := in.GormResourceFilter(datasource.DBFromCtx(ctx).Model(&application.Application{}))
ins := &application.Application{}
if err := query.Where("id = ?", in.Id).First(ins).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, exception.NewNotFound("app %s not found", in.Id)
}
return nil, err
}
return ins, nil
}
// UpdateApplication implements application.Service.
func (i *ApplicationServiceImpl) UpdateApplication(context.Context, *application.UpdateApplicationRequest) (*application.Application, error) {
panic("unimplemented")
func (i *ApplicationServiceImpl) UpdateApplication(ctx context.Context, in *application.UpdateApplicationRequest) (*application.Application, error) {
ins, err := i.DescribeApplication(ctx, &in.DescribeApplicationRequest)
if err != nil {
return nil, err
}
ins.CreateApplicationSpec = in.CreateApplicationSpec
return ins, datasource.DBFromCtx(ctx).Where("id = ?", in.Id).Updates(ins).Error
}
// DeleteApplication implements application.Service.
func (i *ApplicationServiceImpl) DeleteApplication(context.Context, *application.DeleteApplicationRequest) (*application.Application, error) {
panic("unimplemented")
func (i *ApplicationServiceImpl) DeleteApplication(ctx context.Context, in *application.DeleteApplicationRequest) (*application.Application, error) {
ins, err := i.DescribeApplication(ctx, &in.DescribeApplicationRequest)
if err != nil {
return nil, err
}
return ins, datasource.DBFromCtx(ctx).
Where("id = ?", in.Id).
Delete(&application.Application{}).
Error
}

View File

@ -14,9 +14,22 @@ func TestCreateApplication(t *testing.T) {
req.CodeRepository = application.CodeRepository{
SshUrl: "git@122.51.31.227:go-course/go18.git",
}
req.SetLabel("team", "golang_dev_group_01")
ins, err := svc.CreateApplication(ctx, req)
if err != nil {
t.Fatal(err)
}
t.Log(ins)
}
// SELECT * FROM `applications` WHERE (NOT JSON_EXTRACT(`label`,'$.team') IS NOT NULL OR JSON_EXTRACT(`label`,'$.team') = 'golang_dev_group_01') ORDER BY created_at desc LIMIT 20
func TestQueryApplication(t *testing.T) {
req := application.NewQueryApplicationRequest()
req.SetScope("team", []string{"golang_dev_group_01"})
// req.SetScope("env", []string{"prod"})
ins, err := svc.QueryApplication(ctx, req)
if err != nil {
t.Fatal(err)
}
t.Log(ins)
}

View File

@ -30,6 +30,14 @@ type Service interface {
DescribeApplication(context.Context, *DescribeApplicationRequest) (*Application, error)
}
func NewQueryApplicationRequest() *QueryApplicationRequest {
return &QueryApplicationRequest{
QueryApplicationRequestSpec: QueryApplicationRequestSpec{
PageRequest: request.NewDefaultPageRequest(),
},
}
}
type QueryApplicationRequest struct {
policy.ResourceScope
QueryApplicationRequestSpec

6
go.mod
View File

@ -17,11 +17,13 @@ require (
go.mongodb.org/mongo-driver v1.17.3
golang.org/x/crypto v0.38.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.5
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.26.0
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.13.2 // indirect
@ -44,13 +46,13 @@ require (
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.26.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect

23
go.sum
View File

@ -1,3 +1,5 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -66,11 +68,16 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
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/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@ -93,8 +100,8 @@ github.com/infraboard/modules v0.0.12 h1:vQqm+JwzmhL+hcD9SV+WVlp9ecInc7NsbGahcTm
github.com/infraboard/modules v0.0.12/go.mod h1:NdgdH/NoeqibJmFPn9th+tisMuR862/crbXeH4FPMaU=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
@ -136,6 +143,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -317,10 +328,16 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.2.5 h1:9UogU3jkydFVW1bIVVeoYsTpLRgwDVW3rHfJG6/Ek9I=
gorm.io/datatypes v1.2.5/go.mod h1:I5FUdlKpLb5PMqeMQhm30CQ6jXP8Rj89xkTeCSAaAD4=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/driver/sqlserver v1.5.4 h1:xA+Y1KDNspv79q43bPyjDMUgHoYHLhXYmdFcYPobg8g=
gorm.io/driver/sqlserver v1.5.4/go.mod h1:+frZ/qYmuna11zHPlh5oc2O6ZA/lS88Keb0XSH1Zh/g=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.26.0 h1:9lqQVPG5aNNS6AyHdRiwScAVnXHg/L/Srzx55G5fOgs=
gorm.io/gorm v1.26.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=