mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #5822 from swordqiu/hotfix/qj-update-depecated-by-tag-3.1
update deprecated-by tag for release 3.1
This commit is contained in:
@@ -129,9 +129,9 @@ require (
|
||||
k8s.io/cluster-bootstrap v0.17.3
|
||||
k8s.io/kubernetes v1.16.0
|
||||
yunion.io/x/executor v0.0.0-20200227030256-a18417815e74
|
||||
yunion.io/x/jsonutils v0.0.0-20200330063846-589d9924bb8b
|
||||
yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501
|
||||
yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3
|
||||
yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624
|
||||
yunion.io/x/pkg v0.0.0-20200415124010-2c7da30b998f
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
|
||||
yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57
|
||||
yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3
|
||||
|
||||
@@ -1015,8 +1015,8 @@ vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj
|
||||
yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 h1:A15C6VdVRWvmQ9pAJHrUs9yan5qKlYH7uaRxHg1kRbk=
|
||||
yunion.io/x/executor v0.0.0-20200227030256-a18417815e74/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
|
||||
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
|
||||
yunion.io/x/jsonutils v0.0.0-20200330063846-589d9924bb8b h1:mt0TOKRk76yeH0whJfmKsceXBuudXLjvoj8NKGTqpEU=
|
||||
yunion.io/x/jsonutils v0.0.0-20200330063846-589d9924bb8b/go.mod h1:T7kxQJR13+t7z0TuT+Wzd7MTxBOk2H9c0pO1ONQSv90=
|
||||
yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501 h1:i1r9XvbdxH3FgTCLmTaRi3MzQqhiQimXJRlUOPgrxnU=
|
||||
yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501/go.mod h1:T7kxQJR13+t7z0TuT+Wzd7MTxBOk2H9c0pO1ONQSv90=
|
||||
yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE=
|
||||
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d h1:59zrDL7Ft+hDukguJRmLr/Gdu/9V75x+yX99ovZwfaA=
|
||||
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
|
||||
@@ -1025,8 +1025,8 @@ yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3/go.mod h1:LC6f/4FozL0iaAbnFt2
|
||||
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624 h1:yPayJlTJHOP0vKY6ovliZyTwJY9RvdWEF+QDqnxt/iw=
|
||||
yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/pkg v0.0.0-20200415124010-2c7da30b998f h1:7aKKuquYIFESmLnti3ea0IhGMZ1K1JnP/1XeJg59bmA=
|
||||
yunion.io/x/pkg v0.0.0-20200415124010-2c7da30b998f/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
|
||||
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
|
||||
yunion.io/x/sqlchemy v0.0.0-20200312002602-1177cd8fbc57 h1:KtQAuLJ00RSUVqkiRmJ1DiDABiw0U3xxXnzD3lGavaY=
|
||||
|
||||
@@ -285,7 +285,7 @@ type ServerConfigs struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// alias for InstanceType
|
||||
Sku string `json:"sku" deprecated-by:"instance_type"`
|
||||
Sku string `json:"sku" "yunion:deprecated-by":"instance_type"`
|
||||
|
||||
// 虚拟机高可用(创建备机)
|
||||
// default: false
|
||||
@@ -357,12 +357,13 @@ type ServerCreateInput struct {
|
||||
// required: false
|
||||
UserData string `json:"user_data"`
|
||||
|
||||
// Deprecated
|
||||
// swagger:ignore
|
||||
Keypair string `json:"keypair" deprecated-by:"keypair_id"`
|
||||
KeypairId string `json:"keypair_id" "yunion:deprecated-by":"keypair"`
|
||||
|
||||
// 秘钥对Id
|
||||
// required: false
|
||||
KeypairId string `json:"keypair_id"`
|
||||
Keypair string `json:"keypair"`
|
||||
|
||||
// 密码
|
||||
// 要求: 密码长度 >= 20, 至少包含一个数字一个小写字母一个大小字母及特殊字符~`!@#$%^&*()-_=+[]{}|:';\",./<>?中的一个
|
||||
|
||||
@@ -147,30 +147,30 @@ type ManagedResourceListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
Manager string `json:"manager" deprecated-by:"cloudprovider"`
|
||||
Manager string `json:"manager" "yunion:deprecated-by":"cloudprovider"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
ManagerId string `json:"manager_id" deprecated-by:"cloudprovider"`
|
||||
ManagerId string `json:"manager_id" "yunion:deprecated-by":"cloudprovider"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
CloudproviderId string `json:"cloudprovider_id" deprecated-by:"cloudprovider"`
|
||||
CloudproviderId string `json:"cloudprovider_id" "yunion:deprecated-by":"cloudprovider"`
|
||||
|
||||
// 列出关联指定云账号(ID或Name)的资源
|
||||
Cloudaccount string `json:"cloudaccount"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
CloudaccountId string `json:"cloudaccount_id" deprecated-by:"cloudaccount"`
|
||||
CloudaccountId string `json:"cloudaccount_id" "yunion:deprecated-by":"cloudaccount"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
Account string `json:"account" deprecated-by:"cloudaccount"`
|
||||
Account string `json:"account" "yunion:deprecated-by":"cloudaccount"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
AccountId string `json:"account_id" deprecated-by:"cloudaccount"`
|
||||
AccountId string `json:"account_id" "yunion:deprecated-by":"cloudaccount"`
|
||||
|
||||
// 列出指定云平台的资源,支持的云平台如下
|
||||
//
|
||||
@@ -196,7 +196,7 @@ type ManagedResourceListInput struct {
|
||||
Providers []string `json:"providers"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
Provider []string `json:"provider" deprecated-by:"providers"`
|
||||
Provider []string `json:"provider" "yunion:deprecated-by":"providers"`
|
||||
|
||||
// 列出指定云平台品牌的资源,一般来说brand和provider相同,除了以上支持的provider之外,还支持以下band
|
||||
//
|
||||
@@ -207,7 +207,7 @@ type ManagedResourceListInput struct {
|
||||
Brands []string `json:"brands"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
Brand []string `json:"brand" deprecated-by:"brands"`
|
||||
Brand []string `json:"brand" "yunion:deprecated-by":"brands"`
|
||||
|
||||
// 列出指定云环境的资源,支持云环境如下:
|
||||
//
|
||||
|
||||
@@ -212,7 +212,7 @@ type DbinstanceFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by dbinstance_id
|
||||
DbinstanceId string `json:"dbinstance_id" deprecated-by:"dbinstance"`
|
||||
DbinstanceId string `json:"dbinstance_id" "yunion:deprecated-by":"dbinstance"`
|
||||
}
|
||||
|
||||
type DBInstanceDetails struct {
|
||||
|
||||
@@ -89,7 +89,7 @@ type SnapshotPolicyFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter disk by snapshotpolicy_id
|
||||
SnapshotpolicyId string `json:"snapshotpolicy_id" deprecated-by:"snapshotpolicy"`
|
||||
SnapshotpolicyId string `json:"snapshotpolicy_id" "yunion:deprecated-by":"snapshotpolicy"`
|
||||
}
|
||||
|
||||
type DiskListInput struct {
|
||||
@@ -109,7 +109,7 @@ type DiskListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by disk type
|
||||
Type string `json:"type" deprecated-by:"disk_type"`
|
||||
Type string `json:"type" "yunion:deprecated-by":"disk_type"`
|
||||
// 过滤指定disk_type的磁盘列表,可能的值为:sys, data, swap. volume
|
||||
//
|
||||
// | disk_type值 | 说明 |
|
||||
@@ -128,7 +128,7 @@ type DiskFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by disk_id
|
||||
DiskId string `json:"disk_id" deprecated-by:"disk"`
|
||||
DiskId string `json:"disk_id" "yunion:deprecated-by":"disk"`
|
||||
}
|
||||
|
||||
type SimpleGuest struct {
|
||||
|
||||
@@ -27,15 +27,15 @@ type RegionalFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
CloudregionId string `json:"cloudregion_id" deprecated-by:"cloudregion"`
|
||||
CloudregionId string `json:"cloudregion_id" "yunion:deprecated-by":"cloudregion"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
Region string `json:"region" deprecated-by:"cloudregion"`
|
||||
Region string `json:"region" "yunion:deprecated-by":"cloudregion"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// description: this param will be deprecate at 3.0
|
||||
RegionId string `json:"region_id" deprecated-by:"cloudregion"`
|
||||
RegionId string `json:"region_id" "yunion:deprecated-by":"cloudregion"`
|
||||
}
|
||||
|
||||
type ZonalFilterListInput struct {
|
||||
@@ -46,7 +46,7 @@ type ZonalFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by zone_id
|
||||
ZoneId string `json:"zone_id" deprecated-by:"zone"`
|
||||
ZoneId string `json:"zone_id" "yunion:deprecated-by":"zone"`
|
||||
// 过滤处于多个指定可用区内的资源
|
||||
Zones []string `json:"zones"`
|
||||
}
|
||||
@@ -67,7 +67,7 @@ type HostFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by host_id
|
||||
HostId string `json:"host_id" deprecated-by:"host"`
|
||||
HostId string `json:"host_id" "yunion:deprecated-by":"host"`
|
||||
}
|
||||
|
||||
type CloudregionListInput struct {
|
||||
|
||||
@@ -28,15 +28,15 @@ type ServerFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by guest Id
|
||||
ServerId string `json:"server_id" deprecated-by:"server"`
|
||||
ServerId string `json:"server_id" "yunion:deprecated-by":"server"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by guest Id
|
||||
Guest string `json:"guest" deprecated-by:"server"`
|
||||
Guest string `json:"guest" "yunion:deprecated-by":"server"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by guest Id
|
||||
GuestId string `json:"guest_id" deprecated-by:"server"`
|
||||
GuestId string `json:"guest_id" "yunion:deprecated-by":"server"`
|
||||
}
|
||||
|
||||
type ServerListInput struct {
|
||||
|
||||
@@ -41,5 +41,5 @@ type GroupFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// deprecated: true
|
||||
// Filter by instance group Id
|
||||
GroupId string `json:"group_id" deprecated-by:"group"`
|
||||
GroupId string `json:"group_id" "yunion:deprecated-by":"group"`
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type VpcFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by vpc Id
|
||||
VpcId string `json:"vpc_id" deprecated-by:"vpc"`
|
||||
VpcId string `json:"vpc_id" "yunion:deprecated-by":"vpc"`
|
||||
}
|
||||
|
||||
type WireFilterListInput struct {
|
||||
@@ -35,7 +35,7 @@ type WireFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// fitler by wire id
|
||||
WireId string `json:"wire_id" deprecated-by:"wire"`
|
||||
WireId string `json:"wire_id" "yunion:deprecated-by":"wire"`
|
||||
}
|
||||
|
||||
type NetworkFilterListInput struct {
|
||||
@@ -46,7 +46,7 @@ type NetworkFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by networkId
|
||||
NetworkId string `json:"network_id" deprecated-by:"network"`
|
||||
NetworkId string `json:"network_id" "yunion:deprecated-by":"network"`
|
||||
}
|
||||
|
||||
type NetworkListInput struct {
|
||||
|
||||
@@ -45,7 +45,7 @@ type SchedtagFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by schedtag_id
|
||||
SchedtagId string `json:"schedtag_id" deprecated-by:"schedtag"`
|
||||
SchedtagId string `json:"schedtag_id" "yunion:deprecated-by":"schedtag"`
|
||||
}
|
||||
|
||||
type SchedtagListInput struct {
|
||||
@@ -56,7 +56,7 @@ type SchedtagListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by type, alias for resource_type
|
||||
Type string `json:"type" deprecated-by:"resource_type"`
|
||||
Type string `json:"type" "yunion:deprecated-by":"resource_type"`
|
||||
}
|
||||
|
||||
type SchedtagDetails struct {
|
||||
|
||||
@@ -162,7 +162,7 @@ type SecgroupFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by secgroup_id
|
||||
SecgroupId string `json:"secgroup_id" deprecated-by:"secgroup"`
|
||||
SecgroupId string `json:"secgroup_id" "yunion:deprecated-by":"secgroup"`
|
||||
}
|
||||
|
||||
type SecgroupDetails struct {
|
||||
|
||||
@@ -144,7 +144,7 @@ type StorageFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by storage_id
|
||||
StorageId string `json:"storage_id" deprecated-by:"storage"`
|
||||
StorageId string `json:"storage_id" "yunion:deprecated-by":"storage"`
|
||||
}
|
||||
|
||||
type StorageShareFilterListInput struct {
|
||||
|
||||
@@ -40,10 +40,10 @@ type IdentityProviderCreateInput struct {
|
||||
Template string `json:"template"`
|
||||
|
||||
// 默认导入用户和组的域
|
||||
TargetDomainId string `json:"target_domain_id"`
|
||||
TargetDomain string `json:"target_domain"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
TargetDomain string `json:"target_domain" "yunion:deprecated-by":"target_domain_id"`
|
||||
TargetDomainId string `json:"target_domain_id" "yunion:deprecated-by":"target_domain"`
|
||||
|
||||
// 新建域的时候是否自动新建第一个项目
|
||||
AutoCreateProject *bool `json:"auto_create_project"`
|
||||
|
||||
@@ -48,15 +48,15 @@ type ProjectFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by project_id
|
||||
ProjectId string `json:"project_id" deprecated-by:"project"`
|
||||
ProjectId string `json:"project_id" "yunion:deprecated-by":"project"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by tenant
|
||||
Tenant string `json:"tenant" deprecated-by:"project"`
|
||||
Tenant string `json:"tenant" "yunion:deprecated-by":"project"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by tenant_id
|
||||
TenantId string `json:"tenant_id" deprecated-by:"project"`
|
||||
TenantId string `json:"tenant_id" "yunion:deprecated-by":"project"`
|
||||
}
|
||||
|
||||
type UserFilterListInput struct {
|
||||
@@ -65,7 +65,7 @@ type UserFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by user_id
|
||||
UserId string `json:"user_id" deprecated-by:"user"`
|
||||
UserId string `json:"user_id" "yunion:deprecated-by":"user"`
|
||||
}
|
||||
|
||||
type GroupFilterListInput struct {
|
||||
@@ -74,7 +74,7 @@ type GroupFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by group_id
|
||||
GroupId string `json:"group_id" deprecated-by:"group"`
|
||||
GroupId string `json:"group_id" "yunion:deprecated-by":"group"`
|
||||
}
|
||||
|
||||
type RoleFilterListInput struct {
|
||||
@@ -83,7 +83,7 @@ type RoleFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by role_id
|
||||
RoleId string `json:"role_id" deprecated-by:"role"`
|
||||
RoleId string `json:"role_id" "yunion:deprecated-by":"role"`
|
||||
}
|
||||
|
||||
type ServiceFilterListInput struct {
|
||||
@@ -92,7 +92,7 @@ type ServiceFilterListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// filter by service_id
|
||||
ServiceId string `json:"service_id" deprecated-by:"service"`
|
||||
ServiceId string `json:"service_id" "yunion:deprecated-by":"service"`
|
||||
}
|
||||
|
||||
type RoleListInput struct {
|
||||
|
||||
+6
-6
@@ -28,11 +28,11 @@ type DomainizedResourceListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Project domain Id filter, alias for project_domain
|
||||
ProjectDomainId string `json:"project_domain_id" deprecated-by:"project_domain"`
|
||||
ProjectDomainId string `json:"project_domain_id" "yunion:deprecated-by":"project_domain"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Domain Id filter, alias for project_domain
|
||||
DomainId string `json:"domain_id" deprecated-by:"project_domain"`
|
||||
DomainId string `json:"domain_id" "yunion:deprecated-by":"project_domain"`
|
||||
}
|
||||
|
||||
type DomainizedResourceCreateInput struct {
|
||||
@@ -53,15 +53,15 @@ type ProjectizedResourceListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by project_id, alias for project
|
||||
ProjectId string `json:"project_id" deprecated-by:"project"`
|
||||
ProjectId string `json:"project_id" "yunion:deprecated-by":"project"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by tenant ID or Name, alias for project
|
||||
Tenant string `json:"tenant" deprecated-by:"project"`
|
||||
Tenant string `json:"tenant" "yunion:deprecated-by":"project"`
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by tenant_id, alias for project
|
||||
TenantId string `json:"tenant_id" deprecated-by:"project"`
|
||||
TenantId string `json:"tenant_id" "yunion:deprecated-by":"project"`
|
||||
}
|
||||
|
||||
type ProjectizedResourceCreateInput struct {
|
||||
@@ -82,7 +82,7 @@ type UserResourceListInput struct {
|
||||
// swagger:ignore
|
||||
// Deprecated
|
||||
// Filter by userId
|
||||
UserId string `json:"user_id" deprecated-by:"user"`
|
||||
UserId string `json:"user_id" "yunion:deprecated-by":"user"`
|
||||
}
|
||||
|
||||
func (input UserResourceListInput) UserStr() string {
|
||||
|
||||
@@ -402,7 +402,7 @@ func FetchServerCreateInputByJSON(obj jsonutils.JSONObject) (*compute.ServerCrea
|
||||
input.InstanceType = skuName
|
||||
}
|
||||
if keypair := jsonutils.GetAnyString(obj, []string{"keypair", "keypair_id"}); keypair != "" {
|
||||
input.KeypairId = keypair
|
||||
input.Keypair = keypair
|
||||
}
|
||||
if secgroup := jsonutils.GetAnyString(obj, []string{"secgroup", "secgroup_id", "secgrp_id"}); len(secgroup) != 0 {
|
||||
input.SecgroupId = secgroup
|
||||
|
||||
@@ -246,8 +246,8 @@ func (gt *SGuestTemplate) getMoreDetails(ctx context.Context, userCred mcclient.
|
||||
configInfo.Disks = disks
|
||||
|
||||
// keypair
|
||||
if len(input.KeypairId) > 0 {
|
||||
model, err := KeypairManager.FetchById(input.KeypairId)
|
||||
if len(input.Keypair) > 0 {
|
||||
model, err := KeypairManager.FetchByIdOrName(userCred, input.Keypair)
|
||||
if err == nil {
|
||||
keypair := model.(*SKeypair)
|
||||
configInfo.Keypair = keypair.GetName()
|
||||
@@ -341,7 +341,7 @@ func (gt *SGuestTemplate) PerformPublic(ctx context.Context, userCred mcclient.T
|
||||
|
||||
// check for below private resource in the guest template
|
||||
privateResource := map[string]int{
|
||||
"keypair": len(input.KeypairId),
|
||||
"keypair": len(input.Keypair),
|
||||
"instance group": len(input.InstanceGroupIds),
|
||||
"instance snapshot": len(input.InstanceSnapshotId),
|
||||
}
|
||||
|
||||
@@ -1211,13 +1211,13 @@ func (manager *SGuestManager) validateCreateData(
|
||||
input.IsolatedDevices[idx] = devConfig
|
||||
}
|
||||
|
||||
keypairId := input.KeypairId
|
||||
keypairId := input.Keypair
|
||||
if len(keypairId) > 0 {
|
||||
keypairObj, err := KeypairManager.FetchByIdOrName(userCred, keypairId)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewResourceNotFoundError("Keypair %s not found", keypairId)
|
||||
}
|
||||
input.KeypairId = keypairObj.GetId()
|
||||
input.Keypair = keypairObj.GetId()
|
||||
}
|
||||
|
||||
secGrpIds := []string{}
|
||||
@@ -4714,7 +4714,7 @@ func (self *SGuest) ToCreateInput(userCred mcclient.TokenCredential) *api.Server
|
||||
userInput.ShutdownBehavior = genInput.ShutdownBehavior
|
||||
userInput.IsSystem = genInput.IsSystem
|
||||
userInput.SecgroupId = genInput.SecgroupId
|
||||
userInput.KeypairId = genInput.KeypairId
|
||||
userInput.Keypair = genInput.Keypair
|
||||
userInput.EipBw = genInput.EipBw
|
||||
userInput.EipChargeType = genInput.EipChargeType
|
||||
// cloned server should belongs to the project creating it
|
||||
@@ -4776,7 +4776,7 @@ func (self *SGuest) toCreateInput() *api.ServerCreateInput {
|
||||
r.IsolatedDevices = self.ToIsolatedDevicesConfig()
|
||||
|
||||
if keypair := self.getKeypair(); keypair != nil {
|
||||
r.KeypairId = keypair.Id
|
||||
r.Keypair = keypair.Id
|
||||
}
|
||||
if host := self.GetHost(); host != nil {
|
||||
r.ResourceType = host.ResourceType
|
||||
|
||||
@@ -262,7 +262,7 @@ func (self *SInstanceSnapshot) ToInstanceCreateInput(
|
||||
sourceInput.VcpuCount = serverConfig.Ncpu
|
||||
}
|
||||
if len(self.KeypairId) > 0 {
|
||||
sourceInput.KeypairId = self.KeypairId
|
||||
sourceInput.Keypair = self.KeypairId
|
||||
}
|
||||
if self.SecGroups != nil {
|
||||
secGroups := make([]string, 0)
|
||||
|
||||
@@ -303,7 +303,7 @@ func (manager *SIdentityProviderManager) ValidateCreateData(
|
||||
}
|
||||
}
|
||||
|
||||
targetDomainStr := input.TargetDomainId
|
||||
targetDomainStr := input.TargetDomain
|
||||
if len(targetDomainStr) > 0 {
|
||||
domain, err := DomainManager.FetchDomainById(targetDomainStr)
|
||||
if err != nil {
|
||||
@@ -313,7 +313,7 @@ func (manager *SIdentityProviderManager) ValidateCreateData(
|
||||
return input, httperrors.NewGeneralError(err)
|
||||
}
|
||||
}
|
||||
input.TargetDomainId = domain.Id
|
||||
input.TargetDomain = domain.Id
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
@@ -364,7 +364,7 @@ func (opts *ServerCreateOptionalOptions) OptionalParams() (*computeapi.ServerCre
|
||||
params := &computeapi.ServerCreateInput{
|
||||
ServerConfigs: config,
|
||||
VcpuCount: opts.VcpuCount,
|
||||
KeypairId: opts.Keypair,
|
||||
Keypair: opts.Keypair,
|
||||
Password: opts.Password,
|
||||
Cdrom: opts.Iso,
|
||||
Vga: opts.Vga,
|
||||
|
||||
Vendored
+2
-2
@@ -924,12 +924,12 @@ sigs.k8s.io/yaml
|
||||
yunion.io/x/executor/apis
|
||||
yunion.io/x/executor/client
|
||||
yunion.io/x/executor/server
|
||||
# yunion.io/x/jsonutils v0.0.0-20200330063846-589d9924bb8b
|
||||
# yunion.io/x/jsonutils v0.0.0-20200415132054-2bf8a5e94501
|
||||
yunion.io/x/jsonutils
|
||||
# yunion.io/x/log v0.0.0-20200313080802-57a4ce5966b3
|
||||
yunion.io/x/log
|
||||
yunion.io/x/log/hooks
|
||||
# yunion.io/x/pkg v0.0.0-20200403115157-880d716ed624
|
||||
# yunion.io/x/pkg v0.0.0-20200415124010-2c7da30b998f
|
||||
yunion.io/x/pkg/errors
|
||||
yunion.io/x/pkg/gotypes
|
||||
yunion.io/x/pkg/prettytable
|
||||
|
||||
+5
-1
@@ -14,6 +14,10 @@
|
||||
|
||||
package jsonutils
|
||||
|
||||
import (
|
||||
"yunion.io/x/pkg/util/reflectutils"
|
||||
)
|
||||
|
||||
const (
|
||||
TAG_DEPRECATED_BY = "deprecated-by"
|
||||
TAG_DEPRECATED_BY = reflectutils.TAG_DEPRECATED_BY
|
||||
)
|
||||
|
||||
+12
-7
@@ -520,7 +520,7 @@ func (this *JSONDict) unmarshalMap(val reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStructFieldValueSet, visited map[string]bool) error {
|
||||
func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStructFieldValueSet, keyIndexMap map[string][]int, visited map[string]bool) error {
|
||||
if visited == nil {
|
||||
visited = make(map[string]bool)
|
||||
}
|
||||
@@ -529,10 +529,14 @@ func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStruct
|
||||
return nil
|
||||
}
|
||||
visited[key] = true
|
||||
indexes := fieldValues.GetStructFieldIndexes(key)
|
||||
if len(indexes) == 0 {
|
||||
// no field match k, ignore
|
||||
return nil
|
||||
indexes, ok := keyIndexMap[key]
|
||||
if !ok || len(indexes) == 0 {
|
||||
// try less strict match name
|
||||
indexes = fieldValues.GetStructFieldIndexes2(key, false)
|
||||
if len(indexes) == 0 {
|
||||
// no field match k, ignore
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for _, index := range indexes {
|
||||
err := v.unmarshalValue(fieldValues[index].Value)
|
||||
@@ -541,7 +545,7 @@ func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStruct
|
||||
}
|
||||
depInfo, ok := fieldValues[index].Info.Tags[TAG_DEPRECATED_BY]
|
||||
if ok {
|
||||
err := setStructFieldAt(depInfo, v, fieldValues, visited)
|
||||
err := setStructFieldAt(depInfo, v, fieldValues, keyIndexMap, visited)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "setStructFieldAt")
|
||||
}
|
||||
@@ -552,8 +556,9 @@ func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStruct
|
||||
|
||||
func (this *JSONDict) unmarshalStruct(val reflect.Value) error {
|
||||
fieldValues := reflectutils.FetchStructFieldValueSetForWrite(val)
|
||||
keyIndexMap := fieldValues.GetStructFieldIndexesMap()
|
||||
for k, v := range this.data {
|
||||
err := setStructFieldAt(k, v, fieldValues, nil)
|
||||
err := setStructFieldAt(k, v, fieldValues, keyIndexMap, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "setStructFieldAt %s: %s", k, v)
|
||||
}
|
||||
|
||||
+157
-7
@@ -16,8 +16,11 @@ package prettytable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type AlignmentType uint8
|
||||
@@ -37,10 +40,15 @@ type ptColumn struct {
|
||||
|
||||
type PrettyTable struct {
|
||||
columns []ptColumn
|
||||
|
||||
maxLineWidth int
|
||||
tryTermWidth bool
|
||||
}
|
||||
|
||||
func NewPrettyTable(fields []string) *PrettyTable {
|
||||
var pt = PrettyTable{}
|
||||
var pt = PrettyTable{
|
||||
tryTermWidth: true,
|
||||
}
|
||||
for _, field := range fields {
|
||||
col := ptColumn{Title: field, Align: AlignLeft}
|
||||
pt.columns = append(pt.columns, col)
|
||||
@@ -48,6 +56,15 @@ func NewPrettyTable(fields []string) *PrettyTable {
|
||||
return &pt
|
||||
}
|
||||
|
||||
func termWidth() (int, error) {
|
||||
fd := int(os.Stdout.Fd())
|
||||
wsz, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int(wsz.Col), nil
|
||||
}
|
||||
|
||||
func rowLine(buf *bytes.Buffer, widths []int) {
|
||||
buf.WriteByte('+')
|
||||
for _, w := range widths {
|
||||
@@ -128,9 +145,14 @@ func runeDisplayWidth(r rune) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// cellDisplayWidth returns display width of the cell when printed as the
|
||||
// nthCol. prevWidth is the total display width (as return by this same func)
|
||||
// of previous cells in the same line
|
||||
// cellDisplayWidth returns display width of the cell content (excluding bars
|
||||
// and paddings) when printed as the nthCol.
|
||||
//
|
||||
// nthCol is 0-based
|
||||
//
|
||||
// prevWidth is the total display width (as return by this same func) of
|
||||
// previous cells in the same line. It will be used to calculate width of tab
|
||||
// characters
|
||||
func cellDisplayWidth(cell string, nthCol int, prevWidth int) int {
|
||||
// `| ` at the front and ` | ` in the middle
|
||||
sX := prevWidth + nthCol*3 + 2
|
||||
@@ -157,14 +179,100 @@ func cellDisplayWidth(cell string, nthCol int, prevWidth int) int {
|
||||
return width
|
||||
}
|
||||
|
||||
func wrapCell(cell string, nthCol int, prevWidth int, newWidth int) string {
|
||||
sX := prevWidth + nthCol*3 + 2
|
||||
var (
|
||||
wrapped = false
|
||||
newCell = ""
|
||||
cline = make([]rune, 0, newWidth+1)
|
||||
cw = 0
|
||||
cx = sX
|
||||
)
|
||||
for _, c := range cell {
|
||||
var incr int
|
||||
if c == '\n' {
|
||||
cline = append(cline, c)
|
||||
newCell += string(cline)
|
||||
cline = cline[:0]
|
||||
cw = 0
|
||||
cx = sX
|
||||
continue
|
||||
} else if c != '\t' {
|
||||
incr = runeDisplayWidth(c)
|
||||
} else {
|
||||
// terminal with have the char TabWidth aligned
|
||||
incr = TabWidth - (cx & (TabWidth - 1))
|
||||
}
|
||||
t := cw + incr
|
||||
if t < newWidth {
|
||||
cline = append(cline, c)
|
||||
cw += incr
|
||||
cx += incr
|
||||
} else if t == newWidth {
|
||||
cline = append(cline, c, '\n')
|
||||
newCell += string(cline)
|
||||
cline = cline[:0]
|
||||
cw = 0
|
||||
cx = sX
|
||||
if !wrapped {
|
||||
wrapped = true
|
||||
}
|
||||
} else {
|
||||
if len(cline) == 0 {
|
||||
newCell += string(c) + "\n"
|
||||
} else {
|
||||
newCell += string(cline) + "\n"
|
||||
cline = cline[:1]
|
||||
cline[0] = c
|
||||
}
|
||||
cw = 0
|
||||
cx = sX
|
||||
if !wrapped {
|
||||
wrapped = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(cline) > 0 {
|
||||
newCell += string(cline)
|
||||
} else if !wrapped && newCell != "" {
|
||||
l := len(newCell) - 1
|
||||
c := newCell[l]
|
||||
if c == '\n' {
|
||||
newCell = newCell[:l]
|
||||
}
|
||||
}
|
||||
return newCell
|
||||
}
|
||||
|
||||
func (this *PrettyTable) MaxLineWidth(w int) {
|
||||
this.maxLineWidth = w
|
||||
}
|
||||
|
||||
func (this *PrettyTable) hasMaxLineWidth() (int, bool) {
|
||||
if this.maxLineWidth > 0 {
|
||||
return this.maxLineWidth, true
|
||||
}
|
||||
if this.tryTermWidth {
|
||||
w, err := termWidth()
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return w, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (this *PrettyTable) GetString(fields [][]string) string {
|
||||
if len(fields) == 0 {
|
||||
return ""
|
||||
}
|
||||
var widths = make([]int, len(this.columns))
|
||||
var (
|
||||
widths = make([]int, len(this.columns))
|
||||
widthAcc = 0
|
||||
)
|
||||
{
|
||||
// width of title columns
|
||||
widthAcc := 0
|
||||
widthAcc = 0
|
||||
for i, c := range this.columns {
|
||||
widths[i] = cellDisplayWidth(c.Title, i, widthAcc)
|
||||
widthAcc += widths[i]
|
||||
@@ -172,7 +280,7 @@ func (this *PrettyTable) GetString(fields [][]string) string {
|
||||
}
|
||||
{
|
||||
// width of content columns
|
||||
widthAcc := 0
|
||||
widthAcc = 0
|
||||
for col := 0; ; col++ {
|
||||
cont := false
|
||||
colWidth := 0
|
||||
@@ -195,6 +303,48 @@ func (this *PrettyTable) GetString(fields [][]string) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
if maxLineWidth, ok := this.hasMaxLineWidth(); ok {
|
||||
nCols := len(this.columns)
|
||||
maxContWidth := maxLineWidth - 3*nCols - 1
|
||||
if maxContWidth < nCols {
|
||||
// ensure at least 1 ascii char print
|
||||
maxContWidth = nCols
|
||||
}
|
||||
if widthAcc > maxContWidth {
|
||||
assured := maxContWidth / len(this.columns)
|
||||
|
||||
rem := maxContWidth
|
||||
nwrap := 0
|
||||
for _, w := range widths {
|
||||
if w <= assured {
|
||||
rem -= w
|
||||
} else {
|
||||
nwrap += 1
|
||||
}
|
||||
}
|
||||
// break long lines
|
||||
widthAcc := 0
|
||||
wrapped := rem / nwrap
|
||||
wrappedRem := rem % nwrap
|
||||
for col, w := range widths {
|
||||
if w > assured {
|
||||
newW := wrapped
|
||||
if wrappedRem > 0 {
|
||||
newW += 1
|
||||
wrappedRem -= 1
|
||||
}
|
||||
this.columns[col].Title = wrapCell(this.columns[col].Title, col, widthAcc, newW)
|
||||
for _, line := range fields {
|
||||
line[col] = wrapCell(line[col], col, widthAcc, newW)
|
||||
}
|
||||
widths[col] = newW // later tabs may need correction
|
||||
widthAcc += newW
|
||||
} else {
|
||||
widthAcc += w
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var columns = make([]ptColumn, len(this.columns))
|
||||
var buf bytes.Buffer
|
||||
rowLine(&buf, widths)
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reflectutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
TAG_AMBIGUOUS_PREFIX = "yunion:ambiguous-prefix"
|
||||
TAG_DEPRECATED_BY = "yunion:deprecated-by"
|
||||
TAG_OLD_DEPRECATED_BY = "deprecated-by"
|
||||
)
|
||||
|
||||
func expandAmbiguousPrefix(fields SStructFieldValueSet) SStructFieldValueSet {
|
||||
keyIndexMap := make(map[string][]int)
|
||||
for i := range fields {
|
||||
if fields[i].Info.Ignore {
|
||||
continue
|
||||
}
|
||||
key := fields[i].Info.MarshalName()
|
||||
values, ok := keyIndexMap[key]
|
||||
if !ok {
|
||||
values = make([]int, 0, 2)
|
||||
}
|
||||
keyIndexMap[key] = append(values, i)
|
||||
}
|
||||
for _, indexes := range keyIndexMap {
|
||||
if len(indexes) > 1 {
|
||||
// ambiguous found
|
||||
for _, idx := range indexes {
|
||||
if amPrefix, ok := fields[idx].Info.Tags[TAG_AMBIGUOUS_PREFIX]; ok {
|
||||
fields[idx].Info.Name = fmt.Sprintf("%s%s", amPrefix, fields[idx].Info.Name)
|
||||
if depBy, ok := fields[idx].Info.Tags[TAG_DEPRECATED_BY]; ok {
|
||||
fields[idx].Info.Tags[TAG_DEPRECATED_BY] = fmt.Sprintf("%s%s", amPrefix, depBy)
|
||||
}
|
||||
if depBy, ok := fields[idx].Info.Tags[TAG_OLD_DEPRECATED_BY]; ok {
|
||||
fields[idx].Info.Tags[TAG_OLD_DEPRECATED_BY] = fmt.Sprintf("%s%s", amPrefix, depBy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
+45
-32
@@ -138,11 +138,11 @@ type SStructFieldValue struct {
|
||||
type SStructFieldValueSet []SStructFieldValue
|
||||
|
||||
func FetchStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet {
|
||||
return fetchStructFieldValueSet(dataValue, false, nil)
|
||||
return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, false, nil))
|
||||
}
|
||||
|
||||
func FetchStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet {
|
||||
return fetchStructFieldValueSet(dataValue, true, nil)
|
||||
return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, true, nil))
|
||||
}
|
||||
|
||||
type sStructFieldInfoMap map[string]SStructFieldInfo
|
||||
@@ -256,49 +256,62 @@ func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool, tags ma
|
||||
return fields
|
||||
}
|
||||
|
||||
func (set SStructFieldValueSet) GetStructFieldIndex(name string) int {
|
||||
for i := 0; i < len(set); i += 1 {
|
||||
jsonInfo := set[i].Info
|
||||
if jsonInfo.MarshalName() == name {
|
||||
return i
|
||||
}
|
||||
if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") {
|
||||
return i
|
||||
}
|
||||
if jsonInfo.FieldName == name {
|
||||
return i
|
||||
}
|
||||
if jsonInfo.FieldName == utils.Capitalize(name) {
|
||||
return i
|
||||
}
|
||||
func (fields SStructFieldValueSet) GetStructFieldIndex(name string) int {
|
||||
indexes := fields.GetStructFieldIndexes(name)
|
||||
if len(indexes) > 0 {
|
||||
return indexes[0]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (set SStructFieldValueSet) GetStructFieldIndexes(name string) []int {
|
||||
func (fields SStructFieldValueSet) GetStructFieldIndexes(name string) []int {
|
||||
return fields.GetStructFieldIndexes2(name, false)
|
||||
}
|
||||
|
||||
func (fields SStructFieldValueSet) GetStructFieldIndexes2(name string, strictMode bool) []int {
|
||||
ret := make([]int, 0)
|
||||
for i := 0; i < len(set); i += 1 {
|
||||
jsonInfo := set[i].Info
|
||||
if jsonInfo.MarshalName() == name {
|
||||
for i := range fields {
|
||||
if fields[i].Info.Ignore {
|
||||
continue
|
||||
}
|
||||
if fields[i].Info.MarshalName() == name {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
if utils.CamelSplit(jsonInfo.FieldName, "_") == utils.CamelSplit(name, "_") {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
if jsonInfo.FieldName == name {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
if jsonInfo.FieldName == utils.Capitalize(name) {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
if !strictMode {
|
||||
if utils.CamelSplit(fields[i].Info.FieldName, "_") == utils.CamelSplit(name, "_") {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
if fields[i].Info.FieldName == name {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
if fields[i].Info.FieldName == utils.Capitalize(name) {
|
||||
ret = append(ret, i)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (fields SStructFieldValueSet) GetStructFieldIndexesMap() map[string][]int {
|
||||
keyIndexMap := make(map[string][]int)
|
||||
for i := range fields {
|
||||
if fields[i].Info.Ignore {
|
||||
continue
|
||||
}
|
||||
key := fields[i].Info.MarshalName()
|
||||
values, ok := keyIndexMap[key]
|
||||
if !ok {
|
||||
values = make([]int, 0, 2)
|
||||
}
|
||||
keyIndexMap[key] = append(values, i)
|
||||
}
|
||||
return keyIndexMap
|
||||
}
|
||||
|
||||
func (set SStructFieldValueSet) GetValue(name string) (reflect.Value, bool) {
|
||||
idx := set.GetStructFieldIndex(name)
|
||||
if idx < 0 {
|
||||
|
||||
Reference in New Issue
Block a user