mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-05 13:47:45 +08:00
docs: relation repository & acl (#848)
* docs: relation-repository * docs: has many repository * docs: acl * docs: acl * docs: acl * docs: acl * docs: acl/AllowManager * docs: acl/ACLAvailableAction * docs: acl * docs: clean up * feat: doc menus Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
460dbcbc7f
commit
d805fafbfc
@ -55,7 +55,7 @@ export default {
|
|||||||
'/development/guide/i18n',
|
'/development/guide/i18n',
|
||||||
'/development/guide/migration',
|
'/development/guide/migration',
|
||||||
{
|
{
|
||||||
title: 'UI Schema Designer',
|
title: 'UI 设计器',
|
||||||
type: 'subMenu',
|
type: 'subMenu',
|
||||||
children: [
|
children: [
|
||||||
// '/development/guide/ui-schema-designer/index',
|
// '/development/guide/ui-schema-designer/index',
|
||||||
@ -72,7 +72,6 @@ export default {
|
|||||||
},
|
},
|
||||||
'/development/guide/ui-router',
|
'/development/guide/ui-router',
|
||||||
'/development/guide/settings-center',
|
'/development/guide/settings-center',
|
||||||
'/development/guide/commands',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -177,7 +176,10 @@ export default {
|
|||||||
'/api/database/collection',
|
'/api/database/collection',
|
||||||
'/api/database/field',
|
'/api/database/field',
|
||||||
'/api/database/repository',
|
'/api/database/repository',
|
||||||
'/api/database/relation-repository',
|
'/api/database/relation-repository/has-one-repository',
|
||||||
|
'/api/database/relation-repository/has-many-repository',
|
||||||
|
'/api/database/relation-repository/belongs-to-repository',
|
||||||
|
'/api/database/relation-repository/belongs-to-many-repository',
|
||||||
'/api/database/operators',
|
'/api/database/operators',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -192,8 +194,17 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '@nocobase/actions',
|
title: '@nocobase/acl',
|
||||||
path: '/api/actions',
|
type: 'subMenu',
|
||||||
|
children: [
|
||||||
|
'/api/acl/index',
|
||||||
|
'/api/acl/acl',
|
||||||
|
'/api/acl/acl-role',
|
||||||
|
'/api/acl/acl-resource',
|
||||||
|
'/api/acl/acl-available-action',
|
||||||
|
'/api/acl/acl-available-strategy',
|
||||||
|
'/api/acl/allow-manager',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '@nocobase/client',
|
title: '@nocobase/client',
|
||||||
@ -225,14 +236,14 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: '@nocobase/acl',
|
|
||||||
path: '/api/acl',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '@nocobase/cli',
|
title: '@nocobase/cli',
|
||||||
path: '/api/cli',
|
path: '/api/cli',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '@nocobase/actions',
|
||||||
|
path: '/api/actions',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '@nocobase/sdk',
|
title: '@nocobase/sdk',
|
||||||
path: '/api/sdk',
|
path: '/api/sdk',
|
||||||
|
@ -1 +0,0 @@
|
|||||||
# ACL
|
|
19
docs/zh-CN/api/acl/acl-available-action.md
Normal file
19
docs/zh-CN/api/acl/acl-available-action.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# ACLAvailableAction
|
||||||
|
|
||||||
|
用于表示一个可用 ACL Action 的数据结构。
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `constructor(public name: string, public options: AvailableActionOptions)`
|
||||||
|
|
||||||
|
实例化 ACLAvailableAction
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
* name: string - 动作名称
|
||||||
|
* options: AvailableActionOptions
|
||||||
|
* displayName - action 显示名称
|
||||||
|
* aliases - action 别名
|
||||||
|
* resource - action 所属资源名称
|
||||||
|
* onNewRecord - action 是否是在创建新的数据库记录
|
||||||
|
* allowConfigureFields - action 是否允许配置字段
|
24
docs/zh-CN/api/acl/acl-available-strategy.md
Normal file
24
docs/zh-CN/api/acl/acl-available-strategy.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# ACLAvailableStrategy
|
||||||
|
|
||||||
|
ACL 角色的权限策略,可以使用其判断角色是否有权限访问资源。
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `constructor(acl: ACL, options: AvailableStrategyOptions)`
|
||||||
|
|
||||||
|
构造函数,创建一个 `ACLAvailableStrategy` 实例。
|
||||||
|
|
||||||
|
### `allow(resourceName: string, actionName: string)`
|
||||||
|
|
||||||
|
判断此策略是否允许给定的资源和动作通过鉴权。
|
||||||
|
|
||||||
|
## 基础数据结构
|
||||||
|
|
||||||
|
### `AvailableStrategyOptions`
|
||||||
|
|
||||||
|
策略定义参数,用以描述一组权限配置规则。
|
||||||
|
|
||||||
|
* displayName - 策略名称
|
||||||
|
* allowConfigure - 此策略是否拥有 **配置资源** 的权限,设置此项为`true`之后,请求判断在 `ACL` 中注册成为 `configResources` 资源的权限,会返回通过。
|
||||||
|
* actions - 策略内的 actions 列表,支持通配符 `*`
|
||||||
|
* resource - 策略内的 resource 定义,支持通配符 `*`
|
57
docs/zh-CN/api/acl/acl-resource.md
Normal file
57
docs/zh-CN/api/acl/acl-resource.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# ACLResource
|
||||||
|
|
||||||
|
ACLResource,ACL 系统中的资源类。在 ACL 系统中,为用户授予权限时会自动创建对应的资源。
|
||||||
|
|
||||||
|
## 基础数据结构
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### `ResourceActions`
|
||||||
|
|
||||||
|
Action 集合对象:
|
||||||
|
|
||||||
|
* key 表示 action 的名称
|
||||||
|
* value 表示 action 的配置参数,见 [`RoleActionParams`](#RoleActionParams)。
|
||||||
|
|
||||||
|
**定义**
|
||||||
|
```typescript
|
||||||
|
type ResourceActions = { [key: string]: RoleActionParams };
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `constructor(options: AclResourceOptions)`
|
||||||
|
|
||||||
|
创建 `ACLResource` 实例
|
||||||
|
|
||||||
|
**AclResourceOptions 参数**
|
||||||
|
|
||||||
|
* options - 资源配置参数
|
||||||
|
* name - 资源名称
|
||||||
|
* role - 资源所属角色
|
||||||
|
* actions - ResourceActions 对象,定义资源的 Action
|
||||||
|
|
||||||
|
### `getActions()`
|
||||||
|
|
||||||
|
获取资源的所有 Action,返回结果为 `ResourceActions` 对象。
|
||||||
|
|
||||||
|
### `getAction(name: string)`
|
||||||
|
|
||||||
|
根据名称返回 Action 的参数配置,返回结果为 `RoleActionParams` 对象。
|
||||||
|
|
||||||
|
## `setAction(name: string, params: RoleActionParams)`
|
||||||
|
|
||||||
|
在资源内部设置一个 Action 的参数配置,返回结果为 `RoleActionParams` 对象。
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
* name - 要设置的 action 名称
|
||||||
|
* params - [`RoleActionParams`](#RoleActionParams)
|
||||||
|
|
||||||
|
## `setActions(actions: ResourceActions)`
|
||||||
|
|
||||||
|
批量调用 `setAction` 的便捷方法
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
* actions: [RoleActionParams](#RoleActionParams)
|
70
docs/zh-CN/api/acl/acl-role.md
Normal file
70
docs/zh-CN/api/acl/acl-role.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# ACL Role
|
||||||
|
|
||||||
|
ACLRole,ACL 系统中的用户角色类。在 ACL 系统中,通常使用 `acl.define` 定义角色。
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `constructor(public acl: ACL, public name: string)`
|
||||||
|
|
||||||
|
* acl - ACL 实例
|
||||||
|
* name - 角色名称
|
||||||
|
|
||||||
|
### `grantAction(path: string, options?: RoleActionParams)`
|
||||||
|
|
||||||
|
为角色授予 Action 权限
|
||||||
|
|
||||||
|
* path - 资源Action路径,如 `posts:edit`,表示 `posts` 资源的 `edit` Action, 资源名称和 Action 之间使用 `:` 冒号分隔。
|
||||||
|
* options? - 配置参数,见 [`RoleActionParams`](#RoleActionParams)。
|
||||||
|
|
||||||
|
|
||||||
|
## 参数
|
||||||
|
|
||||||
|
### `RoleActionParams`
|
||||||
|
|
||||||
|
RoleActionParams 为授权时,对应 action 的可配置参数,用以实现更细粒度的权限控制。
|
||||||
|
|
||||||
|
* fields - 可访问的字段
|
||||||
|
```typescript
|
||||||
|
acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
actions: {
|
||||||
|
'posts:view': {
|
||||||
|
// admin 用户可以请求 posts:view action,但是只有 fields 配置的字段权限
|
||||||
|
fields: ["id", "title", "content"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
* filter - 权限资源过滤配置
|
||||||
|
```typescript
|
||||||
|
acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
actions: {
|
||||||
|
'posts:view': {
|
||||||
|
// admin 用户可以请求 posts:view action,但是列出的结果必须满足 filter 设置的条件。
|
||||||
|
filter: {
|
||||||
|
createdById: '{{ ctx.state.currentUser.id }}', // 支持模板语法,可以取 ctx 中的值,将在权限判断时替换
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
* own - 是否只能访问自己的数据
|
||||||
|
```typescript
|
||||||
|
const actionsWithOwn = {
|
||||||
|
'posts:view': {
|
||||||
|
"own": true //
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等价于
|
||||||
|
const actionsWithFilter = {
|
||||||
|
'posts:view': {
|
||||||
|
"filter": {
|
||||||
|
"createdById": "{{ ctx.state.currentUser.id }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* whitelist - 白名单,只有在白名单中的字段才能被访问
|
||||||
|
* blacklist - 黑名单,黑名单中的字段不能被访问
|
214
docs/zh-CN/api/acl/acl.md
Normal file
214
docs/zh-CN/api/acl/acl.md
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
# ACL
|
||||||
|
|
||||||
|
ACL 为权限管理类,系统中的角色与资源都可以在 ACL 中进行注册。
|
||||||
|
|
||||||
|
## 成员变量
|
||||||
|
|
||||||
|
### `availableActions: Map<string, AclAvailableAction>`
|
||||||
|
|
||||||
|
ACL 内的 `AclAvailableAction` 名称映射。
|
||||||
|
|
||||||
|
### `availableStrategy: Map<string, ACLAvailableStrategy>`
|
||||||
|
|
||||||
|
ACL 内的 [`ACLAvailableStrategy`](#ACLAvailableStrategy) 名称映射。
|
||||||
|
|
||||||
|
### `middlewares`
|
||||||
|
|
||||||
|
ACL 鉴权中间件。
|
||||||
|
|
||||||
|
### `roles: Map<string, ACLRole>`
|
||||||
|
|
||||||
|
ACL 内的 `ACLRole` 名称映射。
|
||||||
|
|
||||||
|
### `actionAlias: Map<string, string>`
|
||||||
|
|
||||||
|
Action 别名映射。
|
||||||
|
|
||||||
|
### `configResources: Array<string>`
|
||||||
|
|
||||||
|
配置资源列表。
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `constructor()`
|
||||||
|
|
||||||
|
构造函数,创建一个 `ACL` 实例。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ACL } from '@nocobase/database';
|
||||||
|
|
||||||
|
const acl = new ACL();
|
||||||
|
```
|
||||||
|
### `define(options: DefineOptions)`
|
||||||
|
|
||||||
|
定义系统角色
|
||||||
|
|
||||||
|
**DefineOptions 参数**
|
||||||
|
|
||||||
|
* `role` - 角色名称
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 定义一个名称为 admin 的角色
|
||||||
|
acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
* `allowConfigure` - 是否允许配置权限
|
||||||
|
* `strategy` - 角色的权限策略
|
||||||
|
* 可以为 `string`,为要使用的策略名,表示使用已定义的策略。
|
||||||
|
* 可以为 `AvailableStrategyOptions`,为该角色定义一个新的策略。
|
||||||
|
* `actions` - 定义角色时,可传入角色可访问的 `actions` 对象,
|
||||||
|
之后会依次调用 `aclRole.grantAction` 授予资源权限。详见 [`ResourceActionsOptions`](#ResourceActionsOptions)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
actions: {
|
||||||
|
'posts:edit': {}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 等同于
|
||||||
|
const role = acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
});
|
||||||
|
|
||||||
|
role.grantAction('posts:edit', {});
|
||||||
|
```
|
||||||
|
|
||||||
|
### `getRole(name: string): ACLRole`
|
||||||
|
|
||||||
|
根据角色名称返回角色对象
|
||||||
|
|
||||||
|
### `removeRole(name: string)`
|
||||||
|
|
||||||
|
根据角色名称移除角色
|
||||||
|
|
||||||
|
### `can({ role, resource, action }: CanArgs): CanResult | null`
|
||||||
|
|
||||||
|
鉴权函数,调用返回为`null`时,表示角色无权限,反之返回`CanResult`对象,表示角色有权限。
|
||||||
|
|
||||||
|
`can` 方法首先会判断角色是否有注册对应的 `Action` 权限,如果没有则会去判断角色的 `strategy` 是否匹配.
|
||||||
|
|
||||||
|
**CanArgs 参数**
|
||||||
|
|
||||||
|
* role - 角色名称
|
||||||
|
* resource - 资源名称
|
||||||
|
* action - 操作名称
|
||||||
|
|
||||||
|
**CanResult 参数**
|
||||||
|
|
||||||
|
* role - 角色名称
|
||||||
|
* resource - 资源名称
|
||||||
|
* action - 操作名称
|
||||||
|
* params - 注册权限时传入的参数
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
acl.define({
|
||||||
|
role: 'admin',
|
||||||
|
actions: {
|
||||||
|
'posts:edit': {
|
||||||
|
fields: ['title', 'content'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const canResult = acl.can({
|
||||||
|
role: 'admin',
|
||||||
|
resource: 'posts',
|
||||||
|
action: 'edit',
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* canResult = {
|
||||||
|
* role: 'admin',
|
||||||
|
* resource: 'posts',
|
||||||
|
* action: 'edit',
|
||||||
|
* params: {
|
||||||
|
* fields: ['title', 'content'],
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
acl.can({
|
||||||
|
role: 'admin',
|
||||||
|
resource: 'posts',
|
||||||
|
action: 'destroy',
|
||||||
|
}); // null
|
||||||
|
```
|
||||||
|
### `use(fn: any)`
|
||||||
|
|
||||||
|
向 middlewares 中添加中间件函数。
|
||||||
|
|
||||||
|
### `middleware()`
|
||||||
|
|
||||||
|
返回一个中间件函数,用于在 `@nocobase/server` 中使用。使用此 `middleware` 之后,`@nocobase/server` 在每次请求处理之前都会进行权限判断。
|
||||||
|
|
||||||
|
### `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`
|
||||||
|
|
||||||
|
注册一个可用的权限策略
|
||||||
|
|
||||||
|
### `registerConfigResource(name: string)`
|
||||||
|
|
||||||
|
将传入的资源名称设置为**配置资源**。配置资源是指这样的一种资源,这些资源的改动会调用`ACL`中的角色、权限注册相关方法,例如用户、权限、角色等,这些资源就需要被设置为配置资源。
|
||||||
|
|
||||||
|
### `registerConfigResources(names: string[])`
|
||||||
|
|
||||||
|
`registerConfigResource` 的批量方法
|
||||||
|
|
||||||
|
### `isConfigResource(name: string)`
|
||||||
|
|
||||||
|
判断传入的资源名称是否为配置资源
|
||||||
|
|
||||||
|
### `setAvailableAction(name: string, options: AvailableActionOptions = {})`
|
||||||
|
|
||||||
|
设置 ACL 中有效的 Action 名称。
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
* name - action 名称
|
||||||
|
* options - action 选项
|
||||||
|
* displayName - action 显示名称
|
||||||
|
* aliases - action 别名
|
||||||
|
* resource - action 所属资源名称
|
||||||
|
* onNewRecord - action 是否是在创建新的数据库记录
|
||||||
|
* allowConfigureFields - action 是否允许配置字段
|
||||||
|
|
||||||
|
|
||||||
|
### `getAvailableAction(name: string)`
|
||||||
|
|
||||||
|
获取 ACL 中有效的 Action。
|
||||||
|
|
||||||
|
### `setAvailableStrategy(name: string, options: AvailableStrategyOptions)`
|
||||||
|
|
||||||
|
设置可用的权限策略,详见 [`AvailableStrategyOptions`](#AvailableStrategyOptions)
|
||||||
|
|
||||||
|
### `allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc)`
|
||||||
|
|
||||||
|
在不指定角色的情况下,开放资源的访问权限。
|
||||||
|
举例来说,例如登录操作,可以被公开访问:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 注册 users:login 可以被公开访问
|
||||||
|
acl.allow('users', 'login');
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
* resourceName - 资源名称
|
||||||
|
* actionNames - 资源动作名
|
||||||
|
* condition? - 配置生效条件
|
||||||
|
* 传入 `string`,表示使用已定义的条件,注册条件使用 `acl.allowManager.registerCondition` 方法。
|
||||||
|
```typescript
|
||||||
|
acl.allowManager.registerAllowCondition('superUser', async () => {
|
||||||
|
return ctx.state.user?.id === 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 开放 users:list 的权限,条件为 superUser
|
||||||
|
acl.allow('users', 'list', 'superUser');
|
||||||
|
```
|
||||||
|
* 传入 ConditionFunc,可接收 `ctx` 参数,返回 `boolean`,表示是否生效。
|
||||||
|
```typescript
|
||||||
|
// 当用户ID为1时,可以访问 user:list
|
||||||
|
acl.allow('users', 'list', (ctx) => {
|
||||||
|
return ctx.state.user?.id === 1;
|
||||||
|
});
|
||||||
|
```
|
55
docs/zh-CN/api/acl/allow-manager.md
Normal file
55
docs/zh-CN/api/acl/allow-manager.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# AllowManager
|
||||||
|
|
||||||
|
开放权限管理
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
### `constructor(public acl: ACL)`
|
||||||
|
|
||||||
|
实例化 AllowManger
|
||||||
|
|
||||||
|
### `allow(resourceName: string, actionName: string, condition?: string | ConditionFunc)`
|
||||||
|
|
||||||
|
注册开放权限
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// users:login 可以被公开访问
|
||||||
|
allowManager.allow('users', 'login');
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
* resourceName - 资源名称
|
||||||
|
* actionName - 资源动作名
|
||||||
|
* condition? - 配置生效条件
|
||||||
|
* 传入 `string`,表示使用已定义的条件,注册条件使用 `acl.allowManager.registerCondition` 方法。
|
||||||
|
```typescript
|
||||||
|
acl.allowManager.registerAllowCondition('superUser', async () => {
|
||||||
|
return ctx.state.user?.id === 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 开放 users:list 的权限,条件为 superUser
|
||||||
|
acl.allow('users', 'list', 'superUser');
|
||||||
|
```
|
||||||
|
* 传入 ConditionFunc,可接收 `ctx` 参数,返回 `boolean`,表示是否生效。
|
||||||
|
```typescript
|
||||||
|
// 当用户ID为1时,可以访问 user:list
|
||||||
|
acl.allow('users', 'list', (ctx) => {
|
||||||
|
return ctx.state.user?.id === 1;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### `registerAllowCondition(name: string, condition: ConditionFunc)`
|
||||||
|
|
||||||
|
注册开放权限条件
|
||||||
|
|
||||||
|
### `getAllowedConditions(resourceName: string, actionName: string): Array<ConditionFunc | true>`
|
||||||
|
|
||||||
|
获取已注册的开放条件
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
* resourceName - 资源名称
|
||||||
|
* actionName - 资源动作名
|
||||||
|
|
||||||
|
### `aclMiddleware()`
|
||||||
|
|
||||||
|
中间件,注入于 `acl` 实例中,用于判断是否开放权限,若根据条件判断为开放权限,则在 `acl` middleware 中会跳过权限检查。
|
||||||
|
|
12
docs/zh-CN/api/acl/index.md
Normal file
12
docs/zh-CN/api/acl/index.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# ACL 权限管理
|
||||||
|
|
||||||
|
ACL 为 Nocobase 中的权限控制模块。在 ACL 中注册角色、资源以及配置相应权限之后,即可对角色进行权限判断。
|
||||||
|
|
||||||
|
## 概念解释
|
||||||
|
|
||||||
|
* 角色 (`ACLRole`):权限判断的对象
|
||||||
|
* 资源 (`ACLResource`):在 Nocobase ACL 中,资源通常对应一个数据库表,概念上可类比为 Restful API 中的 Resource。
|
||||||
|
* Action:对资源的操作,如 `create`、`read`、`update`、`delete` 等。
|
||||||
|
* 策略 (`ACLAvailableStrategy`): 通常每个角色都有自己的权限策略,策略中定义了默认情况下的用户权限。
|
||||||
|
* 授权:在 `ACLRole` 实例中调用 `grantAction` 函数,为角色授予 `Action` 的访问权限。
|
||||||
|
* 鉴权:在 `ACL` 实例中调用 `can` 函数,函数返回结果既为用户的鉴权结果。
|
@ -1,87 +0,0 @@
|
|||||||
# RelationRepository
|
|
||||||
|
|
||||||
关系型数据仓库抽象类。
|
|
||||||
|
|
||||||
## 基类属性
|
|
||||||
|
|
||||||
### `db`
|
|
||||||
|
|
||||||
### `sourceCollection`
|
|
||||||
|
|
||||||
### `targetCollection`
|
|
||||||
|
|
||||||
### `associationField`
|
|
||||||
|
|
||||||
### `sourceKeyValue`
|
|
||||||
|
|
||||||
### `sourceInstance`
|
|
||||||
|
|
||||||
## HasOneRepository
|
|
||||||
|
|
||||||
### `find()`
|
|
||||||
|
|
||||||
### `update()`
|
|
||||||
|
|
||||||
### `destroy()`
|
|
||||||
|
|
||||||
### `remove()`
|
|
||||||
|
|
||||||
### `set()`
|
|
||||||
|
|
||||||
## BelongsToRepository
|
|
||||||
|
|
||||||
### `find()`
|
|
||||||
|
|
||||||
### `update()`
|
|
||||||
|
|
||||||
### `destroy()`
|
|
||||||
|
|
||||||
### `remove()`
|
|
||||||
|
|
||||||
### `set()`
|
|
||||||
|
|
||||||
## HasManyRepository
|
|
||||||
|
|
||||||
### `count()`
|
|
||||||
|
|
||||||
### `find()`
|
|
||||||
|
|
||||||
### `findOne()`
|
|
||||||
|
|
||||||
### `findAndCount()`
|
|
||||||
|
|
||||||
### `create()`
|
|
||||||
|
|
||||||
### `update()`
|
|
||||||
|
|
||||||
### `destroy()`
|
|
||||||
|
|
||||||
### `add()`
|
|
||||||
|
|
||||||
### `remove()`
|
|
||||||
|
|
||||||
### `set()`
|
|
||||||
|
|
||||||
## BelongsToManyRepository
|
|
||||||
|
|
||||||
### `count()`
|
|
||||||
|
|
||||||
### `find()`
|
|
||||||
|
|
||||||
### `findOne()`
|
|
||||||
|
|
||||||
### `findAndCount()`
|
|
||||||
|
|
||||||
### `create()`
|
|
||||||
|
|
||||||
### `update()`
|
|
||||||
|
|
||||||
### `destroy()`
|
|
||||||
|
|
||||||
### `add()`
|
|
||||||
|
|
||||||
### `remove()`
|
|
||||||
|
|
||||||
### `set()`
|
|
||||||
|
|
||||||
### `toggle()`
|
|
@ -0,0 +1,23 @@
|
|||||||
|
## BelongsToManyRepository
|
||||||
|
|
||||||
|
### `count()`
|
||||||
|
|
||||||
|
### `find()`
|
||||||
|
|
||||||
|
### `findOne()`
|
||||||
|
|
||||||
|
### `findAndCount()`
|
||||||
|
|
||||||
|
### `create()`
|
||||||
|
|
||||||
|
### `update()`
|
||||||
|
|
||||||
|
### `destroy()`
|
||||||
|
|
||||||
|
### `add()`
|
||||||
|
|
||||||
|
### `remove()`
|
||||||
|
|
||||||
|
### `set()`
|
||||||
|
|
||||||
|
### `toggle()`
|
@ -0,0 +1,3 @@
|
|||||||
|
## BelongsToRepository
|
||||||
|
|
||||||
|
`BelongsToRepository` 是用于处理 `BelongsTo` 关系的 `Repository`,它提供了一些便捷的方法来处理 `BelongsTo` 关系。其接口与 [HasOneRepository](#has-one-repository) 一致。
|
@ -0,0 +1,152 @@
|
|||||||
|
|
||||||
|
# HasManyRepository
|
||||||
|
|
||||||
|
`HasManyRepository` 是用于处理 `HasMany` 关系的 `Repository`。
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `find()`
|
||||||
|
|
||||||
|
查找关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async find(options?: FindOptions): Promise<M[]>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `FindOptions` | - | 参见 repository.find |
|
||||||
|
|
||||||
|
### `findOne()`
|
||||||
|
|
||||||
|
查找关联对象,仅返回一条记录
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async findOne(options?: FindOneOptions): Promise<M>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `FindOneOptions` | - | 参见 repository.findOne |
|
||||||
|
|
||||||
|
### `count()`
|
||||||
|
|
||||||
|
返回符合查询条件的记录数
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async count(options?: CountOptions)`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `CountOptions` | - | 参见 repository.count |
|
||||||
|
|
||||||
|
|
||||||
|
### `findAndCount()`
|
||||||
|
|
||||||
|
同时返回符合查询条件的记录集合与记录数
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `FindAndCountOptions` | - | 参见 repository.findAndCount |
|
||||||
|
|
||||||
|
|
||||||
|
### `create()`
|
||||||
|
|
||||||
|
创建关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async create(options?: CreateOptions): Promise<M>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `CreateOptions` | - | 参见 repository.create |
|
||||||
|
|
||||||
|
|
||||||
|
### `update()`
|
||||||
|
|
||||||
|
更新符合条件的关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async update(options?: UpdateOptions): Promise<M>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `UpdateOptions` | - | 参见 repository.update |
|
||||||
|
|
||||||
|
|
||||||
|
### `destroy()`
|
||||||
|
|
||||||
|
删除符合条件的关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async destroy(options?: TK | DestroyOptions): Promise<M>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `TK \|DestroyOptions` | - | 传入删除对象的 `targetKeyId`,或者 `targetKeyId` 数组。需传 `transaction` 时 使用 `DestroyOptions` 类型 |
|
||||||
|
|
||||||
|
### `add()`
|
||||||
|
|
||||||
|
添加关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
* `async add(options: TargetKey | TargetKey[] | AssociatedOptions)`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `TargetKey` | - | 关联对象的 `targetKeyId` |
|
||||||
|
| `options` | `TargetKey[]` | - | 多个关联对象的 `targetKeyId` 数组 |
|
||||||
|
| `options` | `AssociatedOptions` | - | `options.tk`, 为 `targetKeyId` 或者 `targetKeyId` 数组;`options.transaction`,为 `Transaction` 对象 |
|
||||||
|
|
||||||
|
|
||||||
|
### `remove()`
|
||||||
|
|
||||||
|
移除符合条件的关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
* `async remove(options: TargetKey | TargetKey[] | AssociatedOptions)`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) |
|
||||||
|
|
||||||
|
|
||||||
|
### `set()`
|
||||||
|
|
||||||
|
设置当前关系的关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async set(options: TargetKey | TargetKey[] | AssociatedOptions)`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `TargetKey \| TargetKey[] \| AssociatedOptions` | - | 同 [add](#add) |
|
@ -0,0 +1,180 @@
|
|||||||
|
# HasOneRepository
|
||||||
|
`HasOneRepository` 为 `HasOne` 类型的关联 Repository。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const User = db.collection({
|
||||||
|
name: 'users',
|
||||||
|
fields: [
|
||||||
|
{ type: 'hasOne', name: 'profile' },
|
||||||
|
{ type: 'string', name: 'name' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const Profile = db.collection({
|
||||||
|
name: 'profiles',
|
||||||
|
fields: [{ type: 'string', name: 'avatar' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = await User.repository.create({
|
||||||
|
values: { name: 'u1' },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建 HasOneRepository 实例
|
||||||
|
const userProfileRepository = new HasOneRepository(User, 'profile', user.get('id'));
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `create(options?: CreateOptions)`
|
||||||
|
创建关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async create(options?: CreateOptions): Promise<Model>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `CreateOptions` | - | 参见 repository.create |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const profile = await UserProfileRepository.create({
|
||||||
|
values: { avatar: 'avatar1' },
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(profile.toJSON());
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
avatar: 'avatar1',
|
||||||
|
userId: 1,
|
||||||
|
updatedAt: 2022-09-24T13:59:40.025Z,
|
||||||
|
createdAt: 2022-09-24T13:59:40.025Z
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### `find()`
|
||||||
|
|
||||||
|
查找关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async find(options?: SingleRelationFindOption): Promise<Model<any> | null>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options.fields` | `Fields` | - | 参见 repository.find.fields |
|
||||||
|
| `options.except` | `Except` | - | 参见 repository.find.except |
|
||||||
|
| `options.appends` | `Appends` | - | 参见 repository.find.appends |
|
||||||
|
| `options.filter` | `Filter` | - | 参见 repository.find.filter |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const profile = await UserProfileRepository.find();
|
||||||
|
// 关联对象不存在时,返回 null
|
||||||
|
```
|
||||||
|
|
||||||
|
### `update()`
|
||||||
|
|
||||||
|
更新关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async update(options: UpdateOptions): Promise<Model>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | `UpdateOptions` | - | 参见 repository.update |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const profile = await UserProfileRepository.update({
|
||||||
|
values: { avatar: 'avatar2' },
|
||||||
|
});
|
||||||
|
|
||||||
|
profile.get('avatar'); // 'avatar2'
|
||||||
|
```
|
||||||
|
|
||||||
|
### `remove()`
|
||||||
|
|
||||||
|
移除关联对象,仅解除关联关系,不删除关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async remove(options?: Transactionable): Promise<void>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options.transaction` | `Transaction` | - | Transaction |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await UserProfileRepository.remove();
|
||||||
|
await UserProfileRepository.find() == null; // true
|
||||||
|
|
||||||
|
await Profile.repository.count() === 1; // true
|
||||||
|
```
|
||||||
|
|
||||||
|
### `destroy()`
|
||||||
|
|
||||||
|
删除关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async destroy(options?: Transactionable): Promise<Boolean>`
|
||||||
|
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options.transaction` | `Transaction` | - | Transaction |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await UserProfileRepository.destroy();
|
||||||
|
await UserProfileRepository.find() == null; // true
|
||||||
|
await Profile.repository.count() === 0; // true
|
||||||
|
```
|
||||||
|
|
||||||
|
### `set()`
|
||||||
|
|
||||||
|
设置关联对象
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `async set(options: TargetKey | SetOption): Promise<void>`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `options` | ` TargetKey \| SetOption` | - | 需要 set 的对象的 targetKey,如果需要一同传入 transaction 则修改为 object 类型参数 |
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const newProfile = await Profile.repository.create({
|
||||||
|
values: { avatar: 'avatar2' },
|
||||||
|
});
|
||||||
|
|
||||||
|
await UserProfileRepository.set(newProfile.get('id'));
|
||||||
|
|
||||||
|
(await UserProfileRepository.find()).get('id') === newProfile.get('id'); // true
|
||||||
|
```
|
45
docs/zh-CN/api/database/relation-repository/index.md
Normal file
45
docs/zh-CN/api/database/relation-repository/index.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# RelationRepository
|
||||||
|
|
||||||
|
`RelationRepository` 是关系类型的 `Repository` 对象,`RelationRepository` 可以实现在不加载关联的情况下对关联数据进行操作。基于 `RelationRepository`,每种关联都派生出对应的实现,分别为
|
||||||
|
|
||||||
|
* [`HasOneRepository`](#has-one-repository)
|
||||||
|
* `HasManyRepository`
|
||||||
|
* `BelongsToRepository`
|
||||||
|
* `BelongsToManyRepository`
|
||||||
|
|
||||||
|
|
||||||
|
## 构造函数
|
||||||
|
|
||||||
|
**签名**
|
||||||
|
|
||||||
|
* `constructor(sourceCollection: Collection, association: string, sourceKeyValue: string | number)`
|
||||||
|
|
||||||
|
**参数**
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 默认值 | 描述 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `sourceCollection` | `Collection` | - | 关联中的参照关系(referencing relation)对应的 Collection |
|
||||||
|
| `association` | `string` | - | 关联名称 |
|
||||||
|
| `sourceKeyValue` | `string \| number` | - | 参照关系中对应的 key 值 |
|
||||||
|
|
||||||
|
|
||||||
|
## 基类属性
|
||||||
|
|
||||||
|
### `db: Database`
|
||||||
|
|
||||||
|
数据库对象
|
||||||
|
|
||||||
|
### `sourceCollection`
|
||||||
|
关联中的参照关系(referencing relation)对应的 Collection
|
||||||
|
|
||||||
|
### `targetCollection`
|
||||||
|
关联中被参照关系(referenced relation)对应的 Collection
|
||||||
|
|
||||||
|
### `association`
|
||||||
|
sequelize 中的与当前关联对应的 association 对象
|
||||||
|
|
||||||
|
### `associationField`
|
||||||
|
collection 中的与当前关联对应的字段
|
||||||
|
|
||||||
|
### `sourceKeyValue`
|
||||||
|
参照关系中对应的 key 值
|
@ -1,4 +1,4 @@
|
|||||||
# Middleware
|
# 中间件
|
||||||
|
|
||||||
## 添加方法
|
## 添加方法
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Settings Center
|
# 配置中心
|
||||||
|
|
||||||
<img src="./settings-tab.jpg" style="max-width: 100%;"/>
|
<img src="./settings-tab.jpg" style="max-width: 100%;"/>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# UI Router
|
# UI 路由
|
||||||
|
|
||||||
NocoBase Client 的 Router 基于 [React Router](https://v5.reactrouter.com/web/guides/quick-start),可以通过 `<RouteSwitch routes={[]} />` 来配置 ui routes,例子如下:
|
NocoBase Client 的 Router 基于 [React Router](https://v5.reactrouter.com/web/guides/quick-start),可以通过 `<RouteSwitch routes={[]} />` 来配置 ui routes,例子如下:
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ describe('acl', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should define role with predicate', () => {
|
it('should define role with predicate', () => {
|
||||||
acl.setAvailableAction('edit', {
|
acl.setAvailableAction('edit', {
|
||||||
type: 'old-data',
|
type: 'old-data',
|
||||||
|
@ -12,6 +12,6 @@ export interface AvailableActionOptions {
|
|||||||
allowConfigureFields?: boolean;
|
allowConfigureFields?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AclAvailableAction {
|
export class ACLAvailableAction {
|
||||||
constructor(public name: string, public options: AvailableActionOptions) {}
|
constructor(public name: string, public options: AvailableActionOptions) {}
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,6 @@ export interface AvailableStrategyOptions {
|
|||||||
resource?: '*';
|
resource?: '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function strategyValueMatched(strategy: StrategyValue, value: string) {
|
|
||||||
if (strategy === '*') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lodash.isString(strategy) && strategy === value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lodash.isArray(strategy) && strategy.includes(value)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const predicate = {
|
export const predicate = {
|
||||||
own: {
|
own: {
|
||||||
filter: {
|
filter: {
|
||||||
|
@ -53,7 +53,7 @@ export class ACLResource {
|
|||||||
this.actions.set(name, context.params);
|
this.actions.set(name, context.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
setActions(actions: { [key: string]: RoleActionParams }) {
|
setActions(actions: ResourceActions) {
|
||||||
for (const actionName of Object.keys(actions)) {
|
for (const actionName of Object.keys(actions)) {
|
||||||
this.setAction(actionName, actions[actionName]);
|
this.setAction(actionName, actions[actionName]);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ export interface RoleActionParams {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResourceActionsOptions {
|
export interface ResourceActionsOptions {
|
||||||
[actionName: string]: RoleActionParams;
|
[actionName: string]: RoleActionParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,33 +25,16 @@ export class ACLRole {
|
|||||||
return this.resources.get(name);
|
return this.resources.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
setResource(name: string, resource: ACLResource) {
|
|
||||||
this.resources.set(name, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setStrategy(value: string | AvailableStrategyOptions) {
|
public setStrategy(value: string | AvailableStrategyOptions) {
|
||||||
this.strategy = value;
|
this.strategy = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public grantResource(resourceName: string, options: ResourceActionsOptions) {
|
|
||||||
const resource = new ACLResource({
|
|
||||||
role: this,
|
|
||||||
name: resourceName,
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const [actionName, actionParams] of Object.entries(options)) {
|
|
||||||
resource.setAction(actionName, actionParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.resources.set(resourceName, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getResourceActionsParams(resourceName: string) {
|
public getResourceActionsParams(resourceName: string) {
|
||||||
const resource = this.getResource(resourceName);
|
const resource = this.getResource(resourceName);
|
||||||
return resource.getActions();
|
return resource.getActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public revokeResource(resourceName) {
|
public revokeResource(resourceName: string) {
|
||||||
for (const key of [...this.resources.keys()]) {
|
for (const key of [...this.resources.keys()]) {
|
||||||
if (key === resourceName || key.includes(`${resourceName}.`)) {
|
if (key === resourceName || key.includes(`${resourceName}.`)) {
|
||||||
this.resources.delete(key);
|
this.resources.delete(key);
|
||||||
|
@ -4,10 +4,10 @@ import EventEmitter from 'events';
|
|||||||
import parse from 'json-templates';
|
import parse from 'json-templates';
|
||||||
import compose from 'koa-compose';
|
import compose from 'koa-compose';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import { AclAvailableAction, AvailableActionOptions } from './acl-available-action';
|
import { ACLAvailableAction, AvailableActionOptions } from './acl-available-action';
|
||||||
import { ACLAvailableStrategy, AvailableStrategyOptions, predicate } from './acl-available-strategy';
|
import { ACLAvailableStrategy, AvailableStrategyOptions, predicate } from './acl-available-strategy';
|
||||||
import { ACLRole, RoleActionParams } from './acl-role';
|
import { ACLRole, ResourceActionsOptions, RoleActionParams } from './acl-role';
|
||||||
import { AllowManager } from './allow-manager';
|
import { AllowManager, ConditionFunc } from './allow-manager';
|
||||||
|
|
||||||
interface CanResult {
|
interface CanResult {
|
||||||
role: string;
|
role: string;
|
||||||
@ -19,10 +19,8 @@ interface CanResult {
|
|||||||
export interface DefineOptions {
|
export interface DefineOptions {
|
||||||
role: string;
|
role: string;
|
||||||
allowConfigure?: boolean;
|
allowConfigure?: boolean;
|
||||||
strategy?: string | Omit<AvailableStrategyOptions, 'acl'>;
|
strategy?: string | AvailableStrategyOptions;
|
||||||
actions?: {
|
actions?: ResourceActionsOptions;
|
||||||
[key: string]: RoleActionParams;
|
|
||||||
};
|
|
||||||
routes?: any;
|
routes?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ interface CanArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ACL extends EventEmitter {
|
export class ACL extends EventEmitter {
|
||||||
protected availableActions = new Map<string, AclAvailableAction>();
|
protected availableActions = new Map<string, ACLAvailableAction>();
|
||||||
protected availableStrategy = new Map<string, ACLAvailableStrategy>();
|
protected availableStrategy = new Map<string, ACLAvailableStrategy>();
|
||||||
protected middlewares: Toposort<any>;
|
protected middlewares: Toposort<any>;
|
||||||
|
|
||||||
@ -131,7 +129,7 @@ export class ACL extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setAvailableAction(name: string, options: AvailableActionOptions = {}) {
|
setAvailableAction(name: string, options: AvailableActionOptions = {}) {
|
||||||
this.availableActions.set(name, new AclAvailableAction(name, options));
|
this.availableActions.set(name, new ACLAvailableAction(name, options));
|
||||||
|
|
||||||
if (options.aliases) {
|
if (options.aliases) {
|
||||||
const aliases = lodash.isArray(options.aliases) ? options.aliases : [options.aliases];
|
const aliases = lodash.isArray(options.aliases) ? options.aliases : [options.aliases];
|
||||||
@ -150,7 +148,7 @@ export class ACL extends EventEmitter {
|
|||||||
return this.availableActions;
|
return this.availableActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAvailableStrategy(name: string, options: Omit<AvailableStrategyOptions, 'acl'>) {
|
setAvailableStrategy(name: string, options: AvailableStrategyOptions) {
|
||||||
this.availableStrategy.set(name, new ACLAvailableStrategy(this, options));
|
this.availableStrategy.set(name, new ACLAvailableStrategy(this, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +220,7 @@ export class ACL extends EventEmitter {
|
|||||||
this.middlewares.add(fn, options);
|
this.middlewares.add(fn, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
allow(resourceName: string, actionNames: string[] | string, condition?: any) {
|
allow(resourceName: string, actionNames: string[] | string, condition?: string | ConditionFunc) {
|
||||||
if (!Array.isArray(actionNames)) {
|
if (!Array.isArray(actionNames)) {
|
||||||
actionNames = [actionNames];
|
actionNames = [actionNames];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ACL } from './acl';
|
import { ACL } from './acl';
|
||||||
|
|
||||||
type ConditionFunc = (ctx: any) => Promise<boolean>;
|
export type ConditionFunc = (ctx: any) => Promise<boolean>;
|
||||||
|
|
||||||
export class AllowManager {
|
export class AllowManager {
|
||||||
protected skipActions = new Map<string, Map<string, string | ConditionFunc | true>>();
|
protected skipActions = new Map<string, Map<string, string | ConditionFunc | true>>();
|
||||||
@ -20,7 +20,7 @@ export class AllowManager {
|
|||||||
|
|
||||||
const roleInstance = await ctx.db.getRepository('roles').findOne({
|
const roleInstance = await ctx.db.getRepository('roles').findOne({
|
||||||
filter: {
|
filter: {
|
||||||
name: roleName
|
name: roleName,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,4 +4,3 @@ export * from './acl-available-strategy';
|
|||||||
export * from './acl-resource';
|
export * from './acl-resource';
|
||||||
export * from './acl-role';
|
export * from './acl-role';
|
||||||
export * from './skip-middleware';
|
export * from './skip-middleware';
|
||||||
|
|
||||||
|
@ -31,6 +31,23 @@ describe('has one repository', () => {
|
|||||||
await db.sync();
|
await db.sync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('create', async () => {
|
||||||
|
const user = await User.repository.create({
|
||||||
|
values: { name: 'u1' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const userProfileRepository = new HasOneRepository(User, 'profile', user['id']);
|
||||||
|
let profile = await userProfileRepository.find();
|
||||||
|
|
||||||
|
profile = await userProfileRepository.create({
|
||||||
|
values: {
|
||||||
|
avatar: 'avatar1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(profile.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
test('find', async () => {
|
test('find', async () => {
|
||||||
const user = await User.repository.create({
|
const user = await User.repository.create({
|
||||||
values: { name: 'u1' },
|
values: { name: 'u1' },
|
||||||
|
@ -20,7 +20,7 @@ export function getConfigByEnv() {
|
|||||||
database: process.env.DB_DATABASE,
|
database: process.env.DB_DATABASE,
|
||||||
host: process.env.DB_HOST,
|
host: process.env.DB_HOST,
|
||||||
port: process.env.DB_PORT,
|
port: process.env.DB_PORT,
|
||||||
dialect: process.env.DB_DIALECT,
|
dialect: process.env.DB_DIALECT || 'sqlite',
|
||||||
logging: process.env.DB_LOGGING === 'on' ? console.log : false,
|
logging: process.env.DB_LOGGING === 'on' ? console.log : false,
|
||||||
storage:
|
storage:
|
||||||
process.env.DB_STORAGE && process.env.DB_STORAGE !== ':memory:'
|
process.env.DB_STORAGE && process.env.DB_STORAGE !== ':memory:'
|
||||||
|
@ -53,7 +53,7 @@ export abstract class RelationRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@transaction()
|
@transaction()
|
||||||
async create(options?: CreateOptions): Promise<any> {
|
async create(options?: CreateOptions): Promise<Model> {
|
||||||
const createAccessor = this.accessors().create;
|
const createAccessor = this.accessors().create;
|
||||||
|
|
||||||
const guard = UpdateGuard.fromOptions(this.targetModel, options);
|
const guard = UpdateGuard.fromOptions(this.targetModel, options);
|
||||||
|
@ -43,7 +43,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async find(options?: SingleRelationFindOption): Promise<Model<any>> {
|
async find(options?: SingleRelationFindOption): Promise<Model<any> | null> {
|
||||||
const transaction = await this.getTransaction(options);
|
const transaction = await this.getTransaction(options);
|
||||||
const findOptions = this.buildQueryOptions({
|
const findOptions = this.buildQueryOptions({
|
||||||
...options,
|
...options,
|
||||||
|
Loading…
Reference in New Issue
Block a user