diff --git a/.gitignore b/.gitignore
index a7ac21b4f..abc4bef2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -205,3 +205,4 @@ results.sqlite
tasks/*
~/*
tasks
+docker-entrypoint.sh
\ No newline at end of file
diff --git a/api/v1/schema/app.py b/api/v1/schema/app.py
index dba562f5f..5c25ff5b3 100644
--- a/api/v1/schema/app.py
+++ b/api/v1/schema/app.py
@@ -15,6 +15,12 @@ class Config:
model_fields = ['id', 'name', 'url', 'logo', 'type']
+class AppListQueryIn(Schema):
+
+ order: Optional[str] = Field(hidden=True, default=None)
+ category_id: Optional[str] = Field(hidden=True, default=None)
+ name: Optional[str] = Field(title=_("应用名称"), default=None)
+
class AppListOut(ResponseSchema):
data: List[AppListItemOut]
@@ -31,6 +37,11 @@ class AppListsOut(ResponseSchema):
data: List[AppItemsOut]
+class AppAllListsQueryIn(Schema):
+
+ not_arkid: Optional[int]=Field(hidden=True,default=None)
+
+
class AppItemOut(ModelSchema):
id: UUID = Field(readonly=True)
diff --git a/api/v1/schema/approve_request.py b/api/v1/schema/approve_request.py
index cbae88a5b..8a9f556af 100644
--- a/api/v1/schema/approve_request.py
+++ b/api/v1/schema/approve_request.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-
+from enum import Enum
from typing import List
from pydantic import Field
from ninja import Schema, ModelSchema
@@ -38,3 +38,13 @@ def resolve_status(obj):
class ApproveRequestListOut(ResponseSchema):
data: List[ApproveRequestListItemOut]
+
+class PermissionCategory(str, Enum):
+ 否 = 'false'
+ 是 = 'true'
+
+class ApproveRequestListQueryIn(Schema):
+
+ package: str = Field(title=_('Package', '包名'), hidden=True, default=None)
+ username: str = Field(title=_('Username', '用户名'), default=None)
+ is_approved: PermissionCategory = Field(title=_('Is Approved', '是否同意'), default=None)
\ No newline at end of file
diff --git a/api/v1/schema/auth_factor.py b/api/v1/schema/auth_factor.py
index 7c4f00f20..67a46047f 100644
--- a/api/v1/schema/auth_factor.py
+++ b/api/v1/schema/auth_factor.py
@@ -14,6 +14,11 @@ class AuthFactorListItemOut(Schema):
extension_name: str = Field(title=_("所属插件"))
extension_package: str = Field(title=_("所属插件标识"))
+
+class FactorListQueryIn(Schema):
+
+ order: str = Field(hidden=True, default=None)
+
class AuthFactorListOut(ResponseSchema):
data: List[AuthFactorListItemOut]
diff --git a/api/v1/schema/languages.py b/api/v1/schema/languages.py
index 21ce8ca86..c676b58c0 100644
--- a/api/v1/schema/languages.py
+++ b/api/v1/schema/languages.py
@@ -45,7 +45,8 @@ class LanguageDataItemOut(Schema):
)
translated:str = Field(
- title=_("译词句")
+ title=_("译词句"),
+ notranslation=True
)
class LanguageDataOut(ResponseSchema):
@@ -60,7 +61,8 @@ class LanguageDataItemCreateIn(Schema):
)
translated:str = Field(
- title=_("译词句")
+ title=_("译词句"),
+ notranslation=True
)
class LanguageDataItemCreateOut(ResponseSchema):
diff --git a/api/v1/schema/mine.py b/api/v1/schema/mine.py
index 50f0984ec..e3b0645b3 100644
--- a/api/v1/schema/mine.py
+++ b/api/v1/schema/mine.py
@@ -69,6 +69,21 @@ class MinePermissionListSchemaOut(Schema):
# model_fields = ['id', 'name', 'category', 'is_system']
+class MinePermissionListQueryIn(Schema):
+
+ app_id: Optional[str] = Field(hidden=True, default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ category: Optional[str] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
+
+class MineAppsGroupQueryIn(Schema):
+
+ app_group_id: Optional[str] = Field(hidden=True, default=None)
+ order: Optional[str] = Field(hidden=True, default=None)
+ name: Optional[str] = Field(title=_("应用名称"), default=None)
+
class MineTenantListOut(ResponseSchema):
data: List[MineTenantListItemOut]
diff --git a/api/v1/schema/permission.py b/api/v1/schema/permission.py
index f391e94c0..115531d1a 100644
--- a/api/v1/schema/permission.py
+++ b/api/v1/schema/permission.py
@@ -55,7 +55,7 @@ class UserAppLastPermissionsItemSchemaOut(Schema):
app_name: str = Field(default=None, alias="app.name", title=_("应用"))
sort_id: int = Field(hidden=True)
# is_open: bool = Field(item_action={"path":"/api/v1/tenant/{tenant_id}/permission/{id}/toggle_open", "method":actions.FrontActionMethod.POST.value}, title=_("是否授权给其它租户"))
- category: str = Field(title=_("分类应用名称"))
+ category: str = Field(title=_("分类名称"), notranslation=True)
in_current: bool = Field(title=_("是否已拥有"))
class UserAppLastPermissionsSchemaOut(ResponseSchema):
@@ -80,6 +80,49 @@ class PermissionCreateItemSchemaIn(Schema):
id:UUID = Field(hidden=True)
name:str
+
+class PermissionListQueryIn(Schema):
+
+ app_id: Optional[str] = Field(hidden=True, default=None)
+ select_user_id: Optional[str] = Field(hidden=True, default=None)
+ group_id: Optional[str] = Field(hidden=True, default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ category: Optional[PermissionCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
+
+class AppPermissionListQueryIn(Schema):
+
+ category: Optional[PermissionCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
+class UserGroupLastPermQueryIn(Schema):
+
+ usergroup_id: Optional[str] = Field(hidden=True, default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ category: Optional[PermissionCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
+class GroupPermissionListQueryIn(Schema):
+
+ select_usergroup_id: Optional[str] = Field(hidden=True, default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ category: Optional[PermissionCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
+class UserPermissionLastQueryIn(Schema):
+
+ app_id: Optional[str] = Field(hidden=True, default=None)
+ user_id: Optional[str] = Field(hidden=True, default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ category: Optional[PermissionCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
class PermissionCreateSchemaIn(ModelSchema):
app: PermissionCreateItemSchemaIn = Field(
diff --git a/api/v1/schema/permission_group.py b/api/v1/schema/permission_group.py
index 21bb96160..b986d78af 100644
--- a/api/v1/schema/permission_group.py
+++ b/api/v1/schema/permission_group.py
@@ -92,17 +92,32 @@ class PermissionGroupEditSchemaIn(Schema):
# model_fields = ['name']
class PermissionListSchemaOut(Schema):
- category: str = Field(title=_("分类"))
+ category: str = Field(title=_("分类"),notranslation=True)
operation_id: str = Field(default='', title=_("操作ID"))
id: UUID = Field(title=_("id"))
name: str = Field(title=_("名称"))
is_open: bool = Field(item_action={"path":"/api/v1/tenant/{tenant_id}/permission/{id}/toggle_open", "method":actions.FrontActionMethod.POST.value}, title=_("是否授权给其它租户"))
is_open_other_user: bool = Field(item_action={"path":"/api/v1/tenant/{tenant_id}/permission/{id}/toggle_other_user_open", "method":actions.FrontActionMethod.POST.value}, title=_("是否租户内所有人可见"))
- is_system: bool = Field(title=_("是否是系统权限 "))
+ is_system: bool = Field(title=_("是否是系统权限"))
# class Config:
# model = SystemPermission
# model_fields = ['id', 'name', 'is_system']
+class PermissionGroupCategory(str, Enum):
+ entry = 'entry'
+ api = 'api'
+ data = 'data'
+ group = 'group'
+ ui = 'ui'
+ other = 'other'
+
+class PermissionGroupListQueryIn(Schema):
+
+ category: Optional[PermissionGroupCategory] = Field(title=_("分类"), default=None)
+ name: Optional[str] = Field(title=_("权限名称"), default=None)
+ app_name: Optional[str] = Field(title=_("应用名称"), default=None)
+ operation_id: Optional[str] = Field(title=_("操作ID"), default=None)
+
class PermissionListSelectSchemaOut(Schema):
@@ -110,7 +125,7 @@ class PermissionListSelectSchemaOut(Schema):
in_current: bool = Field(title=_("是否在当前分组里"), hidden=True)
name: str
category: str
- is_system: bool
+ is_system: bool = Field(title=_("是否是系统权限"))
class PermissionListDataSelectSchemaOut(ResponseSchema):
data: List[PermissionListSelectSchemaOut]
diff --git a/api/v1/schema/user.py b/api/v1/schema/user.py
index 0a46a4a37..b8db4ae12 100644
--- a/api/v1/schema/user.py
+++ b/api/v1/schema/user.py
@@ -10,6 +10,7 @@ class UserListQueryIn(Schema):
order:str = Field(
default=None,
title=_("排序字段"),
+ hidden=True,
notranslation=True
)
username:str = Field(
@@ -18,6 +19,21 @@ class UserListQueryIn(Schema):
notranslation=True
)
+ nickname:str = Field(
+ default=None,
+ title=_("昵称"),
+ )
+
+ mobile:str = Field(
+ default=None,
+ title=_("电话"),
+ )
+
+ email:str = Field(
+ default=None,
+ title=_("邮箱"),
+ )
+
class UserListItemOut(ModelSchema):
class Config:
diff --git a/api/v1/views/app.py b/api/v1/views/app.py
index 308bbad58..f661e5c1c 100644
--- a/api/v1/views/app.py
+++ b/api/v1/views/app.py
@@ -3,7 +3,7 @@
from ninja import ModelSchema
from django.db.models import Q
from arkid.core.models import App
-
+from ninja import Query
from arkid.core.api import api, operation
from django.db import transaction
from ninja.pagination import paginate
@@ -28,10 +28,14 @@
@api.get("/tenant/{tenant_id}/apps/", response=List[AppListItemOut], tags=['应用'])
@operation(AppListOut, roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def list_apps(request, tenant_id: str,order:str=None, category_id:str=None):
+def list_apps(request, tenant_id: str, query_data: AppListQueryIn=Query(...)):
'''
app列表
'''
+ category_id = query_data.category_id
+ name = query_data.name
+ order = query_data.order
+
apps = App.expand_objects.filter(
tenant_id=tenant_id,
is_active=True,
@@ -42,6 +46,9 @@ def list_apps(request, tenant_id: str,order:str=None, category_id:str=None):
apps = apps.filter(arkstore_category_id=category_id)
elif category_id == "-1":
apps = apps.filter(arkstore_category_id=None, arkstore_app_id=None)
+ if name:
+ name = name.strip()
+ apps = apps.filter(name__icontains=name)
if order:
apps = apps.order_by(order)
else:
@@ -85,7 +92,7 @@ def list_all_apps(request, tenant_id: str):
@api.get("/tenant/{tenant_id}/all_apps_in_arkid/", response=AppListsOut, tags=['应用'])
@operation(AppListOut, roles=[NORMAL_USER, TENANT_ADMIN, PLATFORM_ADMIN])
-def all_apps_in_arkid(request, tenant_id: str, not_arkid: int=None):
+def all_apps_in_arkid(request, tenant_id: str, query_data:AppAllListsQueryIn=Query(...)):
'''
所有app列表(含arkid)
'''
@@ -93,7 +100,7 @@ def all_apps_in_arkid(request, tenant_id: str, not_arkid: int=None):
Q(entry_permission__is_open=True)|Q(tenant_id=tenant_id)
)
items = []
- if not_arkid is None:
+ if query_data.not_arkid is None:
items.append({
'id': 'arkid',
'name': 'arkid',
diff --git a/api/v1/views/approve_request.py b/api/v1/views/approve_request.py
index f4ff783ee..3e0777caa 100644
--- a/api/v1/views/approve_request.py
+++ b/api/v1/views/approve_request.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
+from ninja import Query
from arkid.core.api import api, operation
from arkid.core.constants import *
from arkid.core.translation import gettext_default as _
@@ -17,6 +18,7 @@
from api.v1.schema.approve_request import (
ApproveRequestListItemOut,
ApproveRequestListOut,
+ ApproveRequestListQueryIn,
)
@@ -28,14 +30,16 @@
@operation(List[ApproveRequestListItemOut], roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
def approve_request_list(
- request, tenant_id: str, package: str = "", is_approved: str = ""
+ request, tenant_id: str, query_data:ApproveRequestListQueryIn=Query(...)
):
tenant = request.tenant
requests = ApproveRequest.valid_objects.filter(tenant=tenant)
- if package:
- requests = requests.filter(action__extension__package=package)
- if is_approved == "true":
+ if query_data.package:
+ requests = requests.filter(action__extension__package=query_data.package)
+ if query_data.username:
+ requests = requests.filter(user__username__icontains=query_data.username)
+ if query_data.is_approved == "true":
requests = requests.exclude(status="wait")
- elif is_approved == "false":
+ elif query_data.is_approved == "false":
requests = requests.filter(status="wait")
return requests
diff --git a/api/v1/views/auth.py b/api/v1/views/auth.py
index ac490f8d6..f446f622f 100644
--- a/api/v1/views/auth.py
+++ b/api/v1/views/auth.py
@@ -6,6 +6,7 @@
from arkid.core.error import ErrorCode, ErrorDict
from api.v1.schema.auth import *
from django.http import HttpResponse, JsonResponse
+from arkid.core.tasks.celery import dispatch_task
@api.post("/tenant/{tenant_id}/auth/", response=AuthOut, tags=['登录与注册'], auth=None)
@operation(AuthOut, use_id=True)
@@ -22,10 +23,21 @@ def auth(request, tenant_id: str, event_tag: str, data: AuthIn):
# 生成 token
token = refresh_token(user)
+ dispatch_task.delay('async_get_arkstore_access_token', tenant.id.hex, token)
netloc = request.get_host().split(':')[0]
+
+ is_ip_addr = False
+ ip_list = netloc.split('.')
+ if len(ip_list) == 4 and ''.join(ip_list).isdigit():
+ is_ip_addr = True
+
domain = ('.'.join(netloc.split('.')[-2:]))
response = JsonResponse({'error': ErrorCode.OK.value, 'data': {'user': {"id": user.id.hex, "username": user.username}, 'token': token}})
- response.set_cookie("arkid_token", token, domain=domain, httponly=True)
+ if is_ip_addr:
+ response.set_cookie("arkid_token", token, httponly=True)
+ else:
+ response.set_cookie("arkid_token", token, domain=domain, httponly=True)
+
return response
@api.post("/tenant/{tenant_id}/reset_password/", response=ResetPasswordOut, tags=['登录与注册'],auth=None)
diff --git a/api/v1/views/auth_factor.py b/api/v1/views/auth_factor.py
index 552e77182..df59800a6 100644
--- a/api/v1/views/auth_factor.py
+++ b/api/v1/views/auth_factor.py
@@ -1,6 +1,7 @@
from distutils.command.build_ext import extension_name_re
from distutils.command.config import config
from typing import List
+from ninja import Query
from ninja import Field, ModelSchema, Schema
from ninja.pagination import paginate
from arkid.core.api import api, operation
@@ -9,13 +10,13 @@
from arkid.core.extension.auth_factor import AuthFactorExtension
from arkid.extension.models import Extension, TenantExtensionConfig
from arkid.core.error import ErrorCode, ErrorDict
-from api.v1.schema.auth_factor import AuthFactorCreateIn, AuthFactorCreateOut, AuthFactorDeleteOut, AuthFactorListItemOut, AuthFactorListOut, AuthFactorOut, AuthFactorUpdateIn, AuthFactorUpdateOut
+from api.v1.schema.auth_factor import *
from arkid.core.pagenation import CustomPagination
@api.get("/tenant/{tenant_id}/auth_factors/", response=List[AuthFactorListItemOut], tags=[_("认证因素")])
@operation(List[AuthFactorListItemOut], roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_auth_factors(request, tenant_id: str,order:str=None):
+def get_auth_factors(request, tenant_id: str, query_data: FactorListQueryIn=Query(...)):
""" 认证因素列表
"""
extensions = Extension.active_objects.filter(
@@ -23,7 +24,7 @@ def get_auth_factors(request, tenant_id: str,order:str=None):
configs = TenantExtensionConfig.active_objects.filter(
tenant__id=tenant_id, extension__in=extensions)
- if order:
+ if query_data.order:
configs = configs.order_by(order)
configs = configs.all()
diff --git a/api/v1/views/child_manager.py b/api/v1/views/child_manager.py
index f9b629653..61d2e0492 100644
--- a/api/v1/views/child_manager.py
+++ b/api/v1/views/child_manager.py
@@ -16,14 +16,14 @@
@api.get("/tenant/{tenant_id}/child_managers/", response=List[ChildManagerListOut], tags=["子管理员"])
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_child_managers(request, tenant_id: str):
+def get_child_managers(request, tenant_id: str, username: str=None):
""" 子管理员列表
"""
from arkid.core.perm.permission_data import PermissionData
tenant = request.tenant
users = User.valid_objects.filter(tenant=tenant)
permissiondata = PermissionData()
- child_mans = permissiondata.get_child_mans(users, tenant)
+ child_mans = permissiondata.get_child_mans(users, tenant, username)
return child_mans
@api.get("/tenant/{tenant_id}/child_managers/{id}/", response=ChildManagerDeatilBaseOut, tags=["子管理员"])
diff --git a/api/v1/views/event_list.py b/api/v1/views/event_list.py
index 55152c721..48c9a6789 100644
--- a/api/v1/views/event_list.py
+++ b/api/v1/views/event_list.py
@@ -1,4 +1,5 @@
from typing import List
+from ninja import Query
from arkid.core.api import api, operation
from arkid.core.constants import *
from arkid.core.translation import gettext_default as _
@@ -14,18 +15,46 @@ class GetEventListOutItem(Schema):
description:str = Field(title=_("描述"))
url:str = Field(title=_("文档链接"))
+class EventListQueryIn(Schema):
+ tag:str = Field(title=_("标签"), default=None)
+ name:str = Field(title=_("名称"), default=None)
+
@api.get("/tenant/{tenant_id}/event_list/", response=List[GetEventListOutItem], tags=["事件列表"])
@operation(List[GetEventListOutItem], roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_event_list(request, tenant_id: str):
+def get_event_list(request, tenant_id: str, query_data: EventListQueryIn=Query(...)):
""" 事件列表 """
events = []
host = get_app_config().get_host()
+ name = query_data.name
+ tag = query_data.tag
for event_type in event.tag_map_event_type.values():
- events.append({
- 'tag':event_type.tag,
- 'name':event_type.name,
- 'description':event_type.description,
- 'url': f'{host}/arkid/%20%20%20用户指南/用户手册/%20租户管理员/扩展能力/事件列表/#{event_type.name}'
- })
+ if name and tag and name in event_type.description and tag in event_type.tag:
+ events.append({
+ 'tag':event_type.tag,
+ 'name':event_type.name,
+ 'description':event_type.description,
+ 'url': f'{host}/arkid/%20%20%20用户指南/用户手册/%20租户管理员/扩展能力/事件列表/#{event_type.name}'
+ })
+ elif name and name in event_type.description:
+ events.append({
+ 'tag':event_type.tag,
+ 'name':event_type.name,
+ 'description':event_type.description,
+ 'url': f'{host}/arkid/%20%20%20用户指南/用户手册/%20租户管理员/扩展能力/事件列表/#{event_type.name}'
+ })
+ elif tag and tag in event_type.tag:
+ events.append({
+ 'tag':event_type.tag,
+ 'name':event_type.name,
+ 'description':event_type.description,
+ 'url': f'{host}/arkid/%20%20%20用户指南/用户手册/%20租户管理员/扩展能力/事件列表/#{event_type.name}'
+ })
+ elif not name and not tag:
+ events.append({
+ 'tag':event_type.tag,
+ 'name':event_type.name,
+ 'description':event_type.description,
+ 'url': f'{host}/arkid/%20%20%20用户指南/用户手册/%20租户管理员/扩展能力/事件列表/#{event_type.name}'
+ })
return events
\ No newline at end of file
diff --git a/api/v1/views/extension.py b/api/v1/views/extension.py
index 1a40b0913..f23f078ad 100644
--- a/api/v1/views/extension.py
+++ b/api/v1/views/extension.py
@@ -1,4 +1,5 @@
from uuid import UUID
+from ninja import Query
from datetime import datetime
from ninja import Schema, ModelSchema
from arkid.core import actions, extension
@@ -42,6 +43,12 @@ class ExtensionConfigSchemaOut(Schema):
class ExtensionProfileGetSchemaResponse(ResponseSchema):
data: ExtensionProfileGetSchemaOut
+class ExtensionListQueryIn(Schema):
+
+ name: str = Field(title=_("插件名称"), default=None)
+ package: str = Field(title=_("标识"), default=None)
+ category_id: str = Field(hidden=True, default=None)
+
@api.get("/extensions/{id}/profile/", response=ExtensionProfileGetSchemaResponse, tags=['平台插件'])
@operation(roles=[PLATFORM_ADMIN])
def get_extension_profile(request, id: str):
@@ -107,13 +114,17 @@ class Config:
@api.get("/extensions/", response=List[ExtensionListOut], tags=['平台插件'])
@operation(roles=[PLATFORM_ADMIN])
@paginate(CustomPagination)
-def list_extensions(request, status: str = None, category_id: str = None):
+def list_extensions(request, query_data: ExtensionListQueryIn=Query(...)):
""" 获取平台插件列表"""
- if not status:
+ if not query_data.name:
qs = ExtensionModel.valid_objects.filter()
else:
- qs = ExtensionModel.valid_objects.filter(status=status)
+ qs = ExtensionModel.valid_objects.filter(name__icontains=query_data.name)
+
+ if query_data.package:
+ qs = qs.filter(package__icontains=query_data.package)
+ category_id = query_data.category_id
if category_id and category_id != "" and category_id != "0":
qs = qs.filter(category_id=int(category_id))
diff --git a/api/v1/views/loginpage.py b/api/v1/views/loginpage.py
index 5e6eefad2..77b7f6d3e 100644
--- a/api/v1/views/loginpage.py
+++ b/api/v1/views/loginpage.py
@@ -41,6 +41,7 @@ class ButtonSchema(Schema):
http: Optional[ButtonHttpSchema] = Field(title=_('http', 'http请求'))
delay: Optional[int] = Field(title=_('delay', '点击后延时(单位:秒)'))
agreement: Optional[ButtonAgreementSchema] = Field(title=_('agreement', '隐私声明'))
+ action: Optional[str] = Field(title=_('action', '点击执行函数'))
class LOGIN_FORM_ITEM_TYPES(str, Enum):
@@ -59,11 +60,15 @@ class LoginFormItemSchema(Schema):
http: Optional[ButtonHttpSchema] = Field(title=_('http', 'http请求'))
content: Optional[str] = Field(title=_('content', '内容'))
+class ScriptSchema(Schema):
+ src: str
+ globals: Optional[List[str]]
class LoginFormSchema(Schema):
label: str = Field(title=_('label', '表单名'))
items: List[LoginFormItemSchema] = Field(title=_('items', '表单项'))
submit: ButtonSchema = Field(title=_('submit', '表单提交'))
+ scripts: Optional[List[ScriptSchema]] = Field(title=_('scripts', '自定义表单脚本'))
class LoginPageExtendSchema(Schema):
@@ -190,6 +195,12 @@ def login_page(request, tenant_id: str):
tenant_expanded = Tenant.expand_objects.get(id=tenant.id)
tenant_expanded["is_platform_tenant"] = tenant.is_platform_tenant
+
+
+ if not request.session.exists(request.session.session_key):
+ request.session.create()
+ request.session.set_expiry(0)
+
return {
'tenant': tenant_expanded,
'data': data,
diff --git a/api/v1/views/mine.py b/api/v1/views/mine.py
index 6ae7cfb91..41a748039 100644
--- a/api/v1/views/mine.py
+++ b/api/v1/views/mine.py
@@ -1,4 +1,5 @@
from typing import List
+from ninja import Query
from django.urls import reverse
from django.shortcuts import render
from arkid.config import get_app_config
@@ -67,10 +68,7 @@ def update_mine_profile(request, tenant_id: str, data: ProfileSchemaIn):
def get_mine_permissions(
request,
tenant_id: str,
- app_id: str = None,
- app_name: str = None,
- category: str = None,
- operation_id: str = None,
+ query_data:MinePermissionListQueryIn=Query(...)
):
"""我的权限列表"""
login_user = request.user
@@ -78,7 +76,7 @@ def get_mine_permissions(
permissiondata = PermissionData()
items = permissiondata.get_permissions_by_mine_search(
- tenant_id, app_id, None, None, login_user, app_name=app_name, category=category, operation_id=operation_id,
+ tenant_id, query_data.app_id, None, None, login_user, app_name=query_data.app_name, category=query_data.category, operation_id=query_data.operation_id, name=query_data.name,
)
return items
@@ -396,9 +394,13 @@ def get_mine_app_groups(request, tenant_id: str, parent_id=None):
@api.get("/mine/tenant/{tenant_id}/mine_group_apps/", response=List[MineAppListItemOut], tags=["我的"])
@operation(MineAppListOut,roles=[NORMAL_USER, TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_mine_apps_with_group(request, tenant_id: str, app_group_id:str=None, order:str=None):
+def get_mine_apps_with_group(request, tenant_id: str, query_data:MineAppsGroupQueryIn=Query(...)):
"""获取我的分组应用
"""
+ app_group_id = query_data.app_group_id
+ order = query_data.order
+ name = query_data.name
+
apps = []
if app_group_id in [None,"","0",0]:
apps = App.active_objects.filter(
@@ -418,12 +420,45 @@ def get_mine_apps_with_group(request, tenant_id: str, app_group_id:str=None, ord
apps = apps.filter(id__in=app_ids)
else:
apps = apps.filter(id=None)
+ if name:
+ name = name.strip()
+ apps = apps.filter(name__icontains=name)
if order:
apps = apps.order_by(order)
apps = apps.all()
return list(apps) if apps else []
+@api.get("/mine/tenant/{tenant_id}/mine_group_apps_all/", response=MineAppListOut, tags=["我的"])
+@operation(MineAppListOut,roles=[NORMAL_USER, TENANT_ADMIN, PLATFORM_ADMIN])
+def get_mine_apps_with_group_all(request, tenant_id: str, app_group_id:str=None, order:str=None):
+ """获取我的分组应用
+ """
+ apps = []
+ if app_group_id in [None,"","0",0]:
+ apps = App.active_objects.filter(
+ Q(tenant=request.tenant) | Q(entry_permission__is_open=True)
+ )
+ else:
+ app_group = AppGroup.active_objects.get(
+ tenant =request.tenant,
+ id=app_group_id
+ )
+ apps = app_group.apps.filter(Q(tenant=request.tenant) | Q(entry_permission__is_open=True))
+ # 需要甄别有入口权限的应用
+ from arkid.core.perm.permission_data import PermissionData
+ pd = PermissionData()
+ app_ids = pd.get_entry_apps(request.user, tenant_id, apps)
+ if app_ids:
+ apps = apps.filter(id__in=app_ids)
+ else:
+ apps = apps.filter(id=None)
+ if order:
+ apps = apps.order_by(order)
+ apps = apps.all()
+
+ return SuccessDict(data=list(apps) if apps else [])
+
@api.get("/mine/unread_messages/",response=List[MineMessageListItemOut],tags=["我的"],auth=GlobalAuth())
@operation(MineMessageListOut,roles=[NORMAL_USER, TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
diff --git a/api/v1/views/permission.py b/api/v1/views/permission.py
index 020674b7f..8f67b1d93 100644
--- a/api/v1/views/permission.py
+++ b/api/v1/views/permission.py
@@ -2,6 +2,7 @@
from arkid.core.api import api, operation
from typing import List, Optional
from django.db import transaction
+from ninja import Query
from ninja.pagination import paginate
from arkid.core.error import ErrorCode, ErrorDict
from arkid.core.pagenation import CustomPagination
@@ -48,38 +49,38 @@ def create_permission(request, tenant_id: str, data: PermissionCreateSchemaIn):
@api.get("/tenant/{tenant_id}/permissions", response=List[PermissionsListSchemaOut], tags=['权限'])
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def list_permissions(request, tenant_id: str, app_id: str = None, select_user_id: str = None, group_id: str = None, app_name: str = None, category: str = None, operation_id: str = None):
+def list_permissions(request, tenant_id: str, query_data:PermissionListQueryIn=Query(...)):
'''
权限列表
'''
login_user = request.user
from arkid.core.perm.permission_data import PermissionData
permissiondata = PermissionData()
- return permissiondata.get_permissions_by_search(tenant_id, app_id, select_user_id, group_id, login_user, app_name=app_name, category=category, operation_id=operation_id)
+ return permissiondata.get_permissions_by_search(tenant_id, query_data.app_id, query_data.select_user_id, query_data.group_id, login_user, app_name=query_data.app_name, category=query_data.category, operation_id=query_data.operation_id, name=query_data.name)
@api.get("/tenant/{tenant_id}/apps/{id}/permissions", response=List[AppPermissionsItemSchemaOut], tags=['权限'])
@operation(AppPermissionsListSchemaOut, roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def app_list_permissions(request, tenant_id: str, id: str, category: str = None, operation_id: str = None):
+def app_list_permissions(request, tenant_id: str, id: str, query_data:AppPermissionListQueryIn=Query(...)):
'''
应用权限列表
'''
from arkid.core.perm.permission_data import PermissionData
permissiondata = PermissionData()
- return permissiondata.get_app_permissions_by_search(tenant_id, id, category, operation_id)
+ return permissiondata.get_app_permissions_by_search(tenant_id, id, query_data.category, query_data.operation_id, query_data.name)
@api.get("/tenant/{tenant_id}/user_app_last_permissions", response=List[UserAppLastPermissionsItemSchemaOut], tags=['权限'])
@operation(UserAppLastPermissionsSchemaOut, roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def user_app_last_permissions(request, tenant_id: str, user_id: str = None, app_id: str = None, category: str = None, operation_id: str = None):
+def user_app_last_permissions(request, tenant_id: str, query_data:UserPermissionLastQueryIn=Query(...)):
'''
用户最终结果权限列表
'''
login_user = request.user
from arkid.core.perm.permission_data import PermissionData
permissiondata = PermissionData()
- return permissiondata.get_user_app_last_permissions(tenant_id, app_id, user_id, category, operation_id)
+ return permissiondata.get_user_app_last_permissions(tenant_id, query_data.app_id, query_data.user_id, query_data.category, query_data.operation_id, query_data.name, query_data.app_name)
@api.get("/tenant/{tenant_id}/childmanager_permissions", response=List[PermissionsListSchemaOut], tags=['权限'])
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@@ -275,7 +276,6 @@ def usergroup_remove_permission(request, tenant_id: str, select_usergroup_id: st
# from arkid.core.perm.permission_data import PermissionData
# pd = PermissionData()
if isinstance(permission, SystemPermission):
- pass
dispatch_event(Event(tag=REMOVE_USERGROUP_SYSTEM_PERMISSION, tenant=request.tenant, request=request, data=permission))
else:
# pd.remove_app_permission_to_usergroup(
@@ -288,24 +288,24 @@ def usergroup_remove_permission(request, tenant_id: str, select_usergroup_id: st
@api.get("/tenant/{tenant_id}/group_permissions", response=List[PermissionsListSchemaOut], tags=['权限'])
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def list_group_permissions(request, tenant_id: str, select_usergroup_id: str = None, app_name: str = None, category: str = None, operation_id: str = None):
+def list_group_permissions(request, tenant_id: str, query_data:GroupPermissionListQueryIn=Query(...)):
'''
分组权限列表
'''
from arkid.core.perm.permission_data import PermissionData
permissiondata = PermissionData()
- return permissiondata.get_group_permissions_by_search(tenant_id, select_usergroup_id, app_name, category, operation_id)
+ return permissiondata.get_group_permissions_by_search(tenant_id, query_data.select_usergroup_id, query_data.app_name, query_data.category, query_data.operation_id, query_data.name)
@api.get("/tenant/{tenant_id}/user_group_last_permissions", response=List[UserAppLastPermissionsItemSchemaOut], tags=['权限'])
@operation(UserAppLastPermissionsSchemaOut, roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def list_user_group_last_permissions(request, tenant_id: str, usergroup_id: str = None, category: str = None, operation_id: str = None):
+def list_user_group_last_permissions(request, tenant_id: str, query_data:UserGroupLastPermQueryIn=Query(...)):
'''
分组权限最终列表
'''
from arkid.core.perm.permission_data import PermissionData
permissiondata = PermissionData()
- return permissiondata.get_user_group_last_permissions(tenant_id, usergroup_id, category, operation_id)
+ return permissiondata.get_user_group_last_permissions(tenant_id, query_data.usergroup_id, query_data.category, query_data.operation_id, query_data.name, query_data.app_name)
# @api.post("/tenant/{tenant_id}/permission/{permission_id}/set_open", tags=['权限'])
# @operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
diff --git a/api/v1/views/permission_group.py b/api/v1/views/permission_group.py
index ce4661ec2..2bed36d14 100644
--- a/api/v1/views/permission_group.py
+++ b/api/v1/views/permission_group.py
@@ -1,4 +1,5 @@
from uuid import UUID
+from ninja import Query
from typing import List
from ninja import Field
from ninja import Schema
@@ -131,9 +132,13 @@ def delete_permission_group(request, tenant_id: str, id: str):
@api.get("/tenant/{tenant_id}/permission_groups/{permission_group_id}/permissions/", response=List[PermissionListSchemaOut], tags=["权限分组"])
@operation(roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_permissions_from_group(request, tenant_id: str, permission_group_id: str, category: str = None, operation_id: str = None):
+def get_permissions_from_group(request, tenant_id: str, permission_group_id: str, query_data:PermissionGroupListQueryIn=Query(...)):
""" 获取当前分组的权限列表
"""
+ category = query_data.category
+ operation_id = query_data.operation_id
+ name = query_data.name
+ app_name = query_data.app_name
from arkid.core.perm.permission_data import PermissionData
if permission_group_id != 'arkid':
permission = SystemPermission.valid_objects.filter(id=permission_group_id).first()
@@ -147,6 +152,24 @@ def get_permissions_from_group(request, tenant_id: str, permission_group_id: str
if operation_id:
operation_id = operation_id.strip()
result_items = result_items.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ result_items = result_items.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ if isinstance(permission, SystemPermission):
+ permissions = permissions.filter(app__name__icontains=app_name)
+ else:
+ filter_apps = App.valid_objects.filter(
+ name__icontains=app_name
+ )
+ filter_ids = []
+ for filter_app in filter_apps:
+ filter_ids.append(filter_app.entry_permission.id)
+ if filter_ids:
+ result_items = result_items.filter(id__in=filter_ids)
+ else:
+ result_items = result_items.filter(id__isnull=True)
return result_items
else:
app = App.valid_objects.filter(id=permission_group_id).first()
@@ -162,6 +185,18 @@ def get_permissions_from_group(request, tenant_id: str, permission_group_id: str
#code__startswith='group_role'
)
if group_permissions:
+ if category:
+ category = category.strip()
+ group_permissions = group_permissions.filter(category__icontains=category)
+ if operation_id:
+ operation_id = operation_id.strip()
+ group_permissions = group_permissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ group_permissions = group_permissions.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ group_permissions = group_permissions.filter(app__name__icontains=app_name)
items.extend(group_permissions)
for group_permission in group_permissions:
for item in group_permission.container.all():
@@ -178,23 +213,59 @@ def get_permissions_from_group(request, tenant_id: str, permission_group_id: str
if operation_id:
operation_id = operation_id.strip()
group_permission_details = group_permission_details.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ group_permission_details = group_permission_details.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ group_permissions = group_permissions.filter(app__name__icontains=app_name)
items.extend(group_permission_details)
entry_permission = None
if app.entry_permission:
- if category and category in app.entry_permission.category:
- category = category.strip()
+ if category and operation_id and name and category in app.entry_permission.category and operation_id in app.entry_permission.operation_id and name in app.entry_permission.name:
+ entry_permission = app.entry_permission
+ elif category and operation_id and category in app.entry_permission.category and operation_id in app.entry_permission.operation_id:
+ entry_permission = app.entry_permission
+ elif category and name and category in app.entry_permission.category and name in app.entry_permission.name:
+ entry_permission = app.entry_permission
+ elif operation_id and name and operation_id in app.entry_permission.operation_id and name in app.entry_permission.name:
+ entry_permission = app.entry_permission
+ elif category and category in app.entry_permission.category:
entry_permission = app.entry_permission
elif operation_id and operation_id in app.entry_permission.operation_id:
- operation_id = operation_id.strip()
entry_permission = app.entry_permission
- else:
+ elif name and name in app.entry_permission.name:
entry_permission = app.entry_permission
+
+ if app_name and app_name not in app.name:
+ entry_permission = None
# 需要过滤展示
permissiondata = PermissionData()
items = permissiondata.get_permissions_by_app_filter(tenant_id, app.id, items, entry_permission, request.user)
return items
else:
permissions = SystemPermission.valid_objects.filter(category='group', is_system=True)
+ if category:
+ category = category.strip()
+ permissions = permissions.filter(category__icontains=category)
+ if operation_id:
+ operation_id = operation_id.strip()
+ permissions = permissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ filter_apps = App.valid_objects.filter(
+ name__icontains=app_name
+ )
+ filter_ids = []
+ for filter_app in filter_apps:
+ filter_ids.append(filter_app.entry_permission.id)
+ if filter_ids:
+ permissions = permissions.filter(id__in=filter_ids)
+ else:
+ permissions = permissions.filter(id__isnull=True)
# 只能看到自己拥有的权限
permissiondata = PermissionData()
return permissiondata.get_system_permission_by_filter(tenant_id, permissions, request.user)
@@ -270,9 +341,12 @@ def update_permissions_from_group(request, tenant_id: str, permission_group_id:
@api.get("/tenant/{tenant_id}/permission_groups/{permission_group_id}/select_permissions/", response=List[PermissionListSelectSchemaOut], tags=["权限分组"])
@operation(PermissionListDataSelectSchemaOut, roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_select_permissions(request, tenant_id: str, permission_group_id: str, category: str = None, operation_id: str = None):
+def get_select_permissions(request, tenant_id: str, permission_group_id: str, query_data:PermissionGroupListQueryIn=Query(...)):
""" 获取所有权限并附加是否在当前分组的状态
"""
+ category = query_data.category
+ operation_id = query_data.operation_id
+ name = query_data.name
# 只允许非arkid的分组操作(如果用户直接在系统分组里加权限会有问题)
if permission_group_id == 'arkid':
return []
@@ -293,6 +367,9 @@ def get_select_permissions(request, tenant_id: str, permission_group_id: str, ca
if operation_id:
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
for permission in permissions:
id_hex = permission.id.hex
if id_hex in ids:
@@ -312,6 +389,9 @@ def get_select_permissions(request, tenant_id: str, permission_group_id: str, ca
if operation_id:
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
for permission in permissions:
id_hex = permission.id.hex
if id_hex in ids:
diff --git a/api/v1/views/tenant_extension.py b/api/v1/views/tenant_extension.py
index 5c1f7a678..d2e2cc128 100644
--- a/api/v1/views/tenant_extension.py
+++ b/api/v1/views/tenant_extension.py
@@ -1,4 +1,5 @@
from uuid import UUID
+from ninja import Query
from datetime import datetime
from ninja import Query, Schema, ModelSchema
from arkid.core.api import api, operation
@@ -42,6 +43,11 @@ class ExtensionConfigGetOut(ResponseSchema):
class ExtensionConfigCreateSchemaOut(Schema):
config_id: str
+class TenantExtensionListQueryIn(Schema):
+
+ name: str = Field(title=_("插件名称"), default=None)
+ package: str = Field(title=_("标识"), default=None)
+ category_id: str = Field(hidden=True, default=None)
class TenantExtensionConfigOut(ModelSchema):
@@ -256,14 +262,21 @@ def get_platform_extensions(request, tenant_id: str, category_id: str = None):
@api.get("/tenant/{tenant_id}/tenant/extensions/", tags=["租户插件"],response=List[TenantRentedExtensionListOut])
@operation(List[TenantRentedExtensionListOut], roles=[TENANT_ADMIN, PLATFORM_ADMIN])
@paginate(CustomPagination)
-def get_tenant_extensions(request, tenant_id: str, category_id: str = None):
+def get_tenant_extensions(request, tenant_id: str, query_data: TenantExtensionListQueryIn=Query(...)):
""" 租户插件列表
"""
+ category_id: str = query_data.category_id
token = request.user.auth_token
tenant = Tenant.objects.get(id=tenant_id)
extension_ids = TenantExtension.valid_objects.filter(tenant_id=tenant_id, is_rented=True).values('extension_id')
extensions = ExtensionModel.active_objects.filter(id__in = extension_ids)
+ if query_data.name:
+ extensions = extensions.filter(name__icontains=query_data.name)
+
+ if query_data.package:
+ extensions = extensions.filter(package__icontains=query_data.package)
+
if category_id and category_id != "" and category_id != "0":
extensions = extensions.filter(category_id=int(category_id))
diff --git a/api/v1/views/user.py b/api/v1/views/user.py
index d005f3fe7..93512dabb 100644
--- a/api/v1/views/user.py
+++ b/api/v1/views/user.py
@@ -30,6 +30,12 @@ def user_list(request, tenant_id: str, query_data: UserListQueryIn=Query(...)):
users = User.expand_objects.filter(tenant_id=tenant_id, is_del=False)
if query_data.username:
users = users.filter(username__icontains=query_data.username)
+ if query_data.nickname:
+ users = users.filter(nickname__icontains=query_data.nickname)
+ if query_data.mobile:
+ users = users.filter(mobile__icontains=query_data.mobile)
+ if query_data.email:
+ users = users.filter(email__icontains=query_data.email)
if query_data.order:
users = users.order_by(query_data.order)
login_user = request.user
@@ -43,7 +49,6 @@ def user_list(request, tenant_id: str, query_data: UserListQueryIn=Query(...)):
return list(users)
-
@api.get("/tenant/{tenant_id}/user_no_super/",response=UserListOut, tags=['用户'])
@operation(UserListOut,roles=[TENANT_ADMIN, PLATFORM_ADMIN])
# @paginate(CustomPagination)
diff --git a/arkid/common/arkstore.py b/arkid/common/arkstore.py
index ca0d2755f..132e812f7 100644
--- a/arkid/common/arkstore.py
+++ b/arkid/common/arkstore.py
@@ -16,18 +16,19 @@
from arkid.extension.utils import import_extension, unload_extension, load_extension_apps, restart_celery
from pathlib import Path
from arkid.common.logger import logger
+from django.core.cache import cache
-arkid_saas_token_cache = {}
-
def get_saas_token(tenant, token, use_cache=True):
"""
获取saas平台token
"""
# 缓存 saas_token
key = (str(tenant.id) + '_' + str(token)).replace('-', '')
- if use_cache and key in arkid_saas_token_cache:
- return arkid_saas_token_cache[key]
+ saas_cache = cache.get(key)
+ if use_cache and saas_cache:
+ return saas_cache
+
app = Application.objects.filter(name='arkid_saas', uuid = tenant.id).first()
nonce = uuid.uuid4().hex
params = {
@@ -55,11 +56,12 @@ def get_saas_token(tenant, token, use_cache=True):
resp = requests.get(resp.url)
if resp.status_code != 200:
- arkid_saas_token_cache.pop(key, None)
+ cache.delete(key)
raise Exception(f'Error get_saas_token: {resp.status_code}')
resp = resp.json()
- arkid_saas_token_cache[key] = (resp['token'], resp['tenant_id'], resp['tenant_slug'])
- return arkid_saas_token_cache[key]
+ result = (resp['token'], resp['tenant_id'], resp['tenant_slug'])
+ cache.set(key, result, timeout=60*60)
+ return result
def get_arkstore_access_token(tenant, token, use_cache=True):
@@ -77,7 +79,6 @@ def get_arkstore_access_token(tenant, token, use_cache=True):
use_cache=False, local_tenant=tenant, local_token=token)
-arkstore_access_token_saas_cache = {}
def get_arkstore_access_token_with_saas_token(saas_tenant_slug, saas_tenant_id, saas_token,
use_cache=True, local_tenant=None, local_token=None):
@@ -86,19 +87,20 @@ def get_arkstore_access_token_with_saas_token(saas_tenant_slug, saas_tenant_id,
"""
# 缓存 idtoken
key = (str(saas_tenant_id) + '_' + str(saas_token)).replace('-', '')
- if use_cache and key in arkstore_access_token_saas_cache:
+ id_token = cache.get(key)
+ if use_cache and id_token:
try:
- payload = jwt.decode(arkstore_access_token_saas_cache[key], options={"verify_signature": False})
+ payload = jwt.decode(id_token, options={"verify_signature": False})
except Exception:
- arkstore_access_token_saas_cache.pop(key, None)
+ cache.delete(key)
raise Exception("Unable to parse id_token")
exp_dt = datetime.fromtimestamp(payload["exp"])
expire_time = timezone.make_aware(exp_dt, timezone.get_default_timezone())
now = timezone.localtime()
if now <= expire_time:
- return arkstore_access_token_saas_cache[key]
+ return id_token
else:
- arkstore_access_token_saas_cache.pop(key, None)
+ cache.delete(key)
# id_token 过期后,重新获取saas_token和id_token
if local_tenant and local_token:
saas_token, saas_tenant_id, saas_tenant_slug = get_saas_token(local_tenant, local_token, use_cache=False)
@@ -107,15 +109,16 @@ def get_arkstore_access_token_with_saas_token(saas_tenant_slug, saas_tenant_id,
app_login_url = settings.ARKSTOER_URL + '/api/v1/login'
resp = requests.get(app_login_url, params=params)
if resp.status_code != 200:
- arkstore_access_token_saas_cache.pop(key, None)
+ cache.delete(key)
raise Exception(f'Error get_arkstore_access_token_with_saas_token: {resp.status_code}, url: {resp.url}')
try:
resp = resp.json()
except:
from urllib.parse import urlencode, unquote
raise Exception(f'Error get_arkstore_access_token_with_saas_token: {resp.status_code}, url: {unquote(resp.url)}')
- arkstore_access_token_saas_cache[key] = resp['access_token']
- return arkstore_access_token_saas_cache[key]
+ id_token = resp['access_token']
+ cache.set(key, id_token, timeout=60*60)
+ return id_token
def get_arkstore_extensions(access_token, purchased=None, rented=False, type=None, offset=0, limit=10, extra_params={}):
@@ -605,6 +608,15 @@ def check_arkstore_purcahsed_extension_expired(tenant, token, package):
if ext_info is None:
return True
extension_uuid = ext_info['uuid']
+
+ price_info = get_arkstore_extension_price(access_token, extension_uuid)
+ prices = price_info.get('prices')
+ if not prices:
+ return True
+ for price in prices:
+ if price.get('sale_price') == 0:
+ return True
+
order_url = settings.ARKSTOER_URL + f'/api/v1/arkstore/extensions/{extension_uuid}/purchased'
headers = {'Authorization': f'Token {access_token}'}
params = {}
@@ -725,4 +737,24 @@ def get_app_config_from_arkstore(request, arkstore_app_id):
if res['type'] == 'auto_form_fill':
app = get_arkid_saas_app_detail(tenant, token, arkstore_app_id)
return app.get('config', {}).get('config', {})
- return {}
\ No newline at end of file
+ return {}
+
+
+def get_admin_user_token():
+ from django.core.cache import cache
+
+ key = "ADMIN_USER_TOKEN"
+ value = refresh_admin_uesr_token
+ timeout = 60*30
+ token = cache.get_or_set(key, value, timeout=timeout)
+ return token
+
+
+def refresh_admin_uesr_token():
+ from arkid.core.token import refresh_token
+ platform_tenant = Tenant.platform_tenant()
+ admin_user = User.objects.filter(
+ username='admin', tenant=platform_tenant
+ ).first()
+ token = refresh_token(admin_user)
+ return token
diff --git a/arkid/core/actions.py b/arkid/core/actions.py
index e81bd1757..479a9d064 100644
--- a/arkid/core/actions.py
+++ b/arkid/core/actions.py
@@ -1,9 +1,9 @@
from enum import Enum
-from typing import Union, Tuple,List
+from typing import Union, Tuple,List, Optional
from arkid.common import DeepSN
from arkid.common.utils import gen_tag
from arkid.core.translation import gettext_default as _
-
+from ninja import Schema
class FrontActionType(Enum):
"""前端动作类型枚举类
@@ -35,6 +35,7 @@ class FrontActionType(Enum):
NEXT_ACTION = 'next'
ORDER_ACTION = 'order'
ORDERSET_ACTION = 'orderset'
+ SCRIPT_ACTION = 'script'
class FrontActionMethod(Enum):
@@ -214,6 +215,16 @@ def __init__(self, path: str, order_parms:List[str], *args, **kwargs):
self.order_parms = order_parms
super().__init__(action_type=FrontActionType.ORDERSET_ACTION,*args, **kwargs)
+class ScriptSchema(Schema):
+ src: str
+ globals: Optional[List[str]]
+
+
+class ScriptAction(FrontAction):
+ def __init__(self, scripts: List[ScriptSchema], script_func:str, *args, **kwargs):
+ self.scripts = scripts
+ self.script_func = script_func
+ super().__init__(action_type=FrontActionType.SCRIPT_ACTION, *args, **kwargs)
nav_actions = {}
diff --git a/arkid/core/api.py b/arkid/core/api.py
index 6f7233920..c87c335be 100644
--- a/arkid/core/api.py
+++ b/arkid/core/api.py
@@ -77,6 +77,7 @@ class HttpBaseBearer(HttpAuthBase, ABC):
header: str = "Authorization"
app_id: str = "APP_ID"
app_secret: str = "APP_SECRET"
+ download_token = "DOWNLOAD_TOKEN"
def __call__(self, request: HttpRequest) -> Optional[Any]:
headers = get_headers(request)
@@ -86,6 +87,8 @@ def __call__(self, request: HttpRequest) -> Optional[Any]:
parts = auth_value.split(" ")
if parts[0].lower() == self.openapi_scheme:
token = " ".join(parts[1:])
+ elif request.GET.get(self.download_token, None):
+ token = request.GET.get(self.download_token)
app_id = headers.get(self.app_id, None)
app_secret = headers.get(self.app_secret, None)
@@ -107,6 +110,7 @@ def authenticate(self, request, token, app_id, app_secret):
token = ExpiringToken.objects.filter(user=request.user).first()
if not token:
token = ExpiringToken.objects.create(user=request.user, token=generate_token())
+ self.refresh_token_active_date(token)
tenant = request.tenant
# 获取操作id查询用户权限
operation_id = request.operation_id
@@ -122,6 +126,7 @@ def authenticate(self, request, token, app_id, app_secret):
if token:
# 使用传统的token访问
token = ExpiringToken.objects.get(token=token)
+ self.refresh_token_active_date(token)
if not token.user.is_active:
raise HttpError(401, _('User inactive or deleted','用户无效或被删除'))
tenant = request.tenant or Tenant.platform_tenant()
@@ -172,6 +177,14 @@ def authenticate(self, request, token, app_id, app_secret):
# logger.error(err)
# return
+ @staticmethod
+ def refresh_token_active_date(token):
+ from django.utils import timezone
+ local_date = timezone.localdate()
+ if not token.active_date or token.active_date < local_date:
+ token.active_date = local_date
+ token.save()
+
class ArkidApi(NinjaAPI):
def create_response(self, request, *args, **kwargs):
diff --git a/arkid/core/migrations/0032_expiringtoken_active_date.py b/arkid/core/migrations/0032_expiringtoken_active_date.py
new file mode 100644
index 000000000..541951d7a
--- /dev/null
+++ b/arkid/core/migrations/0032_expiringtoken_active_date.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.6 on 2022-10-26 13:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0031_alter_tenant_slug'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='expiringtoken',
+ name='active_date',
+ field=models.DateField(blank=True, default=None, null=True, verbose_name='Active Date'),
+ ),
+ ]
diff --git a/arkid/core/models.py b/arkid/core/models.py
index 19a6d825f..ac3834b49 100644
--- a/arkid/core/models.py
+++ b/arkid/core/models.py
@@ -547,6 +547,7 @@ class Meta(object):
default=generate_token,
)
created = models.DateTimeField(_("Created", '创建时间'), auto_now=True)
+ active_date = models.DateField(_("Active Date", '活跃日期'), blank=True, null=True, default=None)
def expired(self, tenant):
"""Return boolean indicating token expiration."""
diff --git a/arkid/core/perm/permission_data.py b/arkid/core/perm/permission_data.py
index 3a8a275e0..d87d6f0b0 100644
--- a/arkid/core/perm/permission_data.py
+++ b/arkid/core/perm/permission_data.py
@@ -1451,7 +1451,7 @@ def update_tenant_all_user_permission(self, tenant):
data_group_parent_child[parent_id_hex] = temp_data_group
data_dict = collections.OrderedDict(sorted(data_dict.items(), key=lambda obj: obj[0]))
- def get_app_permissions_by_search(self, tenant_id, app_id, category = None, operation_id = None):
+ def get_app_permissions_by_search(self, tenant_id, app_id, category = None, operation_id = None, name = None):
'''
根据应用查权限(根据应用权限字符串)
'''
@@ -1481,6 +1481,9 @@ def get_app_permissions_by_search(self, tenant_id, app_id, category = None, oper
if operation_id:
operation_id = operation_id.strip()
result_items = result_items.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ result_items = result_items.filter(name__icontains=name)
result.extend(list(result_items.order_by('sort_id')))
else:
result_items = SystemPermission.valid_objects.filter(
@@ -1492,6 +1495,9 @@ def get_app_permissions_by_search(self, tenant_id, app_id, category = None, oper
if operation_id:
operation_id = operation_id.strip()
result_items = result_items.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ result_items = result_items.filter(name__icontains=name)
result.extend(list(result_items.order_by('sort_id')))
return result
@@ -1566,7 +1572,7 @@ def get_permissions_by_app_filter(self, tenant_id, app_id, items, entry_permissi
return result
- def get_permissions_by_search(self, tenant_id, app_id, user_id, group_id, login_user, parent_id=None, is_only_show_group=False, app_name=None, category=None, operation_id=None):
+ def get_permissions_by_search(self, tenant_id, app_id, user_id, group_id, login_user, parent_id=None, is_only_show_group=False, app_name=None, category=None, operation_id=None, name=None):
'''
根据应用,用户,分组查权限(要根据用户身份显示正确的列表)
'''
@@ -1600,11 +1606,24 @@ def get_permissions_by_search(self, tenant_id, app_id, user_id, group_id, login_
if app_name:
app_name = app_name.strip()
permissions = permissions.filter(app__name__icontains=app_name)
- systempermissions = systempermissions.filter(id__isnull=True)
+ filter_apps = App.active_objects.filter(name__icontains=app_name)
+ entry_permission_ids = []
+ for filter_app in filter_apps:
+ entry_permission = filter_app.entry_permission
+ if entry_permission:
+ entry_permission_ids.append(entry_permission.id)
+ if entry_permission_ids:
+ systempermissions = systempermissions.filter(id__in=entry_permission_ids)
+ else:
+ systempermissions = systempermissions.filter(id__isnull=True)
if category:
category = category.strip()
permissions = permissions.filter(category__icontains=category)
systempermissions = systempermissions.filter(category__icontains=category)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ systempermissions = systempermissions.filter(name__icontains=name)
if operation_id:
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
@@ -1710,7 +1729,7 @@ def get_permissions_by_search(self, tenant_id, app_id, user_id, group_id, login_
systempermissions = systempermissions.filter(Q(tenant__isnull=True)|Q(tenant_id=tenant_id))
return list(systempermissions.all())+list(permissions.all())
- def get_user_app_last_permissions(self, tenant_id, app_id, user_id, category=None, operation_id=None):
+ def get_user_app_last_permissions(self, tenant_id, app_id, user_id, category=None, operation_id=None, name=None, app_name=None):
'''
获取用户指定应用的最终权限
'''
@@ -1757,6 +1776,24 @@ def get_user_app_last_permissions(self, tenant_id, app_id, user_id, category=Non
if operation_id:
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ if app_id:
+ permissions = permissions.filter(app__name__icontains=app_name)
+ else:
+ filter_apps = App.valid_objects.filter(
+ name__icontains=app_name
+ )
+ filter_ids = []
+ for filter_app in filter_apps:
+ filter_ids.append(filter_app.entry_permission.id)
+ if filter_ids:
+ permissions = permissions.filter(id__in=filter_ids)
+ else:
+ permissions = permissions.filter(id__isnull=True)
permissions = permissions.order_by('sort_id')
for permission in permissions:
@@ -1769,7 +1806,7 @@ def get_user_app_last_permissions(self, tenant_id, app_id, user_id, category=Non
else:
return []
- def get_user_group_last_permissions(self, tenant_id, usergroup_id, category=None, operation_id=None):
+ def get_user_group_last_permissions(self, tenant_id, usergroup_id, category=None, operation_id=None, name=None, app_name=None):
'''
获取用户分组的最终权限
'''
@@ -1789,7 +1826,23 @@ def get_user_group_last_permissions(self, tenant_id, usergroup_id, category=None
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
systempermissions = systempermissions.filter(operation_id__icontains=operation_id)
-
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ systempermissions = systempermissions.filter(name__icontains=name)
+ if app_name:
+ app_name = app_name.strip()
+ permissions = permissions.filter(app__name__icontains=app_name)
+ filter_apps = App.valid_objects.filter(
+ name__icontains=app_name
+ )
+ filter_ids = []
+ for filter_app in filter_apps:
+ filter_ids.append(filter_app.entry_permission.id)
+ if filter_ids:
+ systempermissions = systempermissions.filter(id__in=filter_ids)
+ else:
+ systempermissions = systempermissions.filter(id__isnull=True)
compress = Compress()
usergroup = UserGroup.valid_objects.filter(
id=usergroup_id
@@ -1854,7 +1907,7 @@ def get_user_group_last_permissions(self, tenant_id, usergroup_id, category=None
return list(systempermissions)+list(permissions)
- def get_permissions_by_mine_search(self, tenant_id, app_id, user_id, group_id, login_user, parent_id=None, is_only_show_group=False, app_name=None, category=None, operation_id=None):
+ def get_permissions_by_mine_search(self, tenant_id, app_id, user_id, group_id, login_user, parent_id=None, is_only_show_group=False, app_name=None, category=None, operation_id=None, name=None):
'''
根据应用,用户,分组查权限(要根据用户身份显示正确的列表)
'''
@@ -1899,6 +1952,11 @@ def get_permissions_by_mine_search(self, tenant_id, app_id, user_id, group_id, l
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
systempermissions = systempermissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ systempermissions = systempermissions.filter(name__icontains=name)
+
if app_id or user_id or group_id:
if app_id:
app = App.valid_objects.filter(
@@ -2047,7 +2105,7 @@ def get_permissions_by_childmanager(self, tenant_id, login_user, only_show_group
return systempermissions
- def get_group_permissions_by_search(self, tenant_id, select_usergroup_id, app_name, category, operation_id=None):
+ def get_group_permissions_by_search(self, tenant_id, select_usergroup_id, app_name, category, operation_id=None, name=None):
'''
根据应用,用户分组,分类查权限(要根据分组身份显示正确的列表)
'''
@@ -2071,6 +2129,10 @@ def get_group_permissions_by_search(self, tenant_id, select_usergroup_id, app_na
operation_id = operation_id.strip()
permissions = permissions.filter(operation_id__icontains=operation_id)
systempermissions = systempermissions.filter(operation_id__icontains=operation_id)
+ if name:
+ name = name.strip()
+ permissions = permissions.filter(name__icontains=name)
+ systempermissions = systempermissions.filter(name__icontains=name)
if select_usergroup_id:
# 系统权限
usergroup_permissionresult = GroupPermissionResult.valid_objects.filter(
@@ -2750,7 +2812,7 @@ def get_child_manager_info(self, tenant_id, select_user):
})
return permissions, manager_scope, self_source_ids
- def get_child_mans(self, auth_users, tenant):
+ def get_child_mans(self, auth_users, tenant, username):
'''
获取子管理员
'''
@@ -2802,7 +2864,11 @@ def get_child_mans(self, auth_users, tenant):
auth_user.is_tenant_admin = False
if ids:
- return User.valid_objects.filter(id__in=ids)
+ users = User.valid_objects.filter(id__in=ids)
+ if username:
+ return users.filter(username__icontains=username)
+ else:
+ return users
else:
return []
diff --git a/arkid/extension/utils.py b/arkid/extension/utils.py
index 7a7fd9598..93d7a3f98 100644
--- a/arkid/extension/utils.py
+++ b/arkid/extension/utils.py
@@ -152,7 +152,12 @@ def unload_extension(ext_dir: str) -> any:
if not Path(ext_dir).exists():
return
ext_name = f'{Path(ext_dir).parent}.{Path(ext_dir).name}'
- ext = importlib.import_module(ext_name)
+ try:
+ ext = importlib.import_module(ext_name)
+ except Exception as e:
+ logger.error(f"import_module {ext_name} failed: {str(e)}")
+ return
+
if ext:
ext.extension.stop()
sys.modules.pop(ext_name, None)
diff --git a/arkid/settings.py b/arkid/settings.py
index cd9b1a1e3..6617b1017 100644
--- a/arkid/settings.py
+++ b/arkid/settings.py
@@ -175,12 +175,33 @@
# '/home/guancy/longgui/arkid/extension_root/com_longgui_international_en_us/locale'
]
+REDIS_CONFIG = {
+ 'HOST': 'localhost',
+ 'PORT': 6379,
+ 'DB': 0,
+ 'PASSWORD': None,
+}
+
+REDIS_URL = 'redis://{}:{}/{}'.format(REDIS_CONFIG['HOST'], REDIS_CONFIG['PORT'],\
+ REDIS_CONFIG['DB']) if REDIS_CONFIG['PASSWORD'] is None \
+ else 'redis://:{}@{}:{}/{}'.format(REDIS_CONFIG['PASSWORD'],\
+ REDIS_CONFIG['HOST'], REDIS_CONFIG['PORT'], REDIS_CONFIG['DB'])
+
# Celery settings
-CELERY_BROKER = 'redis://localhost:6379'
-CELERY_BROKER_URL = 'redis://localhost:6379'
+CELERY_BROKER = REDIS_URL
+CELERY_BROKER_URL = REDIS_URL
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
+CACHES = {
+ "default": {
+ "BACKEND": "django.core.cache.backends.redis.RedisCache",
+ "LOCATION": f"{REDIS_URL}/1",
+ }
+}
+SESSION_ENGINE = "django.contrib.sessions.backends.cache"
+SESSION_CACHE_ALIAS = "default"
+
#: Only add pickle to this list if your broker is secured
#: from unwanted access (see userguide/security.html)
# CELERY_ACCEPT_CONTENT = ['json']
@@ -244,4 +265,4 @@
exec(open(os.path.join(BASE_DIR, 'settings_local.py')).read())
-CSRF_TRUSTED_ORIGINS = []
\ No newline at end of file
+CSRF_TRUSTED_ORIGINS = []
diff --git a/docker-compose/settings.py b/docker-compose/settings.py
index d7d50e63b..dd31da081 100644
--- a/docker-compose/settings.py
+++ b/docker-compose/settings.py
@@ -30,3 +30,10 @@
# CELERY
CELERY_BROKER_URL = REDIS_URL
+
+CACHES = {
+ "default": {
+ "BACKEND": "django.core.cache.backends.redis.RedisCache",
+ "LOCATION": f"{REDIS_URL}/1",
+ }
+}
\ No newline at end of file
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
old mode 100644
new mode 100755
diff --git "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/ \346\217\222\344\273\266.md" "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/ \346\217\222\344\273\266.md"
new file mode 100644
index 000000000..805e5065a
--- /dev/null
+++ "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/ \346\217\222\344\273\266.md"
@@ -0,0 +1,46 @@
+# 插件接入
+
+## 创建插件
+
+### ArkID插件
+
+1.在ArkID中点击应用管理-应用列表-本地应用,点击开发与代理,跳转到ArkStore
+
+[](https://x.imgtu.com/i/Bbbgph)
+
+2.在Arkstore中点击开发商-插件管理-仓库管理,上传插件所在的gitee仓库或者zip压缩包
+
+[](https://x.imgtu.com/i/Bbb5yZ)
+
+!!! 注意
+ 名称必填,仓库分支与上传文件任选其一
+
+3.如果选择gitee方式来创建仓库,并且仓库为私有仓库,需要授权龙归来访问您的gitee仓库,公开gitee仓库和zip压缩包方式可以跳过此步
+点击授权
+[](https://x.imgtu.com/i/BbbAUU)
+
+跳转到gitee
+[](https://x.imgtu.com/i/BbbGoH)
+
+同意授权
+[](https://x.imgtu.com/i/BbbV2q)
+
+4.导入插件, 插件导入后会展示在插件包管理中
+点击导入插件
+[](https://x.imgtu.com/i/BbbAUU)
+
+插件包管理
+[](https://x.imgtu.com/i/BbbhG9)
+
+5.设置价格,详情请见[**价格规则**](../#_2)
+点击设置价格
+[](https://x.imgtu.com/i/Bbb8tY)
+
+设置价格
+[](https://x.imgtu.com/i/BbbKj4)
+
+6.提交审核
+
+[](https://x.imgtu.com/i/Bbb8tY)
+
+7.龙归审核通过后,插件上架完成,所有ArkID的用户在其插件商店中都能看到该插件。
diff --git "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/index.md" "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/index.md"
new file mode 100644
index 000000000..57d39a779
--- /dev/null
+++ "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/index.md"
@@ -0,0 +1,53 @@
+# ArkID开发商
+
+如果您有开发能力,或者独立运营自己的SaaS产品,只通过ArkID账号访问ArkStore,即可成为ArkID开发商。
+
+## 开发商条件
+
+* 任何个人或企业
+* 有开发自研能力
+* 拥有ArkID账号
+* 访问ArkStore
+
+开发商可以向ArkID生态提供生产两类产品:[**ArkID插件**](./%20插件/) 与 [**SaaS应用**](./应用/)。
+
+## 价格规则
+
+### 商店支付
+
+插件只能选择商店支付的方式,应用可以是商店支付或者应用内支付的方式。
+
+无论是插件还是应用,开发商都可以设置价格。
+
+价格分两类:**购买价格** 与 **租赁价格**,两种价格的组成是相同的。
+
+价格包含两个元素:**市场指导价** 与 **成本折扣**
+
+市场指导价的单位为: x元/y人/z天
+
+* 当x=0,则被视为免费
+* 当y=0,则被认为不限人数
+* 当z=0,则被认为不限天数
+
+成本折扣可以为0-1之间的任何一个两位小数。
+
+!!! 注意
+ 每成交一个产品,开发商实际获得的收益为:市场指导价 * 成本折扣
+
+价格可以设置多条,以满足不同的定价策略。
+
+### 应用内支付
+
+你的应用可以不通过商店支付,而是用户自行在你的应用内支付页面完成支付。
+
+这种情况,需要你跟龙归签署相关合作协议,并商定好分成比例,定期与龙归结算即可。
+
+## 订单记录
+
+在ArkStore中,点击 费用中心-开发商订单 即可查看
+
+## 提现
+
+在ArkStore中,点击 费用中心-提现申请 即可发起申请,后台审核完后会打款。
+
+微信分账功能正在接入。
\ No newline at end of file
diff --git "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/\345\272\224\347\224\250.md" "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/\345\272\224\347\224\250.md"
new file mode 100644
index 000000000..2ea5cd1e2
--- /dev/null
+++ "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ ArkID\345\274\200\345\217\221\345\225\206/\345\272\224\347\224\250.md"
@@ -0,0 +1,98 @@
+# 应用接入
+
+## 创建应用
+
+### SaaS应用
+
+#### OIDC
+
+1.在ArkID中点击应用管理-应用列表-本地应用,点击开发与代理,跳转到ArkStore
+
+[](https://x.imgtu.com/i/Bbbgph)
+
+2.在ArkStore中点击开发商-应用管理-中心ArkID-应用管理-应用列表-本地应用-创建,来创建应用
+点击创建
+[](https://x.imgtu.com/i/Bb8yEt)
+
+创建应用
+[](https://x.imgtu.com/i/Bb8NyJ)
+
+3.对新创建的应用,点击协议配置,选择OIDC-platform协议,并完成应用接入
+
+[](https://x.imgtu.com/i/Bb8EoL)
+
+!!! 提示
+ OIDC-platform就是OIDC协议,只是该类型的应用可以被整个平台所有租户访问。你可以按照OIDC的接入流程接入即可,只是用户参数中会增加:租户标识。
+
+4.点击开发商-SaaS应用-添加应用,接入方式选择OIDC,应用ID输入步骤2中创建的应用ID(可通过点击步骤2中创建应用的编辑按钮来获取)
+点击添加应用
+[](https://x.imgtu.com/i/Bb83p7)
+
+添加应用
+[](https://x.imgtu.com/i/Bb8u2B)
+
+获取应用ID
+[](https://x.imgtu.com/i/Bb8qUG)
+
+5.设置价格,详情请见[**价格规则**](../#_2)
+点击设置价格
+[](https://x.imgtu.com/i/Bb8l8I)
+
+设置价格
+[](https://x.imgtu.com/i/Bb87tV)
+
+6.提交审核
+
+[](https://x.imgtu.com/i/Bb8l8I)
+
+
+7.龙归审核通过后,应用上架完成,所有ArkID的用户在其应用商店中都能看到该应用。
+
+#### 自定义认证协议
+
+如果你的应用使用的是其它非标准协议,请联系我们。
+
+#### 账密代填
+
+如果你的应用暂时无法通过OIDC接入,我们还推荐使用账密代填的方式。
+
+创建账密代填应用与创建OIDC应用相似,只需在步骤3中协议配置选择AutoFormFill,同时在步骤4中选择表单代填即可。
+
+账密代填并非单点登录的协议,只是会在浏览器中记录对应站点的账号密码,并自动填入并点击登录。
+
+如果该网站使用了如验证码等额外的方式,则不适用账密代填。
+
+#### 推广链接
+
+如果当前应用不支持上述各类情况,你可以仅仅上传一个ArkID的专属推广链接,并记录下该用户后续的注册,登录,付费等行为,用来作为与ArkID分账的依据。
+
+通常这种情况,支付会使用内付费的形式,你需要联系我们。
+
+
+### 私有化部署应用
+
+1.在ArkID中点击应用管理-应用列表-本地应用,点击开发与代理,跳转到ArkStore
+
+[](https://x.imgtu.com/i/Bbbgph)
+
+2.在Arkstore中点击开发商-应用管理-私有部署应用-添加应用,上传Helm Charts的tgz格式压缩包
+点击创建
+[](https://x.imgtu.com/i/Bb8gpP)
+
+上传文件
+[](https://x.imgtu.com/i/Bb8hGw)
+
+5.设置价格,详情请见[**价格规则**](../#_2)
+点击设置价格
+[](https://x.imgtu.com/i/Bb8Kje)
+
+设置价格
+[](https://x.imgtu.com/i/Bb87tV)
+
+4.提交审核
+
+[](https://x.imgtu.com/i/Bb8Kje)
+
+7.龙归审核通过后,应用上架完成,所有ArkID的用户在其应用商店中都能看到该应用。
+
+
diff --git "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ \345\274\200\345\217\221\345\225\206.md" "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ \345\274\200\345\217\221\345\225\206.md"
deleted file mode 100644
index 8ef5b7c71..000000000
--- "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/ \345\274\200\345\217\221\345\225\206.md"
+++ /dev/null
@@ -1,101 +0,0 @@
-# ArkID开发商
-
-如果您有开发能力,或者独立运营自己的SaaS产品,只通过ArkID账号访问ArkStore,即可成为ArkID开发商。
-
-## 开发商条件
-
-* 任何个人或企业
-* 有开发自研能力
-* 拥有ArkID账号
-* 访问ArkStore
-
-开发商可以向ArkID生态提供生产两类产品:**ArkID插件** 与 **SaaS应用**。
-
-## 创建插件或应用
-
-### ArkID插件
-
-1. 访问ArkStore
-1. 点击开发商-仓库管理,上传插件所在的github仓库或者zip压缩包
-
- !!! 注意
- ArkStore会通过解析插件下config.json文件,来生成插件记录
-
-2. 设置价格,详情请见[价格规则](#_3)
-3. 提交审批
-4. 通过即上架完成,所有ArkID的用户在其插件商店中都能看到该插件了。
-
-### SaaS应用
-
-#### OIDC
-
-1. 访问官方中心ArkID。
-1. 创建应用,选择OIDC-platform协议,并完成应用接入。
-
- !!! 提示
- OIDC-platform就是OIDC协议,只是该类型的应用可以被整个平台所有租户访问。你可以按照OIDC的接入流程接入即可,只是用户参数中会增加:租户标识。
-
-2. 访问ArkStore
-3. 点击开发商-应用管理,创建应用,绑定在ArkID中创建的应用。
-4. 设置价格,详情请见[价格规则](#_3)
-5. 提交审核
-6. 通过即上架完成,所有ArkID的用户在其应用商店中都能看到该应用了。
-
-#### 自定义认证协议
-
-如果你的应用使用的是其它非标准协议,请联系我们。
-
-#### 账密代填
-
-如果你的应用暂时无法通过OIDC接入,我们还推荐使用账密代填的方式。
-
-账密代填并非单点登录的协议,只是会在浏览器中记录对应站点的账号密码,并自动填入并点击登录。
-
-如果该网站使用了如验证码等额外的方式,则不适用账密代填。
-
-#### 推广链接
-
-如果当前应用不支持上述各类情况,你可以仅仅上传一个ArkID的专属推广链接,并记录下该用户后续的注册,登录,付费等行为,用来作为与ArkID分账的依据。
-
-通常这种情况,支付会使用内付费的形式,你需要联系我们。
-
-## 价格规则
-
-### 商店支付
-
-插件只能选择商店支付的方式,应用可以是商店支付或者应用内支付的方式。
-
-无论是插件还是应用,开发商都可以设置价格。
-
-价格分两类:**购买价格** 与 **租赁价格**,两种价格的组成是相同的。
-
-价格包含两个元素:**市场指导价** 与 **成本折扣**
-
-市场指导价的单位为: x元/y人/z天
-
-* 当x=0,则被视为免费
-* 当y=0,则被认为不限人数
-* 当z=0,则被认为不限天数
-
-成本折扣可以为0-1之间的任何一个两位小数。
-
-!!! 注意
- 每成交一个产品,开发商实际获得的收益为:市场指导价 * 成本折扣
-
-价格可以设置多条,以满足不同的定价策略。
-
-### 应用内支付
-
-你的应用可以不通过商店支付,而是用户自行在你的应用内支付页面完成支付。
-
-这种情况,需要你跟龙归签署相关合作协议,并商定好分成比例,定期与龙归结算即可。
-
-## 订单记录
-
-在ArkStore中,点击 费用中心-开发商订单 即可查看
-
-## 提现
-
-在ArkStore中,点击 费用中心-提现申请 即可发起申请,后台审核完后会打款。
-
-微信分账功能正在接入。
\ No newline at end of file
diff --git "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/index.md" "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/index.md"
index 9a12d2718..23fda81f7 100644
--- "a/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/index.md"
+++ "b/docs/ \345\225\206\344\270\232\345\220\210\344\275\234\346\214\207\345\215\227/index.md"
@@ -4,7 +4,7 @@
您可以通过以下三种方式来参与并共建ArkID生态:
-* 成为[**ArkID开发商**](./%20%20开发商/)
+* 成为[**ArkID开发商**](./%20%20ArkID开发商/)
* 成为[**ArkID代理商**](./%20代理商/)
* 成为[**ArkID运营商**](./%20运营商/)
diff --git a/extension_root/com_longgui_auto_form_fill/arkid_chrome_extension.zip b/extension_root/com_longgui_auto_form_fill/arkid_chrome_extension.zip
index 565f89152..b3dba7065 100644
Binary files a/extension_root/com_longgui_auto_form_fill/arkid_chrome_extension.zip and b/extension_root/com_longgui_auto_form_fill/arkid_chrome_extension.zip differ