|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. |
| 4 | +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. |
| 5 | +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at https://opensource.org/licenses/MIT |
| 7 | +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
| 8 | +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| 9 | +specific language governing permissions and limitations under the License. |
| 10 | +""" |
| 11 | +from typing import Dict, List |
| 12 | + |
| 13 | +from django.db.models import ManyToManyRel |
| 14 | +from django.utils.translation import gettext_lazy as _ |
| 15 | + |
| 16 | +from backend.db_meta.models import Tag |
| 17 | +from backend.db_services.tag.constants import TagResourceType |
| 18 | +from backend.exceptions import ValidationError |
| 19 | + |
| 20 | + |
| 21 | +class TagHandler: |
| 22 | + """标签的操作类""" |
| 23 | + |
| 24 | + def batch_set_tags(self, tag_ids: List[int]): |
| 25 | + """ |
| 26 | + 给资源批量设置标签 |
| 27 | + """ |
| 28 | + # 1. 判断标签中 key 是否允许多值 |
| 29 | + |
| 30 | + # 2. 批量设置标签 |
| 31 | + pass |
| 32 | + |
| 33 | + @classmethod |
| 34 | + def delete_tags(cls, bk_biz_id: int, ids: List[int]): |
| 35 | + """ |
| 36 | + 删除标签 |
| 37 | + """ |
| 38 | + # 1. 检查标签是否被引用 |
| 39 | + related_resources = cls.query_related_resources(ids) |
| 40 | + for related_resource in related_resources: |
| 41 | + if related_resource["count"] > 0: |
| 42 | + raise ValidationError(_("标签被引用,无法删除")) |
| 43 | + |
| 44 | + # 2. 批量删除标签 |
| 45 | + Tag.objects.filter(bk_biz_id=bk_biz_id, id__in=ids).delete() |
| 46 | + |
| 47 | + @classmethod |
| 48 | + def query_related_resources(cls, ids: List[int], resource_type: str = None): |
| 49 | + """ |
| 50 | + 查询关联资源 |
| 51 | + """ |
| 52 | + # 1. 查询外键关联资源 |
| 53 | + data = [] |
| 54 | + for tag_id in ids: |
| 55 | + info = {"id": tag_id, "related_resources": []} |
| 56 | + for field in Tag._meta.get_fields(): |
| 57 | + if isinstance(field, ManyToManyRel) and (field.name == resource_type or resource_type is None): |
| 58 | + related_objs = field.related_model.objects.prefetch_related("tags").filter(tags__id=tag_id) |
| 59 | + info["related_resources"].append( |
| 60 | + { |
| 61 | + "resource_type": field.name, |
| 62 | + "count": related_objs.count(), |
| 63 | + } |
| 64 | + ) |
| 65 | + |
| 66 | + # 2. 查询第三方服务关联资源(如资源池、后续可能扩展的别的服务) |
| 67 | + if resource_type == TagResourceType.DB_RESOURCE.value or resource_type is None: |
| 68 | + info["related_resources"].append( |
| 69 | + { |
| 70 | + "resource_type": TagResourceType.DB_RESOURCE.value, |
| 71 | + # TODO 请求资源池接口得到统计数量 |
| 72 | + "count": 0, |
| 73 | + } |
| 74 | + ) |
| 75 | + data.append(info) |
| 76 | + return data |
| 77 | + |
| 78 | + @classmethod |
| 79 | + def batch_create(cls, bk_biz_id: int, tags: List[Dict[str, str]], creator: str = ""): |
| 80 | + """ |
| 81 | + 批量创建标签 |
| 82 | + """ |
| 83 | + duplicate_tags = cls.verify_duplicated(bk_biz_id, tags) |
| 84 | + if duplicate_tags: |
| 85 | + raise ValidationError(_("检查到重复的标签"), data=duplicate_tags) |
| 86 | + |
| 87 | + tag_models = [Tag(bk_biz_id=bk_biz_id, key=tag["key"], value=tag["value"], creator=creator) for tag in tags] |
| 88 | + Tag.objects.bulk_create(tag_models) |
| 89 | + |
| 90 | + @classmethod |
| 91 | + def verify_duplicated(cls, bk_biz_id: int, tags: List[Dict[str, str]]) -> List[Dict[str, str]]: |
| 92 | + """ |
| 93 | + 检查标签是否重复 |
| 94 | + """ |
| 95 | + biz_tags = [f"{tag.key}:{tag.value}" for tag in Tag.objects.filter(bk_biz_id=bk_biz_id)] |
| 96 | + duplicate_tags = [] |
| 97 | + for tag in tags: |
| 98 | + if f'{tag["key"]}:{tag["value"]}' in biz_tags: |
| 99 | + duplicate_tags.append(tag) |
| 100 | + return duplicate_tags |
0 commit comments