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

9 changes: 9 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,11 @@ 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
# 流程跨业务复制
ENABLE_APIGW_COPY_TEMPLATE = env.ENABLE_APIGW_COPY_TEMPLATE
guohelu marked this conversation as resolved.
Show resolved Hide resolved
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
7 changes: 7 additions & 0 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,10 @@
# 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", "")
# 流程跨业务复制
ENABLE_APIGW_COPY_TEMPLATE = False if os.getenv("ENABLE_APIGW_COPY_TEMPLATE") is None else True
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_biz import copy_template_across_biz

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_biz/(?P<project_id>\d+)/$", copy_template_across_biz),
]
78 changes: 78 additions & 0 deletions gcloud/apigw/views/copy_template_across_biz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
Copy link
Member

Choose a reason for hiding this comment

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

接口需要添加注册文件和文档

"""
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
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.conf import settings
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


@login_exempt
@csrf_exempt
@require_POST
@apigw_require
@return_json_response
@project_inject
@mark_request_whether_is_trust
def copy_template_across_biz(request, project_id):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
if not request.is_trust or not settings.ENABLE_APIGW_COPY_TEMPLATE:
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.get("new_project_id")
template_id = params_data.get("template_id")
template_id_list = [template_id] if template_id is not None else []
guohelu marked this conversation as resolved.
Show resolved Hide resolved

if not new_project_id or not template_id_list:
Copy link
Member

Choose a reason for hiding this comment

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

参数校验,最好用 validator 或者 serializer 来做,可以参考其他接口

return {
"result": False,
"message": "missing or invalid parameter",
"code": err_code.REQUEST_PARAM_INVALID.code,
}

try:
export_data = TaskTemplate.objects.export_templates(
template_id_list, 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("[API] copy common tempalte error: {}".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 AppMakerAdmin(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"
28 changes: 28 additions & 0 deletions gcloud/contrib/template_market/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.2.15 on 2024-12-06 06:47

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(db_index=True, help_text="模版 ID", 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.
28 changes: 28 additions & 0 deletions gcloud/contrib/template_market/models.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.
"""


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"), db_index=True, help_text="模版 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")
29 changes: 29 additions & 0 deletions gcloud/contrib/template_market/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- 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 rest_framework import serializers

from gcloud.constants import DATETIME_FORMAT
from gcloud.contrib.template_market.models import TemplateSharedRecord


class TemplateSharedRecordSerializer(serializers.ModelSerializer):
template_id = serializers.CharField(required=True, help_text="模板id")
project_id = serializers.CharField(required=True, help_text="项目id")
creator = serializers.CharField(required=False, max_length=32, help_text="创建者")
create_at = serializers.DateTimeField(required=False, help_text="创建时间", format=DATETIME_FORMAT)
extra_info = serializers.JSONField(required=False, allow_null=True, help_text="额外信息")

class Meta:
model = TemplateSharedRecord
fields = ["project_id", "template_id", "creator", "create_at", "extra_info"]
25 changes: 25 additions & 0 deletions gcloud/contrib/template_market/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- 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.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from gcloud.contrib.template_market.viewsets import StoreTemplateViewSet, SharedProcessTemplateViewSet


drf_api = DefaultRouter()
guohelu marked this conversation as resolved.
Show resolved Hide resolved
drf_api.register(r"store_templates", StoreTemplateViewSet)
drf_api.register(r"shared_process_templates", SharedProcessTemplateViewSet)

urlpatterns = [
url(r"^api/", include(drf_api.urls)),
]
101 changes: 101 additions & 0 deletions gcloud/contrib/template_market/viewsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# -*- 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 viewsets
from rest_framework.response import Response
from rest_framework import permissions

from gcloud.conf import settings
from gcloud import err_code
from gcloud.contrib.template_market.serializers import TemplateSharedRecordSerializer
from gcloud.contrib.template_market.models import TemplateSharedRecord
from gcloud.core.apis.drf.serilaziers.task_template import TaskTemplateSerializer
from gcloud.taskflow3.models import TaskTemplate


class StoreTemplatePermission(permissions.BasePermission):
Copy link
Member

Choose a reason for hiding this comment

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

permission 放到独立的文件里面

def has_permission(self, request, view):
template_id = view.kwargs.get("pk")
project_id = request.GET.get("project_id")

if not template_id or not project_id:
logging.warning("Missing required parameters.")
return False
try:
TemplateSharedRecord.objects.get(template_id=template_id, project_id=project_id)
guohelu marked this conversation as resolved.
Show resolved Hide resolved
except Exception:
logging.warning("template_id {} does not exist.".format(template_id))
return False
return True


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


class StoreTemplateViewSet(viewsets.ViewSet):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
queryset = TaskTemplate.objects.filter(pipeline_template__isnull=False, is_deleted=False)
serializer_class = TaskTemplateSerializer
permission_classes = [permissions.IsAuthenticated, StoreTemplatePermission]

def retrieve(self, request, *args, **kwargs):
instance = self.queryset.get(id=kwargs["pk"], project_id=request.GET.get("project_id"))
serializer = self.serializer_class(instance)
guohelu marked this conversation as resolved.
Show resolved Hide resolved

return Response(serializer.data)


class SharedProcessTemplateViewSet(viewsets.ModelViewSet):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
queryset = TemplateSharedRecord.objects.all()
serializer_class = TemplateSharedRecordSerializer
permission_classes = [permissions.IsAuthenticated, SharedProcessTemplatePermission]

def _get_market_routing(self, market_url):
return f"{settings.TEMPLATE_MARKET_API_URL}/{market_url}"

def retrieve(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.GET)
serializer.is_valid(raise_exception=True)

project_id = serializer.validated_data.get("project_id")
template_id = serializer.validated_data.get("template_id")

data = {"project_id": project_id, "template_id": template_id}

# todo: 调用第三方接口查询信息

return Response({"result": True, "data": data, "code": err_code.SUCCESS.code})

def create(self, request, *args, **kwargs):
guohelu marked this conversation as resolved.
Show resolved Hide resolved
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)

project_id = serializer.validated_data.get("project_id")
template_id = serializer.validated_data.get("template_id")

try:
TaskTemplate.objects.get(project_id=project_id, id=template_id)
except TaskTemplate.DoesNotExist:
logging.warning(f"Template with project_id {project_id} and template_id {template_id} not found.")
return Response({"result": False, "message": "Template not found", "code": err_code.OPERATION_FAIL.code})

# todo: 调用第三方接口实现共享

self.perform_create(serializer)

return Response({"result": True, "message": "Share template successfully", "code": err_code.SUCCESS.code})
Loading