diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8906b81e..3689787c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,10 +19,3 @@ repos: - id: commitlint stages: [commit-msg] additional_dependencies: ['@commitlint/config-conventional'] - - repo: local - hooks: - - id: check-migrate - name: check migrate - entry: python scripts/check_migrate/check_migrate.py - language: system - types: [python] diff --git a/common/utils.py b/common/utils.py index 29c128c5..f74bad20 100644 --- a/common/utils.py +++ b/common/utils.py @@ -22,7 +22,6 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from django.conf import settings # 开发框架公用方法 # 1. 页面输入内容转义(防止xss攻击) @@ -56,7 +55,7 @@ def html_escape(html, is_json=False): html = html.replace(">", ">") # 单双引号转换 if not is_json: - html = html.replace(' ', " ") + html = html.replace(" ", " ") html = html.replace('"', """) html = html.replace("'", "'") return html @@ -65,7 +64,7 @@ def html_escape(html, is_json=False): def url_escape(url): url = url.replace("<", "") url = url.replace(">", "") - url = url.replace(' ', "") + url = url.replace(" ", "") url = url.replace('"', "") url = url.replace("'", "") return url @@ -93,19 +92,3 @@ def texteditor_escape(str_escape, is_support_img=True): def cmp(a, b): """适配py2的cmp方法""" return (a > b) - (a < b) - - -def notice_receiver_filter(receivers): - """ - 通知名单过滤 - """ - if not receivers: - return receivers - - receiver_type = "list" - if isinstance(receivers, str): - receiver_type = "str" - receivers = receivers.strip().split(",") - - receivers = [i for i in receivers if i not in settings.NOTICE_IGNORE_LIST] - return receivers if receiver_type == "list" else ",".join(receivers) diff --git a/config/default.py b/config/default.py index b716fc76..12a82dbf 100644 --- a/config/default.py +++ b/config/default.py @@ -25,7 +25,6 @@ import base64 import datetime import importlib -import os from urllib.parse import urljoin, urlparse from blueapps.conf.default_settings import * # noqa @@ -110,7 +109,8 @@ "blueapps.opentelemetry.instrument_app", "itsm.plugin_service", "bk_notice_sdk", - "pipeline.contrib.engine_admin" + "pipeline.contrib.engine_admin", + "itsm.meta", ) INSTALLED_APPS = ("itsm.helper",) + INSTALLED_APPS @@ -350,7 +350,7 @@ def _(s): "rest_framework.parsers.FormParser", "rest_framework.parsers.MultiPartParser", ), - "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",) + "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",), } # ============================================================================== @@ -959,16 +959,15 @@ def redirect_func(request): # 公共配置 -BK_SHARED_RES_URL = os.getenv("BKPAAS_SHARED_RES_URL") or os.getenv("BKAPP_SHARED_RES_URL") +BK_SHARED_RES_URL = os.getenv("BKPAAS_SHARED_RES_URL") or os.getenv( + "BKAPP_SHARED_RES_URL" +) BK_PLATFORM_NAME = os.getenv("BKAPP_PLATFORM_NAME", "") -# 通知过滤 -NOTICE_IGNORE_LIST = os.getenv("BKAPP_NOTICE_IGNORE_LIST", []) -if isinstance(NOTICE_IGNORE_LIST, str): - NOTICE_IGNORE_LIST = [i.lower().strip() for i in NOTICE_IGNORE_LIST.split(",")] - # SMS 邀请评价限额 TICKET_INVITE_SMS_COUNT = int(os.getenv("BKAPP_TICKET_INVITE_SMS_COUNT", 10)) # eri admin -PIPELINE_ENGINE_ADMIN_API_PERMISSION = "itsm.helper.permissions.check_permission_success" +PIPELINE_ENGINE_ADMIN_API_PERMISSION = ( + "itsm.helper.permissions.check_permission_success" +) diff --git a/itsm/component/bkchat/utils.py b/itsm/component/bkchat/utils.py index a49b9377..04a22920 100644 --- a/itsm/component/bkchat/utils.py +++ b/itsm/component/bkchat/utils.py @@ -6,11 +6,11 @@ from django.http import JsonResponse from common.log import logger -from common.utils import notice_receiver_filter from config.default import CLOSE_NOTIFY from itsm.component.constants import APPROVE_RESULT, API, RUNNING, SHOW_BY_CONDITION from itsm.component.exceptions import ComponentCallError from itsm.component.utils.conversion import show_conditions_validate, format_exp_value +from itsm.meta.models import context_service from itsm.ticket.models import Ticket, Status, TicketField, SignTask # 当前运行环境 @@ -113,12 +113,24 @@ def send_fast_approval_message(title, content, receivers, ticket, state_id): # 更新详情url ticket.generate_ticket_url(state_id, receivers) - + + # 如果ticket的service_id在黑名单中则不发送bkchat快速审批通知 + service_approval_blacklist = context_service.get_context_value_list( + key="service_approval_blacklist" + ) + if str(ticket.service_id) in service_approval_blacklist: + logger.info( + f"[fast_approval] service id is in service_approval_blacklist, ticket_id=>{ticket_id}" + ) + return + # 接收人过滤 - receivers = notice_receiver_filter(receivers) + receivers = context_service.notice_receiver_filter(receivers) if not receivers: - logger.info(f"[fast approval] receivers is empty after filter, ticket_id=>{ticket_id}") - return + logger.info( + f"[fast approval] receivers is empty after filter, ticket_id=>{ticket_id}" + ) + return # 构造data信息 data = { diff --git a/itsm/component/notify.py b/itsm/component/notify.py index ad31c2c8..b9976b8f 100644 --- a/itsm/component/notify.py +++ b/itsm/component/notify.py @@ -29,18 +29,18 @@ from django.utils.translation import ugettext as _ from common.log import logger -from common.utils import notice_receiver_filter from itsm.component.constants import GENERAL_NOTICE from itsm.component.esb.esbclient import client_backend from itsm.component.exceptions import ComponentCallError from itsm.component.utils.basic import merge_dict_list +from itsm.meta.models import context_service from weixin.core.settings import WEIXIN_APP_EXTERNAL_HOST class BaseNotifier(object): def __init__(self, title, receivers, message, notify_type=GENERAL_NOTICE): self.title = title - self.receivers = notice_receiver_filter(receivers) + self.receivers = context_service.notice_receiver_filter(receivers) self.message = message self.notify_type = notify_type diff --git a/itsm/meta/__init__.py b/itsm/meta/__init__.py new file mode 100644 index 00000000..7525a6a4 --- /dev/null +++ b/itsm/meta/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" diff --git a/itsm/meta/admin.py b/itsm/meta/admin.py new file mode 100644 index 00000000..50b69151 --- /dev/null +++ b/itsm/meta/admin.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +from django.contrib import admin +from .models import Context + + +class ContextAdmin(admin.ModelAdmin): + list_display = ("id", "key", "value", "created_at", "updated_at") + search_fields = ("key", "value") + list_filter = ("key",) + + +admin.site.register(Context, ContextAdmin) diff --git a/itsm/meta/apps.py b/itsm/meta/apps.py new file mode 100644 index 00000000..5c6283b4 --- /dev/null +++ b/itsm/meta/apps.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +from django.apps import AppConfig + + +class MetaConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "itsm.meta" diff --git a/itsm/meta/migrations/0001_initial.py b/itsm/meta/migrations/0001_initial.py new file mode 100644 index 00000000..daf5f1e0 --- /dev/null +++ b/itsm/meta/migrations/0001_initial.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +# Generated by Django 3.2.25 on 2024-12-06 14:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Context", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("key", models.CharField(max_length=255, unique=True)), + ("value", models.TextField(blank=True)), + ], + options={ + "db_table": "meta_context", + }, + ), + ] diff --git a/itsm/meta/migrations/__init__.py b/itsm/meta/migrations/__init__.py new file mode 100644 index 00000000..7525a6a4 --- /dev/null +++ b/itsm/meta/migrations/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" diff --git a/itsm/meta/models.py b/itsm/meta/models.py new file mode 100644 index 00000000..068140b9 --- /dev/null +++ b/itsm/meta/models.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making BK-ITSM 蓝鲸流程服务 available. + +Copyright (C)2024 THL A29 Limited, a Tencent company. All rights reserved. + +BK-ITSM 蓝鲸流程服务 is licensed under the MIT License. + +License for BK-ITSM 蓝鲸流程服务: +-------------------------------------------------------------------- +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +from django.core.cache import cache +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver +from common.log import logger + +CACHE_TIMEOUT = 30 # 缓存过期时间 + + +class Context(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + key = models.CharField(max_length=255, unique=True) + value = models.TextField(blank=True) + + def __str__(self): + return self.key + + class Meta: + db_table = "meta_context" + + +@receiver(post_save, sender=Context) +def update_cache(sender, instance, **kwargs): + cache_key = f"meta_context_{instance.key}" + cache.set(cache_key, instance.value, CACHE_TIMEOUT) + + +class ContextService: + @staticmethod + def get_context_value(key): + """返回str类型的context_value""" + cache_key = f"meta_context_{key}" + context_value = cache.get(cache_key) + if context_value is None: + try: + context_value = Context.objects.get(key=key).value + except Context.DoesNotExist: + logger.info(f"key为'{key}'的上下文配置不存在") + context_value = "" + cache.set(cache_key, context_value, CACHE_TIMEOUT) + return context_value + + @staticmethod + def get_context_value_list(key): + """返回list类型的context_value""" + context_value = ContextService.get_context_value(key) + + if context_value: + # 分割字符串,去除空白字符,并去重 + unique_values = list(set(item.strip() for item in context_value.split(","))) + return unique_values + return [] + + @staticmethod + def notice_receiver_filter(receivers): + """通知名单过滤""" + if not receivers: + return receivers + + if isinstance(receivers, str): + receivers = receivers.strip().split(",") + + # 对黑名单的内容进行去重 + notice_blacklist = ContextService.get_context_value_list("notice_blacklist") + filtered_receivers = [i for i in receivers if i not in notice_blacklist] + return ( + filtered_receivers + if isinstance(receivers, list) + else ",".join(filtered_receivers) + ) + + +context_service = ContextService() diff --git a/itsm/pipeline_plugins/components/collections/itsm_approval_node.py b/itsm/pipeline_plugins/components/collections/itsm_approval_node.py index 70543d35..0ba586b0 100644 --- a/itsm/pipeline_plugins/components/collections/itsm_approval_node.py +++ b/itsm/pipeline_plugins/components/collections/itsm_approval_node.py @@ -28,6 +28,7 @@ from django.conf import settings from django.core.cache import cache from itsm.component.constants import PROCESS_COUNT +from itsm.meta.models import context_service from itsm.ticket.models import Ticket, Status from pipeline.component_framework.component import Component @@ -61,7 +62,13 @@ def execute(self, data, parent_data): ) is_multi = ticket.flow.get_state(state_id)["is_multi"] user_count = str(self.get_user_count(ticket_id, state_id)) if is_multi else "1" - ticket.create_moa_ticket(state_id) + + # 如果service_id不在service_approval_blacklist中,则创建moa单据 + service_approval_blacklist = context_service.get_context_value_list( + "service_approval_blacklist" + ) + if str(ticket.service_id) not in service_approval_blacklist: + ticket.create_moa_ticket(state_id) # 如果是普通的审批节点,则自动生成条件 if not is_multi: