审批系统
功能介绍#
审批系统主要用于处理审批请求,插件开发者可以在处理审批请求逻辑中,将审批请求发送到不同的第三方系统,第三方系统在处理完审批请求后,可以将处理结果发送回来
实现思路#
-
首先创建审批动作,指定接口Path, method和负责处理的审批系统插件
-
在中间件arkid.core.approve_request_middleware中根据扫描审批动作,拦截HTTP Request,
- 如果某个审批动作没有创建审批请求,则创建审批请求,分发CREATE_APPROVE_REQUEST事件,将HTTP Request存储在审批请求中, 中断HTTP Request
- 如果某个审批动作已经创建审批请求,判断该审批请求状态,如果状态为通过,继续执行HTTP Request,如果状态为拒绝,中断HTTP Request
-
在审批系统插件中监听CREATE_APPROVE_REQUEST事件,通过create_approve_request将审批请求发送到其他第三方系统处理
-
其他第三方审批系统处理完审批请求后,可以将审批结果通过接口返回
-
同意审批请求接口
- path:/approve_requests/{{request_id}}/pass/
- method: PUT
- 处理函数:pass_approve_request_handler
- 需要实现抽象方法: pass_approve_request
-
拒绝审批请求接口
- path:/approve_requests/{{request_id}}/deny/'
- method: PUT
- 处理函数:deny_approve_request_handler
- 需要实现抽象方法: deny_approve_request
-
抽象方法#
基类定义#
arkid.core.extension.approve_system.ApproveSystemExtension (Extension)
#
Source code in arkid/core/extension/approve_system.py
class ApproveSystemExtension(Extension):
TYPE = "approve_system"
composite_schema_map = {}
created_composite_schema_list = []
composite_key = 'type'
composite_model = TenantExtensionConfig
@property
def type(self):
return ApproveSystemExtension.TYPE
def load(self):
self.listen_event(
core_event.CREATE_APPROVE_REQUEST, self.create_approve_request
)
self.pass_path = self.register_api(
f'/approve_requests/{{request_id}}/pass/',
'PUT',
self.pass_approve_request_handler,
response=ApproveRequestOut,
)
self.deny_path = self.register_api(
f'/approve_requests/{{request_id}}/deny/',
'PUT',
self.deny_approve_request_handler,
response=ApproveRequestOut,
)
super().load()
@abstractmethod
def create_approve_request(self, event, **kwargs):
"""
抽象方法
Args:
event (arkid.core.event.Event): 创建审批请求事件
"""
pass
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
def pass_approve_request_handler(self, request, request_id):
approve_request = ApproveRequest.valid_objects.get(id=request_id)
self.pass_approve_request(request, approve_request)
approve_request.status = 'pass'
approve_request.save()
return ErrorDict(ErrorCode.OK)
@abstractmethod
def pass_approve_request(self, request, approve_request):
"""
抽象方法
Args:
request (django.http.HttpRequest): HTTP 请求
approve_request (arkid.core.models.ApproveRequest): 需要同意的审批请求
"""
pass
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
def deny_approve_request_handler(self, request, request_id):
approve_request = ApproveRequest.valid_objects.get(id=request_id)
self.deny_approve_request(request, approve_request)
approve_request.status = 'deny'
approve_request.save()
return ErrorDict(ErrorCode.OK)
@abstractmethod
def deny_approve_request(self, request, approve_request):
"""
抽象方法
Args:
request (django.http.HttpRequest): HTTP 请求
approve_request (arkid.core.models.ApproveRequest): 需要拒绝的审批请求
"""
pass
def create_tenant_config(self, tenant, config, name, type):
tenant_config = super().create_tenant_config(tenant, config, name, type)
tenant_config.config["pass_request_url"] = self.pass_path
tenant_config.config["deny_request_url"] = self.deny_path
tenant_config.save()
return tenant_config
def register_approve_system_schema(self, schema, system_type):
self.register_config_schema(schema, self.package + '_' + system_type)
self.register_composite_config_schema(
schema, system_type, exclude=['extension']
)
composite_model (BaseModel)
django-model
#
TenantExtensionConfig(id, is_del, is_active, updated, created, tenant, extension, config, name, type)
Source code in arkid/core/extension/approve_system.py
class TenantExtensionConfig(BaseModel):
class Meta(object):
verbose_name = _("插件运行时配置")
verbose_name_plural = _("插件运行时配置")
tenant = models.ForeignKey('core.Tenant', blank=False, on_delete=models.PROTECT, verbose_name=_('租户'))
extension = models.ForeignKey('Extension', blank=False, on_delete=models.PROTECT, verbose_name=_('插件'))
config = models.JSONField(blank=True, default=dict, verbose_name=_('Runtime Config','运行时配置'))
name = models.CharField(max_length=128, default='', verbose_name=_('名称'))
type = models.CharField(max_length=128, default='', verbose_name=_('类型'))
config: JSONField
blank
django-field
#
Runtime Config
created: DateTimeField
blank
django-field
nullable
#
创建时间
extension: ForeignKey
django-field
#
插件
id: UUIDField
django-field
#
ID
is_active: BooleanField
django-field
#
是否可用
is_del: BooleanField
django-field
#
是否删除
name: CharField
django-field
#
名称
tenant: ForeignKey
django-field
#
租户
type: CharField
django-field
#
类型
updated: DateTimeField
blank
django-field
nullable
#
更新时间
create_approve_request(self, event, **kwargs)
#
create_tenant_config(self, tenant, config, name, type)
#
创建运行时配置
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tenant |
Tenant |
租户 |
required |
config |
dict |
config |
required |
name |
str |
运行时配置名字 |
required |
type |
str |
配置类型 |
required |
Returns:
Type | Description |
---|---|
TenantExtensionConfig |
创建的对象 |
Source code in arkid/core/extension/approve_system.py
deny_approve_request(self, request, approve_request)
#
抽象方法
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
django.http.HttpRequest |
HTTP 请求 |
required |
approve_request |
arkid.core.models.ApproveRequest |
需要拒绝的审批请求 |
required |
load(self)
#
抽象方法,插件加载的入口方法
Source code in arkid/core/extension/approve_system.py
def load(self):
self.listen_event(
core_event.CREATE_APPROVE_REQUEST, self.create_approve_request
)
self.pass_path = self.register_api(
f'/approve_requests/{{request_id}}/pass/',
'PUT',
self.pass_approve_request_handler,
response=ApproveRequestOut,
)
self.deny_path = self.register_api(
f'/approve_requests/{{request_id}}/deny/',
'PUT',
self.deny_approve_request_handler,
response=ApproveRequestOut,
)
super().load()
pass_approve_request(self, request, approve_request)
#
抽象方法
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
django.http.HttpRequest |
HTTP 请求 |
required |
approve_request |
arkid.core.models.ApproveRequest |
需要同意的审批请求 |
required |
示例#
extension_root.com_longgui_approve_system_arkid.ApproveSystemArkIDExtension (ApproveSystemExtension)
#
Source code in extension_root/com_longgui_approve_system_arkid/__init__.py
class ApproveSystemArkIDExtension(ApproveSystemExtension):
def load(self):
super().load()
self.register_api(
f'/approve_requests/',
'GET',
self.list_tenant_approve_requests,
response=List[ApproveRequestListItemOut],
tenant_path=True,
)
self.register_approve_system_schema(
ApproveSystemArkIDConfigSchema, 'approve_system_arkid'
)
self.register_front_pages([router_page, waiting_page, approved_page])
self.register_front_routers(router, approve_manage_router)
@operation(List[ApproveRequestListItemOut], roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
def list_tenant_approve_requests(
self, request, tenant_id: str, is_approved: str = ''
):
package = 'com.longgui.approve.system.arkid'
requests = ApproveRequest.valid_objects.filter(
tenant=request.tenant, action__extension__package=package
)
if is_approved == 'true':
requests = requests.exclude(status="wait")
elif is_approved == 'false':
requests = requests.filter(status="wait")
return requests
def create_approve_request(self, event, **kwargs):
pass
def pass_approve_request(self, request, approve_request):
response = restore_approve_request(approve_request)
logger.info(f'Restore approve request with result: {response}')
def deny_approve_request(self, request, approve_request):
pass
create_approve_request(self, event, **kwargs)
#
deny_approve_request(self, request, approve_request)
#
抽象方法
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
django.http.HttpRequest |
HTTP 请求 |
required |
approve_request |
arkid.core.models.ApproveRequest |
需要拒绝的审批请求 |
required |
load(self)
#
抽象方法,插件加载的入口方法
Source code in extension_root/com_longgui_approve_system_arkid/__init__.py
def load(self):
super().load()
self.register_api(
f'/approve_requests/',
'GET',
self.list_tenant_approve_requests,
response=List[ApproveRequestListItemOut],
tenant_path=True,
)
self.register_approve_system_schema(
ApproveSystemArkIDConfigSchema, 'approve_system_arkid'
)
self.register_front_pages([router_page, waiting_page, approved_page])
self.register_front_routers(router, approve_manage_router)
pass_approve_request(self, request, approve_request)
#
抽象方法
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
django.http.HttpRequest |
HTTP 请求 |
required |
approve_request |
arkid.core.models.ApproveRequest |
需要同意的审批请求 |
required |