Skip to content

Commit

Permalink
Merge pull request #910 from longguikeji/feature-284
Browse files Browse the repository at this point in the history
feat: 🎸 添加审批系统插件基类文档
  • Loading branch information
fanhe-lg authored Jun 6, 2022
2 parents 738863b + 4f9011d commit dc34632
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 70 deletions.
13 changes: 13 additions & 0 deletions arkid/core/approve_request_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
from arkid.core.approve import create_approve_request
from arkid.common.utils import verify_token
from pydantic import Field
from arkid.core.event import (
Event,
register_event,
dispatch_event,
CREATE_APPROVE_REQUEST,
)


class ApproveRequestMiddleware:
Expand Down Expand Up @@ -45,6 +51,13 @@ def process_view(self, request, view_func, view_args, view_kwargs):
).first()
if not approve_request:
approve_request = create_approve_request(request, user, approve_action)
dispatch_event(
Event(
tag=CREATE_APPROVE_REQUEST,
tenant=request.tenant,
data=approve_request,
)
)
response = HttpResponse(status=401)
return response
else:
Expand Down
4 changes: 2 additions & 2 deletions arkid/core/extension/account_life.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def load(self):
def periodic_task(self, event, **kwargs):
"""
抽象方法
Params:
event arkid.core.event.Event: 生命周期定时任务事件
Args:
event (arkid.core.event.Event): 生命周期定时任务事件
"""
pass

Expand Down
19 changes: 13 additions & 6 deletions arkid/core/extension/approve_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
from abc import abstractmethod
from arkid.core.extension import Extension
from arkid.core.translation import gettext_default as _
from arkid.core import api as core_api, event as core_event
from arkid.extension.models import TenantExtensionConfig, TenantExtension
from arkid.core.api import api
from typing import List
from arkid.core.error import ErrorCode
from arkid.common.logger import logger
from arkid.core import event as core_event
from arkid.extension.models import TenantExtensionConfig
from pydantic import Field
from ninja import Schema

Expand Down Expand Up @@ -45,10 +41,21 @@ def load(self):

@abstractmethod
def create_approve_request(self, event, **kwargs):
"""
抽象方法
Args:
event (arkid.core.event.Event): 创建审批请求事件
"""
pass

@abstractmethod
def change_approve_request_status(self, request, approve_request_id):
"""
抽象方法
Args:
request (django.http.HttpRequest): 创建审批请求事件
approve_request_id (str): 需要改变审批状态的审批请求ID
"""
pass

def create_tenant_config(self, tenant, config, name, type):
Expand Down
58 changes: 26 additions & 32 deletions arkid/core/extension/external_idp.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ def load(self):
def get_authorize_url(self, client_id, redirect_uri):
"""
抽象方法
Params:
client_id: str, 第三方认证提供的Client_ID,
redirect_uri: str, 由ArkID提供的回调地址
Return:
Args:
client_id (str): 第三方认证提供的Client_ID,
redirect_uri (str): 由ArkID提供的回调地址
Returns:
str: 第三方登录提供的认证URL
"""
pass
Expand Down Expand Up @@ -98,10 +98,10 @@ def login(self, request, tenant_id, config_id):
def get_ext_token_by_code(self, code, config):
"""
抽象方法
Params:
code: str 第三方认证返回的code
config: dict 第三方登录的插件运行时配置
Return:
Args:
code (str): 第三方认证返回的code
config (dict): 第三方登录的插件运行时配置
Returns:
str: 返回第三方认证提供的token
"""
pass
Expand All @@ -110,9 +110,9 @@ def get_ext_token_by_code(self, code, config):
def get_user_info_by_ext_token(self, token):
"""
抽象方法
Params:
token: str 第三方认证返回的token
Return:
Args:
token (str): 第三方认证返回的token
Returns:
dict: 返回第三方认证提供的用户信息
"""
pass
Expand All @@ -121,9 +121,9 @@ def get_user_info_by_ext_token(self, token):
def get_arkid_user(self, ext_id):
"""
抽象方法
Params:
ext_id: str 第三方认证返回的用户标识
Return:
Args:
ext_id (str): 第三方认证返回的用户标识
Returns:
arkid.core.models.User: ArkID用户
"""
pass
Expand Down Expand Up @@ -185,11 +185,11 @@ def callback(self, request, tenant_id, config_id):
@abstractmethod
def bind_arkid_user(self, ext_id, user):
"""
Params:
ext_id:str 第三方登录返回的用户标识
user: arkid.core.models.User ArkID的用户
Return:
{"token":xxx} 返回token
Args:
ext_id (str): 第三方登录返回的用户标识
user (arkid.core.models.User): ArkID的用户
Returns:
{"token":xxx}: 返回token
"""
pass

Expand All @@ -212,24 +212,18 @@ def bind(self, request, tenant_id, config_id):
def get_img_url(self):
"""
抽象方法
Return:
url str: 返回第三方登录按钮的图标
"""
Returns:
url str: 返回第三方登录按钮的图标
"""
pass

def register_external_idp_schema(self, idp_type, schema):
self.register_config_schema(schema, self.package + '_' + idp_type)
self.register_composite_config_schema(
schema, idp_type, exclude=['extension']
)
self.register_composite_config_schema(schema, idp_type, exclude=['extension'])

def create_tenant_config(
self, tenant, config, name, type
):
config_created = super().create_tenant_config(
tenant, config, name, type
)
def create_tenant_config(self, tenant, config, name, type):
config_created = super().create_tenant_config(tenant, config, name, type)
server_host = get_app_config().get_host()
login_url = server_host + reverse(
f'api:{self.pname}_tenant:{self.pname}_login',
Expand Down
56 changes: 56 additions & 0 deletions docs/ 开发者指南/ 插件分类/审批系统.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## 功能介绍
审批系统主要用于处理审批请求,插件开发者可以在处理审批请求逻辑中,将审批请求发送到不同的第三方系统,第三方系统在处理完审批请求后,可以将处理结果发送回来

## 实现思路
* 首先创建审批动作,指定接口Path, method和审批系统插件


```py title='创建审批动作接口'
@api.post(
"/tenant/{tenant_id}/approve_actions/",
tags=["审批动作"],
auth=None,
response=ApproveActionCreateOut,
)
def create_approve_action(request, tenant_id: str, data: ApproveActionCreateIn):
"""创建审批动作"""
extension = Extension.valid_objects.get(id=data.extension_id)
action = ApproveAction.valid_objects.filter(
path=data.path, method=data.method, extension=extension, tenant=request.tenant
).first()
if action:
return {'error': ErrorCode.APPROVE_ACTION_DUPLICATED.value}
else:
action = ApproveAction.valid_objects.create(
name=data.name,
description=data.description,
path=data.path,
method=data.method,
extension=extension,
tenant=request.tenant,
)
return {'error': ErrorCode.OK.value}
```

* 在中间件**arkid.core.approve_request_middleware**中根据扫描审批动作,拦截HTTP Request,
1. 如果某个审批动作没有创建审批请求,则创建审批请求,分发**CREATE_APPROVE_REQUEST**事件,将HTTP Request存储在审批请求中,同时使该请求返回未授权状态码401
2. 如果某个审批动作已经创建审批请求,判断该审批请求状态,如果状态为通过,那么恢复执行之前在审批请求中存储的HTTP Request对应的函数逻辑,如果状态为拒绝,返回未授权状态码401

* 在审批系统插件中监听**CREATE_APPROVE_REQUEST**事件,通过[create_approve_request](#arkid.core.extension.approve_system.ApproveSystemExtension.create_approve_request)将审批请求发送到其他第三方系统处理

* 其他第三方审批系统处理完审批请求后,可以将审批结果,通过覆盖接口 **/change_approve_request_status/{{approve_request_id}}/** 处理函数[change_approve_request_status](#arkid.core.extension.approve_system.ApproveSystemExtension.change_approve_request_status)处理审核结果

## 抽象方法
* [create_approve_request](#arkid.core.extension.approve_system.ApproveSystemExtension.create_approve_request)
* [change_approve_request_status](#arkid.core.extension.approve_system.ApproveSystemExtension.change_approve_request_status)
## 基类定义

::: arkid.core.extension.approve_system.ApproveSystemExtension
rendering:
show_source: true

## 示例

::: extension_root.com_longgui_approve_system_arkid.ApproveSystemArkIDExtension
rendering:
show_source: true
60 changes: 30 additions & 30 deletions extension_root/com_longgui_external_idp_github/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from arkid.core.extension.external_idp import ExternalIdpExtension, ExternalIdpBaseSchema
from arkid.core.extension.external_idp import (
ExternalIdpExtension,
ExternalIdpBaseSchema,
)
from arkid.core.extension import create_extension_schema
from .constants import AUTHORIZE_URL, IMG_URL, GET_TOKEN_URL, GET_USERINFO_URL
from .models import GithubUser
Expand All @@ -24,13 +27,12 @@ def get_img_url(self):
"""
return IMG_URL


def get_authorize_url(self, client_id, redirect_uri):
"""
Params:
client_id:str 注册Github应用返回的客户端标识
redirect_uri:str 在ArkID中创建Github登录配置后返回的回调地址
Return:
Args:
client_id (str): 注册Github应用返回的客户端标识
redirect_uri (str): 在ArkID中创建Github登录配置后返回的回调地址
Returns:
str: 返回用于向Github发起认证的URL
"""
url = "{}?client_id={}&redirect_uri={}".format(
Expand All @@ -42,31 +44,31 @@ def get_authorize_url(self, client_id, redirect_uri):

def get_ext_token_by_code(self, code, config):
"""
Params:
code: str Github返回的授权码
config: Github第三方登录的插件配置
Return:
Args:
code (str): Github返回的授权码
config (dict): Github第三方登录的插件配置
Returns:
str: 返回Github返回的access_token
"""
response = requests.post(
GET_TOKEN_URL,
params={
"code": code,
"client_id": config.get("client_id"),
"client_secret": config.get("client_secret"),
"grant_type": "authorization_code",
},
).__getattribute__("_content")
GET_TOKEN_URL,
params={
"code": code,
"client_id": config.get("client_id"),
"client_secret": config.get("client_secret"),
"grant_type": "authorization_code",
},
).__getattribute__("_content")
result = dict(
[(k, v[0]) for k, v in parse_qs(response.decode()).items()]
) # 将响应信息转换为字典
return result["access_token"]

def get_user_info_by_ext_token(self, token):
"""
Params:
token: str Github返回的access_token
Return:
Args:
token (str): Github返回的access_token
Returns:
tuple: 返回Github中用户信息中的id, login,avatar_url和所有用户信息
"""
headers = {"Authorization": "token " + token}
Expand All @@ -79,25 +81,23 @@ def get_user_info_by_ext_token(self, token):

def get_arkid_user(self, ext_id):
"""
Params:
ext_id: str 从Github用户信息接口获取的用户标识
Return:
arkid.core.models.User 返回ext_id绑定的ArkID用户
Args:
ext_id (str): 从Github用户信息接口获取的用户标识
Returns:
arkid.core.models.User: 返回ext_id绑定的ArkID用户
"""
return GithubUser.valid_objects.filter(github_user_id=ext_id).first().user

def bind_arkid_user(self, ext_id, user):
"""
Params:
ext_id: str 从Github用户信息接口获取的用户标识
user: arkid.core.models.User 用于绑定的ArkID用户
Args:
ext_id(str): 从Github用户信息接口获取的用户标识
user (arkid.core.models.User): 用于绑定的ArkID用户
"""
user.github_user_id = ext_id
user.save()




extension = ExternalIdpGithubExtension(
package=package,
name='Github第三方登录服务',
Expand Down

0 comments on commit dc34632

Please sign in to comment.