Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bkuser_core, bkuser_core/api/web): 新增回收站展示视图 #941

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/api/bkuser_core/api/web/global_settings/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
specific language governing permissions and limitations under the License.
"""

from rest_framework import generics, status
from rest_framework import generics
from rest_framework.response import Response

from bkuser_core.api.web.global_settings.serialziers import GlobalSettingOutputSLZ, GlobalSettingUpdateInputSLZ
Expand All @@ -36,4 +36,4 @@ def put(self, request, *args, **kwargs):
item.value = ns_settings[key]
item.save()

return Response(status=status.HTTP_204_NO_CONTENT)
return Response()
10 changes: 10 additions & 0 deletions src/api/bkuser_core/api/web/recycle_bin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# -*- 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.
"""
97 changes: 97 additions & 0 deletions src/api/bkuser_core/api/web/recycle_bin/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# -*- 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 rest_framework import serializers

from bkuser_core.departments.models import Department
from bkuser_core.profiles.models import Profile
from bkuser_core.recycle_bin.models import RecycleBin


class RecycleBinSearchInputSlZ(serializers.Serializer):
keyword = serializers.CharField(required=False, help_text="搜索关键词")


class RecycleBinCategoryOutputSlZ(serializers.ModelSerializer):
category = serializers.SerializerMethodField(help_text="目录基础信息")
profile_count = serializers.SerializerMethodField(help_text="目录下人员数量")
department_count = serializers.SerializerMethodField(help_text="目录下部门数量")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_category(self, instance):
neronkl marked this conversation as resolved.
Show resolved Hide resolved
category = self.context["category_map"][instance.object_id]
return {
"id": category.id,
"display_name": category.display_name,
"domain": category.domain,
"type": category.type,
}

def get_profile_count(self, instance):
return Profile.objects.filter(category_id=instance.object_id).count()

def get_department_count(self, instance):
return Department.objects.filter(category_id=instance.object_id).count()

class Meta:
model = RecycleBin
fields = ["id", "expires", "category", "profile_count", "department_count", "operator"]


class RecycleBinDepartmentOutputSlZ(serializers.ModelSerializer):
category_display_name = serializers.SerializerMethodField(help_text="所属目录名称")
department = serializers.SerializerMethodField(help_text="部门基础信息")
profile_count = serializers.SerializerMethodField(help_text="部门下人员数量")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_department(self, instance):
neronkl marked this conversation as resolved.
Show resolved Hide resolved
department = self.context["department_map"][instance.object_id]
return {
"id": department.id,
"name": department.name,
"parent_name": department.parent.name if department.parent else "",
"children_count": department.children.all().count(),
}

def get_category_display_name(self, instance):
department = self.context["department_map"][instance.object_id]
return self.context["category_display_name_map"][department.category_id]

def get_profile_count(self, instance):
return self.context["department_map"][instance.object_id].profiles.count()

class Meta:
model = RecycleBin
fields = ["id", "expires", "category_display_name", "department", "profile_count", "operator"]


class RecycleBinProfileOutputSlZ(serializers.ModelSerializer):
category_display_name = serializers.SerializerMethodField(help_text="所属目录信息")
profile = serializers.SerializerMethodField(help_text="人员基础信息")
expires = serializers.IntegerField(help_text="过期剩余天数")

def get_profile(self, instance):
neronkl marked this conversation as resolved.
Show resolved Hide resolved
profile = self.context["profile_map"][instance.object_id]
return {
"id": profile.id,
"username": profile.username,
"domain": profile.domain,
"display_name": profile.display_name,
"department": profile.departments.values("id", "name"),
}

def get_category_display_name(self, instance):
profile = self.context["profile_map"][instance.object_id]
return self.context["category_display_name_map"][profile.category_id]

class Meta:
model = RecycleBin
fields = ["id", "expires", "category_display_name", "profile", "operator"]
33 changes: 33 additions & 0 deletions src/api/bkuser_core/api/web/recycle_bin/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- 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.conf import path

from . import views

urlpatterns = [
path(
"categories/",
views.RecycleBinCategoryListApi.as_view(),
name="recycle_bin.category.list",
),
path(
"departments/",
views.RecycleBinDepartmentListApi.as_view(),
name="recycle_bin.department.list",
),
path(
"profiles/",
views.RecycleBinProfileListApi.as_view(),
name="recycle_bin.profile.list",
),
neronkl marked this conversation as resolved.
Show resolved Hide resolved
]
171 changes: 171 additions & 0 deletions src/api/bkuser_core/api/web/recycle_bin/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# -*- 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.db.models import Q
from rest_framework import generics

from bkuser_core.api.web.recycle_bin.serializers import (
RecycleBinCategoryOutputSlZ,
RecycleBinDepartmentOutputSlZ,
RecycleBinProfileOutputSlZ,
RecycleBinSearchInputSlZ,
)
from bkuser_core.api.web.utils import get_category_display_name_map
from bkuser_core.api.web.viewset import CustomPagination
from bkuser_core.categories.constants import CategoryStatus
from bkuser_core.categories.models import ProfileCategory
from bkuser_core.departments.models import Department
from bkuser_core.profiles.constants import ProfileStatus
from bkuser_core.profiles.models import Profile
from bkuser_core.recycle_bin.constants import RecycleBinObjectType
from bkuser_core.recycle_bin.models import RecycleBin


class RecycleBinCategoryListApi(generics.ListAPIView):
"""
回收站:目录展示
"""

serializer_class = RecycleBinCategoryOutputSlZ
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.CATEGORY.value)
pagination_class = CustomPagination

def get_queryset(self):
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
category_ids = ProfileCategory.objects.filter(
Q(domain__icontains=keyword) | Q(display_name__icontains=keyword),
enabled=False,
status=CategoryStatus.INACTIVE.value,
).values_list("id", flat=True)
queryset = queryset.filter(object_id__in=category_ids)
return queryset.all()

def get_serializer_context(self):
output_slz_context = super(RecycleBinCategoryListApi, self).get_serializer_context()
categories = ProfileCategory.objects.all()
category_map: dict = {}
for category in categories:
category_map[category.id] = category

output_slz_context.update(
{
"category_map": category_map,
}
)
return output_slz_context


class RecycleBinDepartmentListApi(generics.ListAPIView):
"""
回收站:组织展示
"""

serializer_class = RecycleBinDepartmentOutputSlZ
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.DEPARTMENT.value)
pagination_class = CustomPagination

def get_queryset(self):
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
department_ids = Department.objects.filter(name__icontains=keyword, enabled=False).values_list(
"id", flat=True
)
queryset = queryset.filter(object_id__in=department_ids)
return queryset.all()

def get_serializer_context(self):
output_slz_context = super(RecycleBinDepartmentListApi, self).get_serializer_context()

queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if not page:
return output_slz_context

department_ids = [item.object_id for item in page]

departments = Department.objects.filter(id__in=department_ids)

department_map: dict = {}
for department in departments:
department_map[department.id] = department

category_display_name_map = get_category_display_name_map()

output_slz_context.update(
{
"category_display_name_map": category_display_name_map,
"department_map": department_map,
}
)
return output_slz_context


class RecycleBinProfileListApi(generics.ListAPIView):
"""
回收站:人员展示
"""

serializer_class = RecycleBinProfileOutputSlZ
queryset = RecycleBin.objects.filter(object_type=RecycleBinObjectType.PROFILE.value)
pagination_class = CustomPagination

def get_queryset(self):
input_slz = RecycleBinSearchInputSlZ(data=self.request.query_params)
input_slz.is_valid(raise_exception=True)
data = input_slz.validated_data

keyword = data.get("keyword")
queryset = self.queryset
# TODO 此处通过大表模糊查询,获取小表对象,待更好的方案进行优化
if keyword:
profile_ids = Profile.objects.filter(
Q(username__icontains=keyword) | Q(display_name__icontains=keyword),
enabled=False,
status=ProfileStatus.DELETED.value,
).values_list("id", flat=True)
queryset = queryset.filter(object_id__in=profile_ids)
neronkl marked this conversation as resolved.
Show resolved Hide resolved
return queryset.all()

def get_serializer_context(self):
output_slz_context = super(RecycleBinProfileListApi, self).get_serializer_context()

queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if not page:
return output_slz_context

profile_ids = [item.object_id for item in page]

profiles = Profile.objects.filter(id__in=profile_ids)
profile_map: dict = {}
for profile in profiles:
profile_map[profile.id] = profile
category_display_name_map = get_category_display_name_map()

output_slz_context.update(
{
"category_display_name_map": category_display_name_map,
"profile_map": profile_map,
}
)
return output_slz_context
1 change: 1 addition & 0 deletions src/api/bkuser_core/api/web/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
url(r"^site/", include("bkuser_core.api.web.site.urls")),
url(r"^departments/", include("bkuser_core.api.web.department.urls")),
url(r"^passwords/", include("bkuser_core.api.web.password.urls")),
url(r"^recycle_bin/", include("bkuser_core.api.web.recycle_bin.urls")),
# 通用检索
url(r"^search/", include("bkuser_core.api.web.search.urls")),
# 首页
Expand Down
1 change: 1 addition & 0 deletions src/api/bkuser_core/config/common/django_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"bkuser_core.audit",
"bkuser_core.categories",
"bkuser_core.bkiam",
"bkuser_core.recycle_bin",
# 数据库字段翻译,需要后置于需要翻译的 Django App
"modeltranslation",
# apigateway sdk
Expand Down
10 changes: 10 additions & 0 deletions src/api/bkuser_core/recycle_bin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# -*- 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.
"""
17 changes: 17 additions & 0 deletions src/api/bkuser_core/recycle_bin/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- 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.apps import AppConfig


class ProfileConfig(AppConfig):
name = "bkuser_core.recycle_bin"
21 changes: 21 additions & 0 deletions src/api/bkuser_core/recycle_bin/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- 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 enum import auto

from bkuser_core.common.enum import AutoNameEnum


class RecycleBinObjectType(AutoNameEnum):
CATEGORY = auto()
DEPARTMENT = auto()
PROFILE = auto()

_choices_labels = ((CATEGORY, "用户目录"), (DEPARTMENT, "部门组织"), (PROFILE, "人员"))
Loading