Skip to content

Commit

Permalink
feat: add list_profile / retrieve_profile / list_department_profile a…
Browse files Browse the repository at this point in the history
…pi (#1528)
  • Loading branch information
nannan00 authored Jan 19, 2024
1 parent 136baf1 commit 6b861ed
Show file tree
Hide file tree
Showing 9 changed files with 671 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/bk-user/bkuser/apis/login/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class LocalUserCredentialAuthenticateApi(LoginApiAccessControlMixin, generics.Cr
"""本地数据源用户的凭据认证"""

def post(self, request, *args, **kwargs):
# TODO: 所有报错都添加日志,便于后续排查
slz = LocalUserCredentialAuthenticateInputSLZ(data=request.data)
slz.is_valid(raise_exception=True)
data = slz.validated_data
Expand Down
93 changes: 93 additions & 0 deletions src/bk-user/bkuser/apis/open_v2/serializers/profilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,96 @@
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 typing import List

from rest_framework import serializers

from bkuser.common.serializers import StringArrayField


class ProfileFieldsSLZ(serializers.Serializer):
"""用户字段校验"""

fields = StringArrayField(help_text="指定返回的用户字段", required=False)

def validated_fields(self, fields: List[str]) -> List[str]:
# 不再支持返回的字段:
# [基本] code, qq
# [登录&密码相关] password_valid_days, password_update_time, last_login_time, account_expiration_date,
# [时间相关] create_time, update_time
# 总返回固定值字段:logo, type, role
allowed_fields = {
# 基础字段
"id",
"username",
"display_name", # 目前返回值是姓名,即 full_name,后续根据表达式展示
"email",
"telephone",
"country_code",
"iso_code",
"time_zone",
"language",
"extras",
# 微信消息通知相关
"wx_userid",
"wx_openid",
# 原目录相关
"domain",
"category_id",
# 生命周期相关
"status",
"staff_status",
"enabled",
# 关联关系
"departments",
"leader",
}

# 忽略无效的指定字段
return list(set(fields) & allowed_fields)


class ProfileRetrieveInputSLZ(ProfileFieldsSLZ):
lookup_field = serializers.ChoiceField(
help_text="指定路径参数值的字段", choices=["id", "username"], required=False, default="username"
)
include_disabled = serializers.BooleanField(help_text="是否包含软删除用户", required=False, default=False)


class ProfileListInputSLZ(ProfileFieldsSLZ):
lookup_field = serializers.ChoiceField(
help_text="字段名称",
choices=[
"id",
"username",
"display_name",
"email",
"telephone",
# 微信消息通知相关
"wx_userid",
# 原目录相关
"domain",
"category_id",
# 生命周期相关
"status",
"staff_status",
"enabled",
# IAM 特有
"create_time",
],
required=False,
)
exact_lookups = StringArrayField(help_text="精确匹配字段", required=False)
fuzzy_lookups = StringArrayField(help_text="模糊匹配字段", required=False)
include_disabled = serializers.BooleanField(help_text="是否包含软删除用户", required=False, default=False)
no_page = serializers.BooleanField(help_text="全量返回", required=False, default=False)


class DepartmentProfileListInputSLZ(serializers.Serializer):
recursive = serializers.BooleanField(help_text="是否递归", required=False, default=False)
include_disabled = serializers.BooleanField(help_text="是否包含软删除部门", required=False, default=False)
no_page = serializers.BooleanField(help_text="全量返回", required=False, default=False)


class ProfileLanguageUpdateInputSLZ(serializers.Serializer):
language = serializers.ChoiceField(help_text="需设置的语言", choices=["zh-cn", "en"])
6 changes: 6 additions & 0 deletions src/bk-user/bkuser/apis/open_v2/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,10 @@
views.DepartmentProfileListApi.as_view(),
name="open_v2.list_department_profiles",
),
# 更新用户语言
path(
"profiles/<str:username>/languages/",
views.ProfileLanguageUpdateApi.as_view(),
name="open_v2.update_profile_language",
),
]
3 changes: 2 additions & 1 deletion src/bk-user/bkuser/apis/open_v2/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .categories import CategoriesListApi
from .departments import DepartmentChildrenListApi, DepartmentListApi, DepartmentRetrieveApi, ProfileDepartmentListApi
from .edges import DepartmentProfileRelationListApi, ProfileLeaderRelationListApi
from .profilers import DepartmentProfileListApi, ProfileListApi, ProfileRetrieveApi
from .profilers import DepartmentProfileListApi, ProfileLanguageUpdateApi, ProfileListApi, ProfileRetrieveApi

__all__ = [
# 目录类
Expand All @@ -29,4 +29,5 @@
"ProfileListApi",
"ProfileRetrieveApi",
"DepartmentProfileListApi",
"ProfileLanguageUpdateApi",
]
22 changes: 14 additions & 8 deletions src/bk-user/bkuser/apis/open_v2/views/departments.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
DataSourceDepartmentUserRelation,
)
from bkuser.apps.tenant.models import TenantDepartment, TenantUser
from bkuser.common.error_codes import error_codes
from bkuser.utils.tree import Tree


Expand All @@ -42,12 +43,17 @@ def get(self, request, *args, **kwargs):
slz = DepartmentListInputSLZ(data=request.query_params)
slz.is_valid(raise_exception=True)
params = slz.validated_data
no_page = params["no_page"]

tenant_depts = self._filter_queryset(params)
if not params["no_page"]:
if not no_page:
tenant_depts = self.paginate_queryset(tenant_depts)

return Response(self._build_dept_infos(tenant_depts, params.get("fields", []), params["with_ancestors"]))
dept_infos = self._build_dept_infos(tenant_depts, params.get("fields", []), params["with_ancestors"])
if not no_page:
return self.get_paginated_response(dept_infos)

return Response(dept_infos)

def _build_dept_infos(
self, tenant_depts: QuerySet[TenantDepartment], fields: List[str], with_ancestors: bool
Expand Down Expand Up @@ -160,11 +166,11 @@ def _convert_lookup_field(lookup_field: str) -> str:
return "data_source_department__department_relation__parent"
if lookup_field == "enabled":
# FIXME 支持 enabled 参数
raise ValueError("lookup field enabled is not supported now")
raise error_codes.VALIDATION_ERROR.f("lookup field enabled is not supported now")
if lookup_field == "level":
return "data_source_department__department_relation__level"

raise ValueError(f"unsupported lookup field: {lookup_field}")
raise error_codes.VALIDATION_ERROR.f(f"unsupported lookup field: {lookup_field}")


class DepartmentRetrieveApi(LegacyOpenApiCommonMixin, generics.RetrieveAPIView):
Expand Down Expand Up @@ -216,7 +222,7 @@ def get(self, request, *args, **kwargs):
resp_data["parent"] = self._get_dept_parent_id(tenant_dept, dept_relation)
resp_data["level"] = self._get_dept_tree_level(dept_relation)

tenant_dept_full_name = self._get_dept_full_name(dept_relation)
tenant_dept_full_name = self._get_dept_full_name(tenant_dept, dept_relation)
children = self._get_dept_children(tenant_dept, tenant_dept_full_name)
resp_data["full_name"] = tenant_dept_full_name
resp_data["has_children"] = bool(children)
Expand All @@ -228,11 +234,11 @@ def get(self, request, *args, **kwargs):
return Response(resp_data)

@staticmethod
def _get_dept_full_name(dept_relation: DataSourceDepartmentRelation) -> str:
def _get_dept_full_name(tenant_dept: TenantDepartment, dept_relation: DataSourceDepartmentRelation) -> str:
"""获取部门组织路径信息"""
# TODO 考虑协同的情况,不能直接吐出到根部门的路径
if not dept_relation:
return ""
return tenant_dept.data_source_department.name

return "/".join(dept_relation.get_ancestors(include_self=True).values_list("department__name", flat=True))

Expand Down Expand Up @@ -430,7 +436,7 @@ def _get_dept_full_name(dept: DataSourceDepartment) -> str:
"""获取部门组织路径信息"""
dept_relation = DataSourceDepartmentRelation.objects.filter(department=dept).first()
if not dept_relation:
return ""
return dept.name

# TODO 考虑协同的情况,不能直接吐出到根部门的路径
return "/".join(dept_relation.get_ancestors(include_self=True).values_list("department__name", flat=True))
Loading

0 comments on commit 6b861ed

Please sign in to comment.