diff --git a/.gitignore b/.gitignore index b35881ad9..90ab921ab 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ build package-lock.json scripts/local *tsbuildinfo +src/oak-app-domain \ No newline at end of file diff --git a/es/checkers/index.d.ts b/es/checkers/index.d.ts index 587c253bf..e4cd6934d 100644 --- a/es/checkers/index.d.ts +++ b/es/checkers/index.d.ts @@ -1,2 +1,2 @@ -declare const checkers: (import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker)[]; +declare const checkers: (import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker)[]; export default checkers; diff --git a/es/checkers/user.d.ts b/es/checkers/user.d.ts index 1fe61443a..54f3f3278 100644 --- a/es/checkers/user.d.ts +++ b/es/checkers/user.d.ts @@ -3,3 +3,4 @@ import { EntityDict } from '../oak-app-domain'; import { RuntimeCxt } from "../types/RuntimeCxt"; declare const checkers: Checker[]; export default checkers; +export declare const UserCheckers: Checker[]; diff --git a/es/checkers/user.js b/es/checkers/user.js index a3df038b8..899867cd9 100644 --- a/es/checkers/user.js +++ b/es/checkers/user.js @@ -1,5 +1,6 @@ import { judgeRelation } from "oak-domain/lib/store/relation"; import { OakInputIllegalException, OakUserUnpermittedException } from "oak-domain/lib/types"; +import { checkFilterContains } from 'oak-domain/lib/store/filter'; const checkers = [ { type: 'row', @@ -10,14 +11,15 @@ const checkers = [ } }, { - type: 'relation', + type: 'logical', action: ['remove', 'disable', 'enable'], entity: 'user', - relationFilter: () => { + checker: (operation, context) => { // 只有root才能进行操作 - throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); - }, - errMsg: '越权操作', + if (!context.isRoot()) { + throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); + } + } }, { type: 'data', @@ -38,48 +40,41 @@ const checkers = [ }, errMsg: '不能禁用root用户', }, - // { - // type: 'row', - // action: 'select', - // entity: 'user', - // filter: (operation, context) => { - // const systemId = context.getSystemId(); - // // todo 查询用户 先不加systemId - // if (systemId) { - // return { - // id: { - // $in: { - // entity: 'userSystem', - // data: { - // userId: 1, - // }, - // filter: { - // systemId, - // }, - // }, - // }, - // }; - // } - // }, - // }, +]; +export default checkers; +export const UserCheckers = [ { entity: 'user', action: 'update', - type: 'relation', - relationFilter: (operation, context) => { + type: 'logical', + checker: (operation, context) => { + // 在大部分应用中,除了root,其他人不应该有权利更新其他人信息,但是shadow用户应当除外 + // 但这些条件不一定对所有的应用都成立,应用如果有更复杂的用户相互更新策略,就不要引入这个checker + // 这也是个例子,如何对user这样的特殊对象进行权限控制 const userId = context.getCurrentUserId(); - const { data } = operation; + if (context.isRoot()) { + return; + } + const { filter, data } = operation; for (const attr in data) { const rel = judgeRelation(context.getSchema(), 'user', attr); - if (rel === 1) { - return { - id: userId, - }; + if (rel !== 1) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); } } - return undefined; + const result = checkFilterContains('user', context, { + id: userId, + }, filter, true); + if (result instanceof Promise) { + return result.then((r) => { + if (!r) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } + }); + } + if (!result) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } }, - errMsg: '您不能更新他人信息', } ]; -export default checkers; diff --git a/es/components/config/style/platform/index.d.ts b/es/components/config/style/platform/index.d.ts index bd3579c54..aceba872e 100644 --- a/es/components/config/style/platform/index.d.ts +++ b/es/components/config/style/platform/index.d.ts @@ -1,7 +1,7 @@ import { Style } from '../../../../types/Style'; declare const _default: (props: import("oak-frontend-base").ReactComponentProps) => import("react").ReactElement>; diff --git a/es/components/config/upsert/index.d.ts b/es/components/config/upsert/index.d.ts index 6a8e95a3d..26655e31f 100644 --- a/es/components/config/upsert/index.d.ts +++ b/es/components/config/upsert/index.d.ts @@ -1,7 +1,7 @@ import { Config } from '../../../types/Config'; declare const _default: (props: import("oak-frontend-base").ReactComponentProps) => import("react").ReactElement>; diff --git a/es/components/extraFile/commit/index.d.ts b/es/components/extraFile/commit/index.d.ts index a3f91aa67..1131ae5a3 100644 --- a/es/components/extraFile/commit/index.d.ts +++ b/es/components/extraFile/commit/index.d.ts @@ -12,9 +12,9 @@ declare const _default: & import("react").ButtonHTMLAttributes, "id" | "onMouseUp" | "onMouseDown" | "onTouchStart" | "onTouchEnd"> & { + } & Pick & import("react").ButtonHTMLAttributes, "id" | "onMouseDown" | "onMouseUp" | "onTouchStart" | "onTouchEnd"> & { className?: string | undefined; style?: (import("react").CSSProperties & Partial>) | undefined; tabIndex?: number | undefined; diff --git a/es/components/userRelation/list/index.js b/es/components/userRelation/list/index.js index 88292e2a6..4d0f6d17e 100644 --- a/es/components/userRelation/list/index.js +++ b/es/components/userRelation/list/index.js @@ -124,39 +124,9 @@ export default OakComponent({ }, }, }; - /* filter.relationId = { - $in: { - entity: 'relationAuth', - data: { - destRelationId: 1, - }, - filter: { - sourceRelationId: { - $in: { - entity: 'userRelation', - data: { - relationId: 1, - }, - filter: { - userId, - }, - }, - }, - }, - }, - }; */ } return { userRelation$user: filter, - /* id: { - $in: { - entity: 'userRelation', - data: { - userId: 1, - }, - filter, - }, - }, */ }; }, }, @@ -167,19 +137,15 @@ export default OakComponent({ const filter = this.getFilterByName('fulltext'); const users = props.disableDisplay ? rows?.filter((ele) => { - const userRelations = ele.userRelation$user?.filter( - (ele) => !ele.$$deleteAt$$ - ); - return !!(userRelations && userRelations.length > 0); - }) + const userRelations = ele.userRelation$user?.filter((ele) => !ele.$$deleteAt$$); + return !!(userRelations && userRelations.length > 0); + }) : rows; return { users: users?.map((ele) => { const { mobile$user, extraFile$entity } = ele; const mobile = mobile$user && mobile$user[0]?.mobile; - const avatar = features.extraFile.getUrl( - extraFile$entity && extraFile$entity[0] - ); + const avatar = features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]); const user2 = Object.assign({}, ele, { mobile, avatar, @@ -195,8 +161,8 @@ export default OakComponent({ redirectToAfterConfirm: {}, claimUrl: '', qrCodeType: '', - onUpdate: (id) => {}, - onCreate: () => {}, + onUpdate: (id) => { }, + onCreate: () => { }, disableDisplay: false, }, data: { @@ -217,10 +183,8 @@ export default OakComponent({ listeners: { 'entity,entityId'(prev, next) { if (this.state.oakFullpath) { - if ( - prev.entity !== next.entity || - prev.entityId !== next.entityId - ) { + if (prev.entity !== next.entity || + prev.entityId !== next.entityId) { this.refresh(); } } @@ -236,45 +200,33 @@ export default OakComponent({ }, methods: { goUpsert() { - const { - entity, - entityId, - redirectToAfterConfirm, - qrCodeType, - claimUrl, - onCreate, - } = this.props; + const { entity, entityId, redirectToAfterConfirm, qrCodeType, claimUrl, onCreate, } = this.props; if (onCreate) { onCreate(); - } else { + } + else { if (process.env.NODE_ENV === 'development') { - console.warn( - 'userRelation将不再作为page直接使用,请使用回调函数处理' - ); + console.warn('userRelation将不再作为page直接使用,请使用回调函数处理'); } - this.navigateTo( - { - url: '/userRelation/upsert', - entity, - entityId, - }, - { - redirectToAfterConfirm, - qrCodeType, - claimUrl, - } - ); + this.navigateTo({ + url: '/userRelation/upsert', + entity, + entityId, + }, { + redirectToAfterConfirm, + qrCodeType, + claimUrl, + }); } }, goUpdate(id) { const { entity, entityId, onUpdate } = this.props; if (onUpdate) { onUpdate(id); - } else { + } + else { if (process.env.NODE_ENV === 'development') { - console.warn( - 'userRelation将不再作为page直接使用,请使用回调函数处理' - ); + console.warn('userRelation将不再作为page直接使用,请使用回调函数处理'); } this.navigateTo({ url: '/userRelation/upsert/byUser', @@ -291,26 +243,23 @@ export default OakComponent({ const user = users.find((ele) => ele.id === idRemove); const relations = user.userRelation$user; try { - this.updateItem( - { - userRelation$user: [ - { - id: generateNewId(), - action: 'remove', - data: {}, - filter: { - id: { - $in: relations.map((ele) => ele.id), - }, + this.updateItem({ + userRelation$user: [ + { + id: generateNewId(), + action: 'remove', + data: {}, + filter: { + id: { + $in: relations.map((ele) => ele.id), }, }, - ], - }, - idRemove, - 'revoke' - ); + }, + ], + }, idRemove, 'revoke'); await this.execute(); - } catch (err) { + } + catch (err) { if (err instanceof OakUserUnpermittedException) { this.setMessage({ type: 'error', @@ -338,18 +287,16 @@ export default OakComponent({ this.refresh(); }, chooseActionMp(e) { - const { entity, entityId, redirectToAfterConfirm, qrCodeType } = - this.props; - const { - item: { mode }, - } = e.detail; + const { entity, entityId, redirectToAfterConfirm, qrCodeType } = this.props; + const { item: { mode }, } = e.detail; if (mode === 'byMobile') { this.navigateTo({ url: '/userRelation/upsert/byMobile', entity, entityId, }); - } else { + } + else { this.navigateTo({ url: '/userRelation/upsert/byUserEntityGrant', entity, @@ -394,7 +341,8 @@ export default OakComponent({ const { idRemoveMp } = this.state; try { await this.confirmDelete(idRemoveMp); - } catch (err) { + } + catch (err) { this.setState({ idRemoveMp: '', }); diff --git a/es/components/wechatLogin/qrCode/index.d.ts b/es/components/wechatLogin/qrCode/index.d.ts index 69727bd4d..8a45a21cf 100644 --- a/es/components/wechatLogin/qrCode/index.d.ts +++ b/es/components/wechatLogin/qrCode/index.d.ts @@ -1,6 +1,6 @@ import { EntityDict } from '../../../oak-app-domain'; declare const _default: (props: import("oak-frontend-base").ReactComponentProps) => import("react").ReactElement>; export default _default; diff --git a/es/components/wechatMenu/conditionalMenu/web.module.less b/es/components/wechatMenu/conditionalMenu/web.module.less index 529e4afdf..7993d63ec 100644 --- a/es/components/wechatMenu/conditionalMenu/web.module.less +++ b/es/components/wechatMenu/conditionalMenu/web.module.less @@ -399,11 +399,6 @@ } } } -:global { - .ant-popover-inner { - padding: 0 !important; - } -} .subMenuContent { display: flex; flex-direction: row; diff --git a/es/oak-app-domain/Modi/Schema.d.ts b/es/oak-app-domain/Modi/Schema.d.ts index f127f5dfb..74ccc7dcd 100644 --- a/es/oak-app-domain/Modi/Schema.d.ts +++ b/es/oak-app-domain/Modi/Schema.d.ts @@ -8,7 +8,7 @@ export type OpSchema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -19,7 +19,7 @@ export type Schema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/es/oak-app-domain/Modi/Storage.js b/es/oak-app-domain/Modi/Storage.js index 69676f67f..ecb2757a4 100644 --- a/es/oak-app-domain/Modi/Storage.js +++ b/es/oak-app-domain/Modi/Storage.js @@ -26,7 +26,7 @@ export const desc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { diff --git a/es/oak-app-domain/Oper/Schema.d.ts b/es/oak-app-domain/Oper/Schema.d.ts index 378d8141b..8d8018858 100644 --- a/es/oak-app-domain/Oper/Schema.d.ts +++ b/es/oak-app-domain/Oper/Schema.d.ts @@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType"; import * as User from "../User/Schema"; import * as OperEntity from "../OperEntity/Schema"; export type OpSchema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -17,7 +17,7 @@ export type OpSchema = EntityShape & { }; export type OpAttr = keyof OpSchema; export type Schema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/es/oak-app-domain/Oper/Storage.js b/es/oak-app-domain/Oper/Storage.js index 7290c74b1..c599dcc2a 100644 --- a/es/oak-app-domain/Oper/Storage.js +++ b/es/oak-app-domain/Oper/Storage.js @@ -5,7 +5,7 @@ export const desc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { @@ -35,5 +35,19 @@ export const desc = { } }, actionType: "appendOnly", - actions + actions, + indexes: [ + { + name: 'index_bornAt_operatorId', + attributes: [ + { + name: 'bornAt', + direction: 'DESC', + }, + { + name: "operatorId", + }, + ] + } + ] }; diff --git a/es/triggers/index.d.ts b/es/triggers/index.d.ts index 331576362..0c521e616 100644 --- a/es/triggers/index.d.ts +++ b/es/triggers/index.d.ts @@ -1,2 +1,2 @@ -declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; +declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; export default _default; diff --git a/es/types/Exception.d.ts b/es/types/Exception.d.ts index 655342c2a..97bf70d80 100644 --- a/es/types/Exception.d.ts +++ b/es/types/Exception.d.ts @@ -57,4 +57,4 @@ export declare function makeException(da message?: string; opRecords: SelectOpResult; [A: string]: any; -}): OakException | undefined; +}): OakUploadException | OakTokenExpiredException | OakUserDisabledException | OakDistinguishUserException | OakException | OakNotEnoughMoneyException | OakMobileUnsetException | OakUserInfoUncompletedException | undefined; diff --git a/lib/checkers/index.d.ts b/lib/checkers/index.d.ts index 587c253bf..e4cd6934d 100644 --- a/lib/checkers/index.d.ts +++ b/lib/checkers/index.d.ts @@ -1,2 +1,2 @@ -declare const checkers: (import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker)[]; +declare const checkers: (import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker | import("oak-domain/lib/types").Checker)[]; export default checkers; diff --git a/lib/checkers/user.d.ts b/lib/checkers/user.d.ts index 1fe61443a..54f3f3278 100644 --- a/lib/checkers/user.d.ts +++ b/lib/checkers/user.d.ts @@ -3,3 +3,4 @@ import { EntityDict } from '../oak-app-domain'; import { RuntimeCxt } from "../types/RuntimeCxt"; declare const checkers: Checker[]; export default checkers; +export declare const UserCheckers: Checker[]; diff --git a/lib/checkers/user.js b/lib/checkers/user.js index 56423618e..149436a61 100644 --- a/lib/checkers/user.js +++ b/lib/checkers/user.js @@ -1,7 +1,9 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserCheckers = void 0; const relation_1 = require("oak-domain/lib/store/relation"); const types_1 = require("oak-domain/lib/types"); +const filter_1 = require("oak-domain/lib/store/filter"); const checkers = [ { type: 'row', @@ -12,14 +14,15 @@ const checkers = [ } }, { - type: 'relation', + type: 'logical', action: ['remove', 'disable', 'enable'], entity: 'user', - relationFilter: () => { + checker: (operation, context) => { // 只有root才能进行操作 - throw new types_1.OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); - }, - errMsg: '越权操作', + if (!context.isRoot()) { + throw new types_1.OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); + } + } }, { type: 'data', @@ -40,48 +43,41 @@ const checkers = [ }, errMsg: '不能禁用root用户', }, - // { - // type: 'row', - // action: 'select', - // entity: 'user', - // filter: (operation, context) => { - // const systemId = context.getSystemId(); - // // todo 查询用户 先不加systemId - // if (systemId) { - // return { - // id: { - // $in: { - // entity: 'userSystem', - // data: { - // userId: 1, - // }, - // filter: { - // systemId, - // }, - // }, - // }, - // }; - // } - // }, - // }, +]; +exports.default = checkers; +exports.UserCheckers = [ { entity: 'user', action: 'update', - type: 'relation', - relationFilter: (operation, context) => { + type: 'logical', + checker: (operation, context) => { + // 在大部分应用中,除了root,其他人不应该有权利更新其他人信息,但是shadow用户应当除外 + // 但这些条件不一定对所有的应用都成立,应用如果有更复杂的用户相互更新策略,就不要引入这个checker + // 这也是个例子,如何对user这样的特殊对象进行权限控制 const userId = context.getCurrentUserId(); - const { data } = operation; + if (context.isRoot()) { + return; + } + const { filter, data } = operation; for (const attr in data) { const rel = (0, relation_1.judgeRelation)(context.getSchema(), 'user', attr); - if (rel === 1) { - return { - id: userId, - }; + if (rel !== 1) { + throw new types_1.OakUserUnpermittedException('user', operation, '您不能更新他人信息'); } } - return undefined; + const result = (0, filter_1.checkFilterContains)('user', context, { + id: userId, + }, filter, true); + if (result instanceof Promise) { + return result.then((r) => { + if (!r) { + throw new types_1.OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } + }); + } + if (!result) { + throw new types_1.OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } }, - errMsg: '您不能更新他人信息', } ]; -exports.default = checkers; diff --git a/lib/oak-app-domain/Modi/Schema.d.ts b/lib/oak-app-domain/Modi/Schema.d.ts index f127f5dfb..74ccc7dcd 100644 --- a/lib/oak-app-domain/Modi/Schema.d.ts +++ b/lib/oak-app-domain/Modi/Schema.d.ts @@ -8,7 +8,7 @@ export type OpSchema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -19,7 +19,7 @@ export type Schema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/lib/oak-app-domain/Modi/Storage.js b/lib/oak-app-domain/Modi/Storage.js index bc57d7f93..8e91ab081 100644 --- a/lib/oak-app-domain/Modi/Storage.js +++ b/lib/oak-app-domain/Modi/Storage.js @@ -29,7 +29,7 @@ exports.desc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { diff --git a/lib/oak-app-domain/Oper/Schema.d.ts b/lib/oak-app-domain/Oper/Schema.d.ts index 378d8141b..8d8018858 100644 --- a/lib/oak-app-domain/Oper/Schema.d.ts +++ b/lib/oak-app-domain/Oper/Schema.d.ts @@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType"; import * as User from "../User/Schema"; import * as OperEntity from "../OperEntity/Schema"; export type OpSchema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -17,7 +17,7 @@ export type OpSchema = EntityShape & { }; export type OpAttr = keyof OpSchema; export type Schema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/lib/oak-app-domain/Oper/Storage.js b/lib/oak-app-domain/Oper/Storage.js index c388b301d..1c27a485b 100644 --- a/lib/oak-app-domain/Oper/Storage.js +++ b/lib/oak-app-domain/Oper/Storage.js @@ -8,7 +8,7 @@ exports.desc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { @@ -38,5 +38,19 @@ exports.desc = { } }, actionType: "appendOnly", - actions: action_1.appendOnlyActions + actions: action_1.appendOnlyActions, + indexes: [ + { + name: 'index_bornAt_operatorId', + attributes: [ + { + name: 'bornAt', + direction: 'DESC', + }, + { + name: "operatorId", + }, + ] + } + ] }; diff --git a/lib/triggers/index.d.ts b/lib/triggers/index.d.ts index 331576362..0c521e616 100644 --- a/lib/triggers/index.d.ts +++ b/lib/triggers/index.d.ts @@ -1,2 +1,2 @@ -declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; +declare const _default: (import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger> | import("oak-domain/lib/types").Trigger>)[]; export default _default; diff --git a/lib/types/Exception.d.ts b/lib/types/Exception.d.ts index 655342c2a..97bf70d80 100644 --- a/lib/types/Exception.d.ts +++ b/lib/types/Exception.d.ts @@ -57,4 +57,4 @@ export declare function makeException(da message?: string; opRecords: SelectOpResult; [A: string]: any; -}): OakException | undefined; +}): OakUploadException | OakTokenExpiredException | OakUserDisabledException | OakDistinguishUserException | OakException | OakNotEnoughMoneyException | OakMobileUnsetException | OakUserInfoUncompletedException | undefined; diff --git a/src/checkers/user.ts b/src/checkers/user.ts index 7ceb0a68b..6125524ed 100644 --- a/src/checkers/user.ts +++ b/src/checkers/user.ts @@ -1,6 +1,6 @@ import { judgeRelation } from "oak-domain/lib/store/relation"; import { OakInputIllegalException, Checker, OakUserUnpermittedException } from "oak-domain/lib/types"; -import { ROOT_ROLE_ID } from "../constants"; +import { checkFilterContains } from 'oak-domain/lib/store/filter'; import { EntityDict } from '../oak-app-domain'; import { RuntimeCxt } from "../types/RuntimeCxt"; @@ -14,14 +14,15 @@ const checkers: Checker [] = [ } }, { - type: 'relation', + type: 'logical', action: ['remove', 'disable', 'enable'], entity: 'user', - relationFilter: () => { + checker: (operation, context) => { // 只有root才能进行操作 - throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); - }, - errMsg: '越权操作', + if (!context.isRoot()) { + throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); + } + } }, { type: 'data', @@ -42,49 +43,46 @@ const checkers: Checker [] = [ }, errMsg: '不能禁用root用户', }, - // { - // type: 'row', - // action: 'select', - // entity: 'user', - // filter: (operation, context) => { - // const systemId = context.getSystemId(); - // // todo 查询用户 先不加systemId - // if (systemId) { - // return { - // id: { - // $in: { - // entity: 'userSystem', - // data: { - // userId: 1, - // }, - // filter: { - // systemId, - // }, - // }, - // }, - // }; - // } - // }, - // }, +]; + +export default checkers; + +export const UserCheckers: Checker[] = [ { entity: 'user', action: 'update', - type: 'relation', - relationFilter: (operation, context) => { - const userId = context.getCurrentUserId(); - const { data } = operation as EntityDict['user']['Update']; + type: 'logical', + checker: (operation, context) => { + // 在大部分应用中,除了root,其他人不应该有权利更新其他人信息,但是shadow用户应当除外 + // 但这些条件不一定对所有的应用都成立,应用如果有更复杂的用户相互更新策略,就不要引入这个checker + // 这也是个例子,如何对user这样的特殊对象进行权限控制 + const userId = context.getCurrentUserId(); + if (context.isRoot()) { + return; + } + const { filter, data } = operation as EntityDict['user']['Update']; for (const attr in data) { const rel = judgeRelation(context.getSchema(), 'user', attr); - if (rel === 1) { - return { - id: userId, - }; + if (rel !== 1) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); } } - return undefined; + const result = checkFilterContains('user', context, { + id: userId, + }, filter, true); + + if (result instanceof Promise) { + return result.then( + (r) => { + if (!r) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } + } + ); + } + if (!result) { + throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息'); + } }, - errMsg: '您不能更新他人信息', } ]; - -export default checkers; \ No newline at end of file diff --git a/src/oak-app-domain/Modi/Schema.ts b/src/oak-app-domain/Modi/Schema.ts index fb2df87b5..a4dcba356 100644 --- a/src/oak-app-domain/Modi/Schema.ts +++ b/src/oak-app-domain/Modi/Schema.ts @@ -10,7 +10,7 @@ export type OpSchema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -21,7 +21,7 @@ export type Schema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/src/oak-app-domain/Modi/Storage.ts b/src/oak-app-domain/Modi/Storage.ts index 01b480475..72d64a307 100644 --- a/src/oak-app-domain/Modi/Storage.ts +++ b/src/oak-app-domain/Modi/Storage.ts @@ -28,7 +28,7 @@ export const desc: StorageDesc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { diff --git a/src/oak-app-domain/Oper/Schema.ts b/src/oak-app-domain/Oper/Schema.ts index 64ad80c33..b39f2a6f9 100644 --- a/src/oak-app-domain/Oper/Schema.ts +++ b/src/oak-app-domain/Oper/Schema.ts @@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType"; import * as User from "../User/Schema"; import * as OperEntity from "../OperEntity/Schema"; export type OpSchema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; @@ -17,7 +17,7 @@ export type OpSchema = EntityShape & { }; export type OpAttr = keyof OpSchema; export type Schema = EntityShape & { - action: String<16>; + action: String<24>; data: Object; filter?: Object | null; extra?: Object | null; diff --git a/src/oak-app-domain/Oper/Storage.ts b/src/oak-app-domain/Oper/Storage.ts index 357662ff1..2f11ee7f0 100644 --- a/src/oak-app-domain/Oper/Storage.ts +++ b/src/oak-app-domain/Oper/Storage.ts @@ -7,7 +7,7 @@ export const desc: StorageDesc = { notNull: true, type: "varchar", params: { - length: 16 + length: 24 } }, data: { @@ -37,5 +37,19 @@ export const desc: StorageDesc = { } }, actionType: "appendOnly", - actions + actions, + indexes: [ + { + name: 'index_bornAt_operatorId', + attributes: [ + { + name: 'bornAt', + direction: 'DESC', + }, + { + name: "operatorId", + }, + ] + } + ] }; \ No newline at end of file