适配了domain的修正,去掉了relation类型的checker

This commit is contained in:
Xu Chang 2024-03-17 18:24:06 +08:00
parent 2b3d4d2dcb
commit b65744dacd
30 changed files with 231 additions and 254 deletions

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ build
package-lock.json package-lock.json
scripts/local scripts/local
*tsbuildinfo *tsbuildinfo
src/oak-app-domain

View File

@ -1,2 +1,2 @@
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[]; declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[];
export default checkers; export default checkers;

View File

@ -3,3 +3,4 @@ import { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from "../types/RuntimeCxt"; import { RuntimeCxt } from "../types/RuntimeCxt";
declare const checkers: Checker<EntityDict, 'user', RuntimeCxt>[]; declare const checkers: Checker<EntityDict, 'user', RuntimeCxt>[];
export default checkers; export default checkers;
export declare const UserCheckers: Checker<EntityDict, 'user', RuntimeCxt>[];

View File

@ -1,5 +1,6 @@
import { judgeRelation } from "oak-domain/lib/store/relation"; import { judgeRelation } from "oak-domain/lib/store/relation";
import { OakInputIllegalException, OakUserUnpermittedException } from "oak-domain/lib/types"; import { OakInputIllegalException, OakUserUnpermittedException } from "oak-domain/lib/types";
import { checkFilterContains } from 'oak-domain/lib/store/filter';
const checkers = [ const checkers = [
{ {
type: 'row', type: 'row',
@ -10,14 +11,15 @@ const checkers = [
} }
}, },
{ {
type: 'relation', type: 'logical',
action: ['remove', 'disable', 'enable'], action: ['remove', 'disable', 'enable'],
entity: 'user', entity: 'user',
relationFilter: () => { checker: (operation, context) => {
// 只有root才能进行操作 // 只有root才能进行操作
throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); if (!context.isRoot()) {
}, throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} });
errMsg: '越权操作', }
}
}, },
{ {
type: 'data', type: 'data',
@ -38,48 +40,41 @@ const checkers = [
}, },
errMsg: '不能禁用root用户', errMsg: '不能禁用root用户',
}, },
// { ];
// type: 'row', export default checkers;
// action: 'select', export const UserCheckers = [
// entity: 'user',
// filter: (operation, context) => {
// const systemId = context.getSystemId();
// // todo 查询用户 先不加systemId
// if (systemId) {
// return {
// id: {
// $in: {
// entity: 'userSystem',
// data: {
// userId: 1,
// },
// filter: {
// systemId,
// },
// },
// },
// };
// }
// },
// },
{ {
entity: 'user', entity: 'user',
action: 'update', action: 'update',
type: 'relation', type: 'logical',
relationFilter: (operation, context) => { checker: (operation, context) => {
// 在大部分应用中除了root其他人不应该有权利更新其他人信息但是shadow用户应当除外
// 但这些条件不一定对所有的应用都成立应用如果有更复杂的用户相互更新策略就不要引入这个checker
// 这也是个例子如何对user这样的特殊对象进行权限控制
const userId = context.getCurrentUserId(); const userId = context.getCurrentUserId();
const { data } = operation; if (context.isRoot()) {
return;
}
const { filter, data } = operation;
for (const attr in data) { for (const attr in data) {
const rel = judgeRelation(context.getSchema(), 'user', attr); const rel = judgeRelation(context.getSchema(), 'user', attr);
if (rel === 1) { if (rel !== 1) {
return { throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息');
id: userId,
};
} }
} }
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;

View File

@ -1,7 +1,7 @@
import { Style } from '../../../../types/Style'; import { Style } from '../../../../types/Style';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../../oak-app-domain").EntityDict, keyof import("../../../../oak-app-domain").EntityDict, false, { declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../../oak-app-domain").EntityDict, keyof import("../../../../oak-app-domain").EntityDict, false, {
style: Style; style: Style;
entity: "application" | "system" | "platform"; entity: "platform" | "application" | "system";
entityId: string; entityId: string;
name: string; name: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;

View File

@ -1,7 +1,7 @@
import { Config } from '../../../types/Config'; import { Config } from '../../../types/Config';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, { declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
config: Config; config: Config;
entity: "system" | "platform"; entity: "platform" | "system";
name: string; name: string;
entityId: string; entityId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;

View File

@ -12,9 +12,9 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
type?: ButtonProps['type'] | AmButtonProps['type']; type?: ButtonProps['type'] | AmButtonProps['type'];
executeText?: string | undefined; executeText?: string | undefined;
buttonProps?: (ButtonProps & { buttonProps?: (ButtonProps & {
color?: "primary" | "success" | "warning" | "default" | "danger" | undefined; color?: "success" | "default" | "warning" | "primary" | "danger" | undefined;
fill?: "none" | "solid" | "outline" | undefined; fill?: "none" | "solid" | "outline" | undefined;
size?: "small" | "large" | "middle" | "mini" | undefined; size?: "small" | "middle" | "large" | "mini" | undefined;
block?: boolean | undefined; block?: boolean | undefined;
loading?: boolean | "auto" | undefined; loading?: boolean | "auto" | undefined;
loadingText?: string | undefined; loadingText?: string | undefined;
@ -24,7 +24,7 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
type?: "reset" | "submit" | "button" | undefined; type?: "reset" | "submit" | "button" | undefined;
shape?: "default" | "rounded" | "rectangular" | undefined; shape?: "default" | "rounded" | "rectangular" | undefined;
children?: import("react").ReactNode; children?: import("react").ReactNode;
} & Pick<import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "id" | "onMouseUp" | "onMouseDown" | "onTouchStart" | "onTouchEnd"> & { } & Pick<import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "id" | "onMouseDown" | "onMouseUp" | "onTouchStart" | "onTouchEnd"> & {
className?: string | undefined; className?: string | undefined;
style?: (import("react").CSSProperties & Partial<Record<"--text-color" | "--background-color" | "--border-radius" | "--border-width" | "--border-style" | "--border-color", string>>) | undefined; style?: (import("react").CSSProperties & Partial<Record<"--text-color" | "--background-color" | "--border-radius" | "--border-width" | "--border-style" | "--border-color", string>>) | undefined;
tabIndex?: number | undefined; tabIndex?: number | undefined;

View File

@ -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 { return {
userRelation$user: filter, userRelation$user: filter,
/* id: {
$in: {
entity: 'userRelation',
data: {
userId: 1,
},
filter,
},
}, */
}; };
}, },
}, },
@ -167,19 +137,15 @@ export default OakComponent({
const filter = this.getFilterByName('fulltext'); const filter = this.getFilterByName('fulltext');
const users = props.disableDisplay const users = props.disableDisplay
? rows?.filter((ele) => { ? rows?.filter((ele) => {
const userRelations = ele.userRelation$user?.filter( const userRelations = ele.userRelation$user?.filter((ele) => !ele.$$deleteAt$$);
(ele) => !ele.$$deleteAt$$ return !!(userRelations && userRelations.length > 0);
); })
return !!(userRelations && userRelations.length > 0);
})
: rows; : rows;
return { return {
users: users?.map((ele) => { users: users?.map((ele) => {
const { mobile$user, extraFile$entity } = ele; const { mobile$user, extraFile$entity } = ele;
const mobile = mobile$user && mobile$user[0]?.mobile; const mobile = mobile$user && mobile$user[0]?.mobile;
const avatar = features.extraFile.getUrl( const avatar = features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]);
extraFile$entity && extraFile$entity[0]
);
const user2 = Object.assign({}, ele, { const user2 = Object.assign({}, ele, {
mobile, mobile,
avatar, avatar,
@ -195,8 +161,8 @@ export default OakComponent({
redirectToAfterConfirm: {}, redirectToAfterConfirm: {},
claimUrl: '', claimUrl: '',
qrCodeType: '', qrCodeType: '',
onUpdate: (id) => {}, onUpdate: (id) => { },
onCreate: () => {}, onCreate: () => { },
disableDisplay: false, disableDisplay: false,
}, },
data: { data: {
@ -217,10 +183,8 @@ export default OakComponent({
listeners: { listeners: {
'entity,entityId'(prev, next) { 'entity,entityId'(prev, next) {
if (this.state.oakFullpath) { if (this.state.oakFullpath) {
if ( if (prev.entity !== next.entity ||
prev.entity !== next.entity || prev.entityId !== next.entityId) {
prev.entityId !== next.entityId
) {
this.refresh(); this.refresh();
} }
} }
@ -236,45 +200,33 @@ export default OakComponent({
}, },
methods: { methods: {
goUpsert() { goUpsert() {
const { const { entity, entityId, redirectToAfterConfirm, qrCodeType, claimUrl, onCreate, } = this.props;
entity,
entityId,
redirectToAfterConfirm,
qrCodeType,
claimUrl,
onCreate,
} = this.props;
if (onCreate) { if (onCreate) {
onCreate(); onCreate();
} else { }
else {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
console.warn( console.warn('userRelation将不再作为page直接使用请使用回调函数处理');
'userRelation将不再作为page直接使用请使用回调函数处理'
);
} }
this.navigateTo( this.navigateTo({
{ url: '/userRelation/upsert',
url: '/userRelation/upsert', entity,
entity, entityId,
entityId, }, {
}, redirectToAfterConfirm,
{ qrCodeType,
redirectToAfterConfirm, claimUrl,
qrCodeType, });
claimUrl,
}
);
} }
}, },
goUpdate(id) { goUpdate(id) {
const { entity, entityId, onUpdate } = this.props; const { entity, entityId, onUpdate } = this.props;
if (onUpdate) { if (onUpdate) {
onUpdate(id); onUpdate(id);
} else { }
else {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
console.warn( console.warn('userRelation将不再作为page直接使用请使用回调函数处理');
'userRelation将不再作为page直接使用请使用回调函数处理'
);
} }
this.navigateTo({ this.navigateTo({
url: '/userRelation/upsert/byUser', url: '/userRelation/upsert/byUser',
@ -291,26 +243,23 @@ export default OakComponent({
const user = users.find((ele) => ele.id === idRemove); const user = users.find((ele) => ele.id === idRemove);
const relations = user.userRelation$user; const relations = user.userRelation$user;
try { try {
this.updateItem( this.updateItem({
{ userRelation$user: [
userRelation$user: [ {
{ id: generateNewId(),
id: generateNewId(), action: 'remove',
action: 'remove', data: {},
data: {}, filter: {
filter: { id: {
id: { $in: relations.map((ele) => ele.id),
$in: relations.map((ele) => ele.id),
},
}, },
}, },
], },
}, ],
idRemove, }, idRemove, 'revoke');
'revoke'
);
await this.execute(); await this.execute();
} catch (err) { }
catch (err) {
if (err instanceof OakUserUnpermittedException) { if (err instanceof OakUserUnpermittedException) {
this.setMessage({ this.setMessage({
type: 'error', type: 'error',
@ -338,18 +287,16 @@ export default OakComponent({
this.refresh(); this.refresh();
}, },
chooseActionMp(e) { chooseActionMp(e) {
const { entity, entityId, redirectToAfterConfirm, qrCodeType } = const { entity, entityId, redirectToAfterConfirm, qrCodeType } = this.props;
this.props; const { item: { mode }, } = e.detail;
const {
item: { mode },
} = e.detail;
if (mode === 'byMobile') { if (mode === 'byMobile') {
this.navigateTo({ this.navigateTo({
url: '/userRelation/upsert/byMobile', url: '/userRelation/upsert/byMobile',
entity, entity,
entityId, entityId,
}); });
} else { }
else {
this.navigateTo({ this.navigateTo({
url: '/userRelation/upsert/byUserEntityGrant', url: '/userRelation/upsert/byUserEntityGrant',
entity, entity,
@ -394,7 +341,8 @@ export default OakComponent({
const { idRemoveMp } = this.state; const { idRemoveMp } = this.state;
try { try {
await this.confirmDelete(idRemoveMp); await this.confirmDelete(idRemoveMp);
} catch (err) { }
catch (err) {
this.setState({ this.setState({
idRemoveMp: '', idRemoveMp: '',
}); });

View File

@ -1,6 +1,6 @@
import { EntityDict } from '../../../oak-app-domain'; import { EntityDict } from '../../../oak-app-domain';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, { declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, {
type: "bind" | "login"; type: "login" | "bind";
url: string; url: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default; export default _default;

View File

@ -399,11 +399,6 @@
} }
} }
} }
:global {
.ant-popover-inner {
padding: 0 !important;
}
}
.subMenuContent { .subMenuContent {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -8,7 +8,7 @@ export type OpSchema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -19,7 +19,7 @@ export type Schema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -26,7 +26,7 @@ export const desc = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {

View File

@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType";
import * as User from "../User/Schema"; import * as User from "../User/Schema";
import * as OperEntity from "../OperEntity/Schema"; import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & { export type OpSchema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -17,7 +17,7 @@ export type OpSchema = EntityShape & {
}; };
export type OpAttr = keyof OpSchema; export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & { export type Schema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -5,7 +5,7 @@ export const desc = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {
@ -35,5 +35,19 @@ export const desc = {
} }
}, },
actionType: "appendOnly", actionType: "appendOnly",
actions actions,
indexes: [
{
name: 'index_bornAt_operatorId',
attributes: [
{
name: 'bornAt',
direction: 'DESC',
},
{
name: "operatorId",
},
]
}
]
}; };

View File

@ -1,2 +1,2 @@
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[]; declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[];
export default _default; export default _default;

View File

@ -57,4 +57,4 @@ export declare function makeException<ED extends EntityDict & BaseEntityDict>(da
message?: string; message?: string;
opRecords: SelectOpResult<ED>; opRecords: SelectOpResult<ED>;
[A: string]: any; [A: string]: any;
}): OakException<BaseEntityDict> | undefined; }): OakUploadException<EntityDict & BaseEntityDict> | OakTokenExpiredException<EntityDict & BaseEntityDict> | OakUserDisabledException<EntityDict & BaseEntityDict> | OakDistinguishUserException<EntityDict & BaseEntityDict> | OakException<ED> | OakNotEnoughMoneyException<EntityDict & BaseEntityDict> | OakMobileUnsetException<EntityDict & BaseEntityDict> | OakUserInfoUncompletedException<EntityDict & BaseEntityDict> | undefined;

View File

@ -1,2 +1,2 @@
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[]; declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[];
export default checkers; export default checkers;

View File

@ -3,3 +3,4 @@ import { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from "../types/RuntimeCxt"; import { RuntimeCxt } from "../types/RuntimeCxt";
declare const checkers: Checker<EntityDict, 'user', RuntimeCxt>[]; declare const checkers: Checker<EntityDict, 'user', RuntimeCxt>[];
export default checkers; export default checkers;
export declare const UserCheckers: Checker<EntityDict, 'user', RuntimeCxt>[];

View File

@ -1,7 +1,9 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.UserCheckers = void 0;
const relation_1 = require("oak-domain/lib/store/relation"); const relation_1 = require("oak-domain/lib/store/relation");
const types_1 = require("oak-domain/lib/types"); const types_1 = require("oak-domain/lib/types");
const filter_1 = require("oak-domain/lib/store/filter");
const checkers = [ const checkers = [
{ {
type: 'row', type: 'row',
@ -12,14 +14,15 @@ const checkers = [
} }
}, },
{ {
type: 'relation', type: 'logical',
action: ['remove', 'disable', 'enable'], action: ['remove', 'disable', 'enable'],
entity: 'user', entity: 'user',
relationFilter: () => { checker: (operation, context) => {
// 只有root才能进行操作 // 只有root才能进行操作
throw new types_1.OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); if (!context.isRoot()) {
}, throw new types_1.OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} });
errMsg: '越权操作', }
}
}, },
{ {
type: 'data', type: 'data',
@ -40,48 +43,41 @@ const checkers = [
}, },
errMsg: '不能禁用root用户', errMsg: '不能禁用root用户',
}, },
// { ];
// type: 'row', exports.default = checkers;
// action: 'select', exports.UserCheckers = [
// entity: 'user',
// filter: (operation, context) => {
// const systemId = context.getSystemId();
// // todo 查询用户 先不加systemId
// if (systemId) {
// return {
// id: {
// $in: {
// entity: 'userSystem',
// data: {
// userId: 1,
// },
// filter: {
// systemId,
// },
// },
// },
// };
// }
// },
// },
{ {
entity: 'user', entity: 'user',
action: 'update', action: 'update',
type: 'relation', type: 'logical',
relationFilter: (operation, context) => { checker: (operation, context) => {
// 在大部分应用中除了root其他人不应该有权利更新其他人信息但是shadow用户应当除外
// 但这些条件不一定对所有的应用都成立应用如果有更复杂的用户相互更新策略就不要引入这个checker
// 这也是个例子如何对user这样的特殊对象进行权限控制
const userId = context.getCurrentUserId(); const userId = context.getCurrentUserId();
const { data } = operation; if (context.isRoot()) {
return;
}
const { filter, data } = operation;
for (const attr in data) { for (const attr in data) {
const rel = (0, relation_1.judgeRelation)(context.getSchema(), 'user', attr); const rel = (0, relation_1.judgeRelation)(context.getSchema(), 'user', attr);
if (rel === 1) { if (rel !== 1) {
return { throw new types_1.OakUserUnpermittedException('user', operation, '您不能更新他人信息');
id: userId,
};
} }
} }
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;

View File

@ -8,7 +8,7 @@ export type OpSchema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -19,7 +19,7 @@ export type Schema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -29,7 +29,7 @@ exports.desc = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {

View File

@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType";
import * as User from "../User/Schema"; import * as User from "../User/Schema";
import * as OperEntity from "../OperEntity/Schema"; import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & { export type OpSchema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -17,7 +17,7 @@ export type OpSchema = EntityShape & {
}; };
export type OpAttr = keyof OpSchema; export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & { export type Schema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -8,7 +8,7 @@ exports.desc = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {
@ -38,5 +38,19 @@ exports.desc = {
} }
}, },
actionType: "appendOnly", actionType: "appendOnly",
actions: action_1.appendOnlyActions actions: action_1.appendOnlyActions,
indexes: [
{
name: 'index_bornAt_operatorId',
attributes: [
{
name: 'bornAt',
direction: 'DESC',
},
{
name: "operatorId",
},
]
}
]
}; };

View File

@ -1,2 +1,2 @@
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[]; declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[];
export default _default; export default _default;

View File

@ -57,4 +57,4 @@ export declare function makeException<ED extends EntityDict & BaseEntityDict>(da
message?: string; message?: string;
opRecords: SelectOpResult<ED>; opRecords: SelectOpResult<ED>;
[A: string]: any; [A: string]: any;
}): OakException<BaseEntityDict> | undefined; }): OakUploadException<EntityDict & BaseEntityDict> | OakTokenExpiredException<EntityDict & BaseEntityDict> | OakUserDisabledException<EntityDict & BaseEntityDict> | OakDistinguishUserException<EntityDict & BaseEntityDict> | OakException<ED> | OakNotEnoughMoneyException<EntityDict & BaseEntityDict> | OakMobileUnsetException<EntityDict & BaseEntityDict> | OakUserInfoUncompletedException<EntityDict & BaseEntityDict> | undefined;

View File

@ -1,6 +1,6 @@
import { judgeRelation } from "oak-domain/lib/store/relation"; import { judgeRelation } from "oak-domain/lib/store/relation";
import { OakInputIllegalException, Checker, OakUserUnpermittedException } from "oak-domain/lib/types"; 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 { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from "../types/RuntimeCxt"; import { RuntimeCxt } from "../types/RuntimeCxt";
@ -14,14 +14,15 @@ const checkers: Checker<EntityDict, 'user', RuntimeCxt> [] = [
} }
}, },
{ {
type: 'relation', type: 'logical',
action: ['remove', 'disable', 'enable'], action: ['remove', 'disable', 'enable'],
entity: 'user', entity: 'user',
relationFilter: () => { checker: (operation, context) => {
// 只有root才能进行操作 // 只有root才能进行操作
throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }); if (!context.isRoot()) {
}, throw new OakUserUnpermittedException('user', { id: 'disable', action: 'disable', data: {} });
errMsg: '越权操作', }
}
}, },
{ {
type: 'data', type: 'data',
@ -42,49 +43,46 @@ const checkers: Checker<EntityDict, 'user', RuntimeCxt> [] = [
}, },
errMsg: '不能禁用root用户', errMsg: '不能禁用root用户',
}, },
// { ];
// type: 'row',
// action: 'select', export default checkers;
// entity: 'user',
// filter: (operation, context) => { export const UserCheckers: Checker<EntityDict, 'user', RuntimeCxt>[] = [
// const systemId = context.getSystemId();
// // todo 查询用户 先不加systemId
// if (systemId) {
// return {
// id: {
// $in: {
// entity: 'userSystem',
// data: {
// userId: 1,
// },
// filter: {
// systemId,
// },
// },
// },
// };
// }
// },
// },
{ {
entity: 'user', entity: 'user',
action: 'update', action: 'update',
type: 'relation', type: 'logical',
relationFilter: (operation, context) => { checker: (operation, context) => {
const userId = context.getCurrentUserId(); // 在大部分应用中除了root其他人不应该有权利更新其他人信息但是shadow用户应当除外
const { data } = operation as EntityDict['user']['Update']; // 但这些条件不一定对所有的应用都成立应用如果有更复杂的用户相互更新策略就不要引入这个checker
// 这也是个例子如何对user这样的特殊对象进行权限控制
const userId = context.getCurrentUserId();
if (context.isRoot()) {
return;
}
const { filter, data } = operation as EntityDict['user']['Update'];
for (const attr in data) { for (const attr in data) {
const rel = judgeRelation(context.getSchema(), 'user', attr); const rel = judgeRelation(context.getSchema(), 'user', attr);
if (rel === 1) { if (rel !== 1) {
return { throw new OakUserUnpermittedException('user', operation, '您不能更新他人信息');
id: userId,
};
} }
} }
return undefined; const result = checkFilterContains<EntityDict, 'user', RuntimeCxt>('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;

View File

@ -10,7 +10,7 @@ export type OpSchema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -21,7 +21,7 @@ export type Schema = EntityShape & {
targetEntity: String<32>; targetEntity: String<32>;
entity: String<32>; entity: String<32>;
entityId: String<64>; entityId: String<64>;
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -28,7 +28,7 @@ export const desc: StorageDesc<OpSchema> = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {

View File

@ -7,7 +7,7 @@ import { String, Datetime } from "oak-domain/lib/types/DataType";
import * as User from "../User/Schema"; import * as User from "../User/Schema";
import * as OperEntity from "../OperEntity/Schema"; import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & { export type OpSchema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;
@ -17,7 +17,7 @@ export type OpSchema = EntityShape & {
}; };
export type OpAttr = keyof OpSchema; export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & { export type Schema = EntityShape & {
action: String<16>; action: String<24>;
data: Object; data: Object;
filter?: Object | null; filter?: Object | null;
extra?: Object | null; extra?: Object | null;

View File

@ -7,7 +7,7 @@ export const desc: StorageDesc<OpSchema> = {
notNull: true, notNull: true,
type: "varchar", type: "varchar",
params: { params: {
length: 16 length: 24
} }
}, },
data: { data: {
@ -37,5 +37,19 @@ export const desc: StorageDesc<OpSchema> = {
} }
}, },
actionType: "appendOnly", actionType: "appendOnly",
actions actions,
indexes: [
{
name: 'index_bornAt_operatorId',
attributes: [
{
name: 'bornAt',
direction: 'DESC',
},
{
name: "operatorId",
},
]
}
]
}; };