Skip to content

Commit

Permalink
feat: platform management
Browse files Browse the repository at this point in the history
  • Loading branch information
nannan00 committed Mar 26, 2024
1 parent bda8e65 commit 490dea7
Show file tree
Hide file tree
Showing 15 changed files with 617 additions and 658 deletions.
2 changes: 2 additions & 0 deletions src/bk-user/bkuser/apis/web/data_source/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ def get(self, request, *args, **kwargs):


class DataSourceRandomPasswordApi(CurrentUserTenantMixin, generics.CreateAPIView):
permission_classes = [IsAuthenticated, perm_class(PermAction.MANAGE_TENANT)]

@swagger_auto_schema(
tags=["data_source"],
operation_description="生成数据源用户随机密码",
Expand Down
Empty file.
195 changes: 195 additions & 0 deletions src/bk-user/bkuser/apis/web/platform_management/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
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.
"""
import re
from typing import Any, Dict

from django.conf import settings
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from bkuser.apps.notification.constants import NotificationMethod
from bkuser.apps.tenant.constants import TENANT_ID_REGEX, TenantStatus
from bkuser.apps.tenant.models import Tenant
from bkuser.biz.validators import validate_logo
from bkuser.common.passwd import PasswordValidator
from bkuser.common.validators import validate_phone_with_country_code
from bkuser.plugins.base import get_default_plugin_cfg
from bkuser.plugins.constants import DataSourcePluginEnum
from bkuser.plugins.local.models import LocalDataSourcePluginConfig


class TenantSearchOutputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="租户 ID")
name = serializers.CharField(help_text="租户名")
status = serializers.CharField(help_text="租户状态")
logo = serializers.SerializerMethodField(help_text="租户 Logo")
is_default = serializers.BooleanField(help_text="是否默认租户")
created_at = serializers.CharField(help_text="创建时间", source="created_at_display")

def get_logo(self, obj: Tenant) -> str:
return obj.logo or settings.DEFAULT_TENANT_LOGO


def _validate_duplicate_tenant_name(name: str, tenant_id: str = "") -> str:
"""检查租户是否重名"""
queryset = Tenant.objects.filter(name=name)
# 过滤掉自身名称
if tenant_id:
queryset = queryset.exclude(id=tenant_id)

if queryset.exists():
raise ValidationError(_("租户名 {} 已存在").format(name))

return name


def _validate_fixed_password(fixed_password: str) -> str:
cfg: LocalDataSourcePluginConfig = get_default_plugin_cfg(DataSourcePluginEnum.LOCAL) # type: ignore
ret = PasswordValidator(cfg.password_rule.to_rule()).validate(fixed_password) # type: ignore
if not ret.ok:
raise ValidationError(_("密码不符合密码规则:{}").format(ret.exception_message))

return fixed_password


def _validate_notification(notification_method: str, email: str, phone: str, phone_country_code: str):
"""通知参数校验"""
# 根据选择的通知方式,校验通知账号信息
if notification_method == NotificationMethod.EMAIL and not email:
raise ValidationError(_("选择邮箱通知方式时,邮箱不能为空"))

if notification_method == NotificationMethod.SMS:
if not phone:
raise ValidationError(_("选择短信通知方式时,手机号不能为空"))
# 校验手机号是否合法
try:
validate_phone_with_country_code(phone=phone, country_code=phone_country_code)
except ValueError as e:
raise ValidationError(str(e))


class TenantCreateInputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="租户 ID")
name = serializers.CharField(help_text="租户名称")
logo = serializers.CharField(
help_text="租户 Logo",
required=False,
allow_blank=True,
default=settings.DEFAULT_TENANT_LOGO,
validators=[validate_logo],
)
status = serializers.ChoiceField(help_text="租户状态", choices=TenantStatus.get_choices())
# [内置管理]类型的本地数据源配置
fixed_password = serializers.CharField(help_text="固定初始密码")
notification_method = serializers.ChoiceField(help_text="通知方式", choices=NotificationMethod.get_choices())
# 内置管理账号信息
email = serializers.EmailField(help_text="管理员邮箱", required=False, default="")
phone = serializers.CharField(help_text="管理员手机号", required=False, default="")
phone_country_code = serializers.CharField(
help_text="手机号国际区号", required=False, default=settings.DEFAULT_PHONE_COUNTRY_CODE
)

def validate_id(self, id: str) -> str:
if Tenant.objects.filter(id=id).exists():
raise ValidationError(_("租户 ID {} 已被使用").format(id))

if not re.fullmatch(TENANT_ID_REGEX, id):
raise ValidationError(
_(
"{} 不符合 租户 ID 的命名规范: 由3-32位字母、数字、连接符(-)字符组成,以字母开头,字母或数字结尾",
).format(id),
) # noqa: E501

return id

def validate_name(self, name: str) -> str:
return _validate_duplicate_tenant_name(name)

def validate_fixed_password(self, fixed_password: str) -> str:
return _validate_fixed_password(fixed_password)

def validate(self, attrs: Dict[str, Any]) -> Dict[str, Any]:
# 校验通知信息是否正确
_validate_notification(
attrs["notification_method"], attrs["email"], attrs["phone"], attrs["phone_country_code"]
)
return attrs


class TenantCreateOutputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="租户 ID")


class TenantRetrieveBuiltinManagementUserOutputSLZ(serializers.Serializer):
username = serializers.CharField(help_text="用户名")


class TenantRetrieveOutputSLZ(serializers.Serializer):
id = serializers.CharField(help_text="租户 ID")
name = serializers.CharField(help_text="租户名")
logo = serializers.SerializerMethodField(help_text="租户 Logo")

def get_logo(self, obj: Tenant) -> str:
return obj.logo or settings.DEFAULT_TENANT_LOGO


class TenantUpdateInputSLZ(serializers.Serializer):
name = serializers.CharField(help_text="租户名称")
logo = serializers.CharField(
help_text="租户 Logo",
required=False,
allow_blank=True,
default=settings.DEFAULT_TENANT_LOGO,
validators=[validate_logo],
)

def validate_name(self, name: str) -> str:
return _validate_duplicate_tenant_name(name, self.context["tenant_id"])


class TenantStatusUpdateOutputSLZ(serializers.Serializer):
status = serializers.CharField(help_text="租户状态")


class TenantBuiltinManagerRetrieveOutputSLZ(serializers.Serializer):
username = serializers.CharField(help_text="用户名")


class TenantRelatedResourceStatsOutputSLZ(serializers.Serializer):
data_source_count = serializers.IntegerField(help_text="数据源数量")
data_source_user_count = serializers.IntegerField(help_text="数据源用户数量")
data_source_department_count = serializers.IntegerField(help_text="数据源部门数量")
tenant_count = serializers.IntegerField(help_text="关联租户数量(含归属 / 协同)")
tenant_user_count = serializers.IntegerField(help_text="租户用户数量")
tenant_department_count = serializers.IntegerField(help_text="租户部门数量")


class TenantBuiltinManagerUpdateOutputSLZ(serializers.Serializer):
# [内置管理]类型的本地数据源配置
fixed_password = serializers.CharField(help_text="固定初始密码")
notification_method = serializers.ChoiceField(help_text="通知方式", choices=NotificationMethod.get_choices())
# 内置管理账号信息
email = serializers.EmailField(help_text="管理员邮箱", required=False, default="")
phone = serializers.CharField(help_text="管理员手机号", required=False, default="")
phone_country_code = serializers.CharField(
help_text="手机号国际区号", required=False, default=settings.DEFAULT_PHONE_COUNTRY_CODE
)

def validate_fixed_password(self, fixed_password: str) -> str:
return _validate_fixed_password(fixed_password)

def validate(self, attrs: Dict[str, Any]) -> Dict[str, Any]:
# 校验通知信息是否正确
_validate_notification(
attrs["notification_method"], attrs["email"], attrs["phone"], attrs["phone_country_code"]
)
return attrs
39 changes: 39 additions & 0 deletions src/bk-user/bkuser/apis/web/platform_management/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
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.
"""
from django.urls import include, path

from . import views

urlpatterns = [
# 租户管理
path(
"tenants/",
include(
[
path("", views.TenantListCreateApi.as_view(), name="tenant.list_create"),
path(
"<str:id>/", views.TenantRetrieveUpdateDestroyApi.as_view(), name="tenant.retrieve_update_destroy"
),
path("<str:id>/status/", views.TenantStatusUpdateApi.as_view(), name="tenant.update_status"),
path(
"<str:id>/builtin-manager/",
views.TenantBuiltinManagerRetrieveUpdateApi.as_view(),
name="tenant.retrieve_update_builtin_manager",
),
path(
"<str:id>/related-resource-statistics/",
views.TenantRelatedResourceStatsApi.as_view(),
name="tenant.related_resource_stats",
),
]
),
),
]
Loading

0 comments on commit 490dea7

Please sign in to comment.