add label
This commit is contained in:
parent
c1f263ab84
commit
13ea1f2e04
@ -11,7 +11,7 @@
|
||||
database = "devcloud_go18"
|
||||
username = "root"
|
||||
password = "123456"
|
||||
auto_migrate = false
|
||||
auto_migrate = true
|
||||
debug = true
|
||||
|
||||
[mongo]
|
||||
|
9
devcloud/mcenter/apps/label/README..md
Normal file
9
devcloud/mcenter/apps/label/README..md
Normal file
@ -0,0 +1,9 @@
|
||||
# 资源标签管理(数据字典)
|
||||
|
||||
+ key:value
|
||||
|
||||
Team Label: 用户组
|
||||

|
||||
|
||||
## 如何基于关系性数据库设计Tree结构
|
||||
|
37
devcloud/mcenter/apps/label/design.drawio
Normal file
37
devcloud/mcenter/apps/label/design.drawio
Normal file
@ -0,0 +1,37 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="dN_L16zF_8OOMsYRBXKe" name="第 1 页">
|
||||
<mxGraphModel dx="909" dy="295" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="3" value="产品研发部(技术部)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="20" y="80" width="800" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="产品/项目" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="30" y="180" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" value="开发" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="180" width="340" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="7" value="测试" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="540" y="180" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8" value="运维" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="690" y="180" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="10" value="Web前端" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="195" y="260" width="70" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="11" value="后端" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="285" y="260" width="60" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="12" value="移动端" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="365" y="260" width="60" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="13" value="PC端" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="445" y="260" width="60" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
15
devcloud/mcenter/apps/label/enum.go
Normal file
15
devcloud/mcenter/apps/label/enum.go
Normal file
@ -0,0 +1,15 @@
|
||||
package label
|
||||
|
||||
// 值类型
|
||||
type VALUE_TYPE string
|
||||
|
||||
const (
|
||||
// 文本
|
||||
VALUE_TYPE_TEXT VALUE_TYPE = "text"
|
||||
// 布尔值, 只能是ture或者false
|
||||
VALUE_TYPE_BOOLEAN VALUE_TYPE = "bool"
|
||||
// 枚举
|
||||
VALUE_TYPE_ENUM VALUE_TYPE = "enum"
|
||||
// 基于url的远程选项拉去, 仅存储URL地址, 前端自己处理
|
||||
VALUE_TYPE_HTTP_ENUM VALUE_TYPE = "http_enum"
|
||||
)
|
31
devcloud/mcenter/apps/label/impl/impl.go
Normal file
31
devcloud/mcenter/apps/label/impl/impl.go
Normal file
@ -0,0 +1,31 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
|
||||
"github.com/infraboard/mcube/v2/ioc"
|
||||
"github.com/infraboard/mcube/v2/ioc/config/datasource"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ioc.Controller().Registry(&LabelServiceImpl{})
|
||||
}
|
||||
|
||||
var _ label.Service = (*LabelServiceImpl)(nil)
|
||||
|
||||
type LabelServiceImpl struct {
|
||||
ioc.ObjectImpl
|
||||
}
|
||||
|
||||
func (i *LabelServiceImpl) Init() error {
|
||||
if datasource.Get().AutoMigrate {
|
||||
err := datasource.DB().AutoMigrate(&label.Label{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *LabelServiceImpl) Name() string {
|
||||
return label.APP_NAME
|
||||
}
|
18
devcloud/mcenter/apps/label/impl/impl_test.go
Normal file
18
devcloud/mcenter/apps/label/impl/impl_test.go
Normal file
@ -0,0 +1,18 @@
|
||||
package impl_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
|
||||
"122.51.31.227/go-course/go18/devcloud/mcenter/test"
|
||||
)
|
||||
|
||||
var (
|
||||
svc label.Service
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
func init() {
|
||||
test.DevelopmentSetUp()
|
||||
svc = label.GetService()
|
||||
}
|
62
devcloud/mcenter/apps/label/impl/label.go
Normal file
62
devcloud/mcenter/apps/label/impl/label.go
Normal file
@ -0,0 +1,62 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
|
||||
"github.com/infraboard/mcube/v2/ioc/config/datasource"
|
||||
"github.com/infraboard/mcube/v2/types"
|
||||
)
|
||||
|
||||
// CreateLabel implements label.Service.
|
||||
func (i *LabelServiceImpl) CreateLabel(ctx context.Context, in *label.CreateLabelRequest) (*label.Label, error) {
|
||||
ins, err := label.NewLabel(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := datasource.DBFromCtx(ctx).
|
||||
Create(ins).
|
||||
Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ins, nil
|
||||
}
|
||||
|
||||
// QueryLabel implements label.Service.
|
||||
func (i *LabelServiceImpl) QueryLabel(ctx context.Context, in *label.QueryLabelRequest) (*types.Set[*label.Label], error) {
|
||||
set := types.New[*label.Label]()
|
||||
|
||||
query := datasource.DBFromCtx(ctx).Model(&label.Label{})
|
||||
err := query.Count(&set.Total).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = query.
|
||||
Order("created_at desc").
|
||||
Offset(int(in.ComputeOffset())).
|
||||
Limit(int(in.PageSize)).
|
||||
Find(&set.Items).
|
||||
Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
// DeleteLabel implements label.Service.
|
||||
func (i *LabelServiceImpl) DeleteLabel(ctx context.Context, in *label.DeleteLabelRequest) (*label.Label, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// DescribeLabel implements label.Service.
|
||||
func (i *LabelServiceImpl) DescribeLabel(ctx context.Context, in *label.DescribeLabelRequest) (*label.Label, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// UpdateLabel implements label.Service.
|
||||
func (i *LabelServiceImpl) UpdateLabel(ctx context.Context, in *label.UpdateLabelRequest) (*label.Label, error) {
|
||||
panic("unimplemented")
|
||||
}
|
24
devcloud/mcenter/apps/label/impl/label_test.go
Normal file
24
devcloud/mcenter/apps/label/impl/label_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package impl_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
|
||||
)
|
||||
|
||||
func TestCreateLabel(t *testing.T) {
|
||||
req := label.NewCreateLabelRequest()
|
||||
req.Key = "tech"
|
||||
req.KeyDesc = "技术部"
|
||||
req.ValueType = label.VALUE_TYPE_ENUM
|
||||
req.AddEnumOption(&label.EnumOption{
|
||||
Label: "开发一组",
|
||||
Value: "dev01",
|
||||
})
|
||||
|
||||
ins, err := svc.CreateLabel(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(ins)
|
||||
}
|
57
devcloud/mcenter/apps/label/interface.go
Normal file
57
devcloud/mcenter/apps/label/interface.go
Normal file
@ -0,0 +1,57 @@
|
||||
package label
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/infraboard/mcube/v2/http/request"
|
||||
"github.com/infraboard/mcube/v2/ioc"
|
||||
"github.com/infraboard/mcube/v2/types"
|
||||
)
|
||||
|
||||
const (
|
||||
APP_NAME = "lable"
|
||||
)
|
||||
|
||||
func GetService() Service {
|
||||
return ioc.Controller().Get(APP_NAME).(Service)
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
// 创建标签
|
||||
CreateLabel(context.Context, *CreateLabelRequest) (*Label, error)
|
||||
// 修改标签
|
||||
UpdateLabel(context.Context, *UpdateLabelRequest) (*Label, error)
|
||||
// 删除标签
|
||||
DeleteLabel(context.Context, *DeleteLabelRequest) (*Label, error)
|
||||
// 查询标签列表
|
||||
QueryLabel(context.Context, *QueryLabelRequest) (*types.Set[*Label], error)
|
||||
// 查询标签列表
|
||||
DescribeLabel(context.Context, *DescribeLabelRequest) (*Label, error)
|
||||
}
|
||||
|
||||
type UpdateLabelRequest struct {
|
||||
DescribeLabelRequest
|
||||
// 更新人
|
||||
UpdateBy string `json:"update_by"`
|
||||
// 标签信息
|
||||
Spec *CreateLabelRequest `json:"spec"`
|
||||
}
|
||||
|
||||
type DeleteLabelRequest struct {
|
||||
DescribeLabelRequest
|
||||
}
|
||||
|
||||
func NewQueryLabelRequest() *QueryLabelRequest {
|
||||
return &QueryLabelRequest{
|
||||
PageRequest: request.NewDefaultPageRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
type QueryLabelRequest struct {
|
||||
*request.PageRequest
|
||||
}
|
||||
|
||||
type DescribeLabelRequest struct {
|
||||
// 标签Id
|
||||
Id string `json:"id"`
|
||||
}
|
120
devcloud/mcenter/apps/label/model.go
Normal file
120
devcloud/mcenter/apps/label/model.go
Normal file
@ -0,0 +1,120 @@
|
||||
package label
|
||||
|
||||
import (
|
||||
"github.com/infraboard/mcube/v2/ioc/config/validator"
|
||||
"github.com/infraboard/mcube/v2/tools/pretty"
|
||||
"github.com/infraboard/modules/iam/apps"
|
||||
)
|
||||
|
||||
func NewLabel(spc *CreateLabelRequest) (*Label, error) {
|
||||
if err := spc.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Label{
|
||||
ResourceMeta: *apps.NewResourceMeta(),
|
||||
Spec: spc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Label struct {
|
||||
// 基础数据
|
||||
apps.ResourceMeta
|
||||
// 空间定义
|
||||
Spec *CreateLabelRequest `json:"spec" bson:",inline" gorm:"embedded"`
|
||||
}
|
||||
|
||||
func (l *Label) TableName() string {
|
||||
return "labels"
|
||||
}
|
||||
|
||||
func (l *Label) String() string {
|
||||
return pretty.ToJSON(l)
|
||||
}
|
||||
|
||||
func NewCreateLabelRequest() *CreateLabelRequest {
|
||||
return &CreateLabelRequest{
|
||||
CreateCreateLabelSpec: CreateCreateLabelSpec{
|
||||
Resources: []string{},
|
||||
EnumOptions: []*EnumOption{},
|
||||
Extras: map[string]string{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type CreateLabelRequest struct {
|
||||
// 创建人
|
||||
CreateBy string `json:"create_by" bson:"create_by" gorm:"column:create_by;type:varchar(255)"`
|
||||
// 标签的键
|
||||
Domain string `json:"domain" bson:"domain" gorm:"column:domain;type:varchar(100)"`
|
||||
// 标签的键
|
||||
Namespace string `json:"namespace" bson:"namespace" gorm:"column:namespace;type:varchar(100)"`
|
||||
// 用户参数
|
||||
CreateCreateLabelSpec
|
||||
}
|
||||
|
||||
func (r *CreateLabelRequest) Validate() error {
|
||||
return validator.Validate(r)
|
||||
}
|
||||
|
||||
func (r *CreateLabelRequest) AddEnumOption(enums ...*EnumOption) *CreateLabelRequest {
|
||||
r.EnumOptions = append(r.EnumOptions, enums...)
|
||||
return r
|
||||
}
|
||||
|
||||
type CreateCreateLabelSpec struct {
|
||||
// 适用于那些资源
|
||||
Resources []string `json:"resources" bson:"resources" gorm:"column:resources;type:json;serializer:json;" description:"适用于那些资源" optional:"true"`
|
||||
|
||||
// 标签的键, 标签的Key不允许修改, 带前缀的 tech.dev.frontend01 tech.dev.backend01
|
||||
Key string `json:"key" bson:"key" gorm:"column:key;type:varchar(255)" validate:"required"`
|
||||
// 标签的键的描述
|
||||
KeyDesc string `json:"key_desc" bson:"key_desc" gorm:"column:key_desc;type:varchar(255)" validate:"required"`
|
||||
// 标签的颜色
|
||||
Color string `json:"color" bson:"color" gorm:"column:color;type:varchar(100)"`
|
||||
|
||||
// 值类型
|
||||
ValueType VALUE_TYPE `json:"value_type" gorm:"column:value_type;type:varchar(20)" bson:"value_type"`
|
||||
// 标签默认值
|
||||
DefaultValue string `json:"default_value" gorm:"column:default_value;type:text" bson:"default_value"`
|
||||
// 值描述
|
||||
ValueDesc string `json:"value_desc" gorm:"column:value_desc;type:text" bson:"value_desc"`
|
||||
// 是否是多选
|
||||
Multiple bool `json:"multiple" bson:"multiple" gorm:"column:multiple;tinyint(1)"`
|
||||
// 枚举值的选项
|
||||
EnumOptions []*EnumOption `json:"enum_options,omitempty" bson:"enum_options" gorm:"column:enum_options;type:json;serializer:json;"`
|
||||
// 基于Http枚举的配置
|
||||
HttpEnumConfig HttpEnumConfig `json:"http_enum_config,omitempty" gorm:"embedded" bson:"http_enum_config"`
|
||||
// 值的样例
|
||||
Example string `json:"example" bson:"example" gorm:"column:example;type:text"`
|
||||
|
||||
// 扩展属性
|
||||
Extras map[string]string `json:"extras" bson:"extras" gorm:"column:extras;type:json;serializer:json;"`
|
||||
}
|
||||
|
||||
type EnumOption struct {
|
||||
// 选项的说明
|
||||
Label string `json:"label" bson:"label"`
|
||||
// 用户输入
|
||||
Input string `json:"input" bson:"input" validate:"required"`
|
||||
// 选项的值, 根据parent.input + children.input 自动生成
|
||||
Value string `json:"value" bson:"value"`
|
||||
// 标签的颜色
|
||||
Color string `json:"color" bson:"color"`
|
||||
// 是否废弃
|
||||
Deprecate bool `json:"deprecate" bson:"deprecate"`
|
||||
// 废弃说明
|
||||
DeprecateDesc string `json:"deprecate_desc" bson:"deprecate_desc"`
|
||||
// 枚举的子选项
|
||||
Children []*EnumOption `json:"children,omitempty" bson:"children"`
|
||||
// 扩展属性
|
||||
Extensions map[string]string `json:"extensions" bson:"extensions"`
|
||||
}
|
||||
|
||||
type HttpEnumConfig struct {
|
||||
// 基于枚举的URL, 注意只支持Get方法
|
||||
Url string `json:"url" bson:"url" gorm:"column:http_enum_config_url;type:text"`
|
||||
// Enum Label映射的字段名
|
||||
KeyFiled string `json:"enum_label_name" bson:"enum_label_name" gorm:"column:http_enum_config_key_filed;type:varchar(100)"`
|
||||
// Enum Value映射的字段名
|
||||
ValueFiled string `json:"enum_label_value" bson:"enum_label_value" gorm:"column:http_enum_config_value_filed;type:varchar(100)"`
|
||||
}
|
@ -20,9 +20,9 @@ func TestQueryPolicy(t *testing.T) {
|
||||
|
||||
func TestCreatePolicy(t *testing.T) {
|
||||
req := policy.NewCreatePolicyRequest()
|
||||
req.SetNamespaceId(1)
|
||||
req.UserId = 2
|
||||
req.RoleId = []uint64{1}
|
||||
req.SetNamespaceId(1)
|
||||
set, err := impl.CreatePolicy(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
// 鉴权
|
||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint/impl"
|
||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label/impl"
|
||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace/impl"
|
||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy/impl"
|
||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/role/impl"
|
||||
|
@ -40,14 +40,6 @@ func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *appli
|
||||
query = query.Where("ready = ?", *in.Ready)
|
||||
}
|
||||
|
||||
if in.NamespaceId != nil {
|
||||
query = query.Where("namespace = ?", in.NamespaceId)
|
||||
}
|
||||
// 过滤条件, Label
|
||||
|
||||
if in.Scope != nil {
|
||||
}
|
||||
|
||||
err := query.Count(&set.Total).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
Loading…
x
Reference in New Issue
Block a user