add label
This commit is contained in:
parent
c1f263ab84
commit
13ea1f2e04
@ -11,7 +11,7 @@
|
|||||||
database = "devcloud_go18"
|
database = "devcloud_go18"
|
||||||
username = "root"
|
username = "root"
|
||||||
password = "123456"
|
password = "123456"
|
||||||
auto_migrate = false
|
auto_migrate = true
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[mongo]
|
[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) {
|
func TestCreatePolicy(t *testing.T) {
|
||||||
req := policy.NewCreatePolicyRequest()
|
req := policy.NewCreatePolicyRequest()
|
||||||
req.SetNamespaceId(1)
|
|
||||||
req.UserId = 2
|
req.UserId = 2
|
||||||
req.RoleId = []uint64{1}
|
req.RoleId = []uint64{1}
|
||||||
|
req.SetNamespaceId(1)
|
||||||
set, err := impl.CreatePolicy(ctx, req)
|
set, err := impl.CreatePolicy(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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/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/namespace/impl"
|
||||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy/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"
|
_ "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)
|
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
|
err := query.Count(&set.Total).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
x
Reference in New Issue
Block a user