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: 添加ITSM上下文配置功能 #1452

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 0 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
14 changes: 8 additions & 6 deletions common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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攻击)
Expand All @@ -37,6 +36,7 @@

from common.log import logger
from common.pxfilter import XssHtml
from itsm.meta.models import ContextService


def html_escape(html, is_json=False):
Expand All @@ -56,7 +56,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
Expand All @@ -65,7 +65,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
Expand Down Expand Up @@ -101,11 +101,13 @@ 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]

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notice_receiver_filter(receivers):此方法建议转到 meta 实现,主要考虑可以优化 utils 与 ContextService 的调用依赖,最好是:utils 是基础,由 ContextService 调用 utils

context_service = ContextService()
notice_blacklist = context_service.get_context_value_list("notice_blacklist")
receivers = [i for i in receivers if i not in notice_blacklist]
return receivers if receiver_type == "list" else ",".join(receivers)
19 changes: 9 additions & 10 deletions config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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",),
}

# ==============================================================================
Expand Down Expand Up @@ -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"
)
20 changes: 17 additions & 3 deletions itsm/component/bkchat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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 ContextService
from itsm.ticket.models import Ticket, Status, TicketField, SignTask

# 当前运行环境
Expand Down Expand Up @@ -113,12 +114,25 @@ def send_fast_approval_message(title, content, receivers, ticket, state_id):

# 更新详情url
ticket.generate_ticket_url(state_id, receivers)


# 如果ticket的service_id在黑名单中则不发送bkchat快速审批通知
context_service = ContextService()
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}"
)
return

# 接收人过滤
receivers = 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 = {
Expand Down
Empty file added itsm/meta/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions itsm/meta/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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)
6 changes: 6 additions & 0 deletions itsm/meta/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class MetaConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "itsm.meta"
34 changes: 34 additions & 0 deletions itsm/meta/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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",
},
),
]
Empty file.
45 changes: 45 additions & 0 deletions itsm/meta/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from django.core.cache import cache
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver


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, 30)


class ContextService:
@staticmethod
def get_context_value(key):
cache_key = f"meta_context_{key}"
context_value = cache.get(cache_key)
if not context_value:
try:
context_value = Context.objects.get(key=key).value
except Context.DoesNotExist:
context_value = ""
cache.set(cache_key, context_value, 30)
return context_value

@staticmethod
def get_context_value_list(key):
context_value = ContextService.get_context_value(key)
context_value = (
[item.strip() for item in context_value.split(",")] if context_value else []
)
return context_value
Original file line number Diff line number Diff line change
Expand Up @@ -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 ContextService
from itsm.ticket.models import Ticket, Status
from pipeline.component_framework.component import Component

Expand Down Expand Up @@ -61,7 +62,14 @@ 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单据
context_service = ContextService()
service_approval_blacklist = context_service.get_context_value_list(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同样由 notice filter service 处理

"service_approval_blacklist"
)
if str(ticket.service_id) not in service_approval_blacklist:
ticket.create_moa_ticket(state_id)

# 如果是普通的审批节点,则自动生成条件
if not is_multi:
Expand Down