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: 流程市场共享模板查看 #7626 #7630

7 changes: 7 additions & 0 deletions config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"gcloud.contrib.develop",
"gcloud.contrib.collection",
"gcloud.contrib.operate_record",
"gcloud.contrib.template_market",
"gcloud.apigw",
"gcloud.common_template",
"gcloud.label",
Expand Down Expand Up @@ -883,3 +884,9 @@ def check_engine_admin_permission(request, *args, **kwargs):
if "BKAPP_SOPS_BROKER_URL" in os.environ:
BROKER_URL = os.getenv("BKAPP_SOPS_BROKER_URL")
print(f"BROKER_URL: {BROKER_URL}")


# 流程商店
ENABLE_TEMPLATE_MARKET = env.ENABLE_TEMPLATE_MARKET
# 流程商店 API 地址
TEMPLATE_MARKET_API_URL = env.TEMPLATE_MARKET_API_URL
10 changes: 5 additions & 5 deletions config/urls_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
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 permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from django.conf.urls import include, url
from django.conf import settings

from django.conf.urls import include, url
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions

# 用户自定义 urlconf
urlpatterns_custom = [
Expand All @@ -41,6 +40,7 @@
url(r"^plugin_service/", include("plugin_service.urls")),
url(r"^mako_operations/", include("gcloud.mako_template_helper.urls")),
url(r"^engine_admin/", include("pipeline.contrib.engine_admin.urls")),
url(r"^template_market/", include("gcloud.contrib.template_market.urls")),
]

schema_view = get_schema_view(
Expand Down
5 changes: 5 additions & 0 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,8 @@
# bk_audit
BK_AUDIT_ENDPOINT = os.getenv("BK_AUDIT_ENDPOINT", None)
BK_AUDIT_DATA_TOKEN = os.getenv("BK_AUDIT_DATA_TOKEN", None)

# 流程商店
ENABLE_TEMPLATE_MARKET = False if os.getenv("ENABLE_TEMPLATE_MARKET") is None else True
# 流程商店 API 地址
TEMPLATE_MARKET_API_URL = os.getenv("TEMPLATE_MARKET_API_URL", "")
24 changes: 24 additions & 0 deletions gcloud/apigw/management/commands/data/api-resources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -757,3 +757,27 @@ paths:
authConfig:
userVerifiedRequired: true
disabledStages: []
/copy_template_across_project/{project_id}/:
post:
operationId: copy_template_across_project
description: 跨业务复制模板
tags:
- 通用接口
guohelu marked this conversation as resolved.
Show resolved Hide resolved
responses:
default:
description: ''
x-bk-apigateway-resource:
isPublic: true
guohelu marked this conversation as resolved.
Show resolved Hide resolved
allowApplyPermission: true
guohelu marked this conversation as resolved.
Show resolved Hide resolved
matchSubpath: false
backend:
type: HTTP
method: post
path: /{env.api_sub_path}apigw/copy_template_across_project/{project_id>}/
matchSubpath: false
timeout: 0
upstreams: {}
transformHeaders: {}
authConfig:
userVerifiedRequired: true
disabledStages: []
2 changes: 2 additions & 0 deletions gcloud/apigw/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from gcloud.apigw.views.register_project import register_project
from gcloud.apigw.views.set_periodic_task_enabled import set_periodic_task_enabled
from gcloud.apigw.views.start_task import start_task
from gcloud.apigw.views.copy_template_across_project import copy_template_across_project

urlpatterns = [
url(r"^dispatch_plugin_query/$", dispatch_plugin_query),
Expand Down Expand Up @@ -129,4 +130,5 @@
url(r"^create_clocked_task/(?P<template_id>\d+)/(?P<project_id>\d+)/$", create_clocked_task),
url(r"^get_mini_app_list/(?P<project_id>\d+)/$", get_mini_app_list),
url(r"^get_task_count/(?P<project_id>\d+)/$", get_task_count),
url(r"^copy_template_across_project/(?P<project_id>\d+)/$", copy_template_across_project),
]
28 changes: 28 additions & 0 deletions gcloud/apigw/validators/copy_template_across_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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.
"""
import json

from gcloud.utils.validate import ObjectJsonBodyValidator


class CopyTemplateAcrossProjectValidator(ObjectJsonBodyValidator):
def validate(self, request, *args, **kwargs):
valid, err = super().validate(request, *args, **kwargs)

if not valid:
return valid, err

if not json.loads(request.body).get("new_project_id") or not json.loads(request.body).get("template_id"):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
return False, "new_project_id and template_id is required"
guohelu marked this conversation as resolved.
Show resolved Hide resolved

return True, ""
guohelu marked this conversation as resolved.
Show resolved Hide resolved
70 changes: 70 additions & 0 deletions gcloud/apigw/views/copy_template_across_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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.
"""

import ujson as json
guohelu marked this conversation as resolved.
Show resolved Hide resolved
from apigw_manager.apigw.decorators import apigw_require
from blueapps.account.decorators import login_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

from gcloud import err_code
from gcloud.apigw.decorators import (
mark_request_whether_is_trust,
project_inject,
return_json_response,
)

from gcloud.apigw.views.utils import logger
from gcloud.tasktmpl3.models import TaskTemplate
from gcloud.template_base.utils import format_import_result_to_response_data
from gcloud.utils.decorators import request_validate
from gcloud.apigw.validators.copy_template_across_project import CopyTemplateAcrossProjectValidator


@login_exempt
@csrf_exempt
@require_POST
@apigw_require
@return_json_response
@project_inject
@request_validate(CopyTemplateAcrossProjectValidator)
@mark_request_whether_is_trust
def copy_template_across_project(request, project_id):
if not request.is_trust:
guohelu marked this conversation as resolved.
Show resolved Hide resolved
return {
"result": False,
"message": "you have no permission to call this api.",
"code": err_code.REQUEST_FORBIDDEN_INVALID.code,
}

params_data = json.loads(request.body)
new_project_id = params_data["new_project_id"]
template_id = params_data["template_id"]

try:
export_data = TaskTemplate.objects.export_templates([template_id], is_full=False, project_id=request.project.id)
import_result = TaskTemplate.objects.import_templates(
template_data=export_data,
override=False,
project_id=new_project_id,
operator=request.user.username,
)
except Exception as e:
logger.exception("The process fails to be replicated across services: {}".format(e))
guohelu marked this conversation as resolved.
Show resolved Hide resolved
return {
"result": False,
"message": "invalid flow data or error occur, please contact administrator",
"code": err_code.UNKNOWN_ERROR.code,
}

return format_import_result_to_response_data(import_result)
Empty file.
23 changes: 23 additions & 0 deletions gcloud/contrib/template_market/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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.contrib import admin

from gcloud.contrib.template_market import models


@admin.register(models.TemplateSharedRecord)
class TemplateMarketAdmin(admin.ModelAdmin):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
list_display = ["project_id", "template_id", "creator", "create_at", "extra_info"]
list_filter = ["project_id", "template_id", "creator", "create_at"]
search_fields = ["project_id", "creator"]
6 changes: 6 additions & 0 deletions gcloud/contrib/template_market/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class TemplatemakerConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "gcloud.contrib.template_market"
32 changes: 32 additions & 0 deletions gcloud/contrib/template_market/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 3.2.15 on 2024-12-09 12:51

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="TemplateSharedRecord",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("project_id", models.IntegerField(default=-1, help_text="项目 ID", verbose_name="项目 ID")),
("template_id", models.IntegerField(help_text="模版 ID", verbose_name="模版 ID")),
(
"scene_instance_id",
models.CharField(db_index=True, help_text="场景实例 ID", max_length=32, verbose_name="场景实例 ID"),
),
("creator", models.CharField(default="", max_length=32, verbose_name="创建者")),
("create_at", models.DateTimeField(auto_now_add=True, verbose_name="创建时间")),
("extra_info", models.JSONField(blank=True, null=True, verbose_name="额外信息")),
],
options={
"verbose_name": "模板共享记录 TemplateSharedRecord",
"verbose_name_plural": "模板共享记录 TemplateSharedRecord",
},
),
]
Empty file.
44 changes: 44 additions & 0 deletions gcloud/contrib/template_market/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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 import models
from django.utils.translation import ugettext_lazy as _


class TemplateSharedRecord(models.Model):
project_id = models.IntegerField(_("项目 ID"), default=-1, help_text="项目 ID")
template_id = models.IntegerField(_("模版 ID"), help_text="模版 ID")
scene_instance_id = models.CharField(_("场景实例 ID"), max_length=32, db_index=True, help_text="场景实例 ID")
Copy link
Member

Choose a reason for hiding this comment

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

场景实例是什么概念,切换成我们的概念。比如 market_record_id 这种,然后注明一下映射关系

creator = models.CharField(_("创建者"), max_length=32, default="")
create_at = models.DateTimeField(_("创建时间"), auto_now_add=True)
extra_info = models.JSONField(_("额外信息"), blank=True, null=True)

class Meta:
verbose_name = _("模板共享记录 TemplateSharedRecord")
verbose_name_plural = _("模板共享记录 TemplateSharedRecord")

@classmethod
def create(cls, project_id, template_id, scene_instance_id, creator="", extra_info=None):
if not scene_instance_id:
Copy link
Member

Choose a reason for hiding this comment

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

字段校验通过序列化器来做,不要在 model 里面做

raise ValueError("场景实例 ID 不能为空")

instance = cls(
project_id=project_id,
template_id=template_id,
scene_instance_id=scene_instance_id,
creator=creator,
extra_info=extra_info,
)
instance.save()
return instance
40 changes: 40 additions & 0 deletions gcloud/contrib/template_market/permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 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.
"""
import logging

from rest_framework import permissions

from gcloud.conf import settings
from gcloud.contrib.template_market.models import TemplateSharedRecord


class TemplatePreviewPermission(permissions.BasePermission):
def has_permission(self, request, view):
template_id = request.GET.get("template_id")
project_id = request.GET.get("project_id")

if not template_id or not project_id:
logging.warning("Missing required parameters.")
return False

record = TemplateSharedRecord.objects.filter(template_id=template_id, project_id=project_id).first()
if record is None:
logging.warning("template_id {} does not exist.".format(template_id))
return False

return True


class SharedProcessTemplatePermission(permissions.BasePermission):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
def has_permission(self, request, view):
return settings.ENABLE_TEMPLATE_MARKET
guohelu marked this conversation as resolved.
Show resolved Hide resolved
guohelu marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading