@steedos/objectql 2.1.56 → 2.1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dynamic-load/preload_data.d.ts +3 -0
- package/lib/dynamic-load/preload_data.js +158 -1
- package/lib/dynamic-load/preload_data.js.map +1 -1
- package/lib/dynamic-load/restrictionRules.d.ts +1 -0
- package/lib/dynamic-load/restrictionRules.js +42 -0
- package/lib/dynamic-load/restrictionRules.js.map +1 -0
- package/lib/dynamic-load/shareRules.d.ts +1 -0
- package/lib/dynamic-load/shareRules.js +42 -0
- package/lib/dynamic-load/shareRules.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/metadata-register/_base.d.ts +3 -1
- package/lib/metadata-register/_base.js +16 -5
- package/lib/metadata-register/_base.js.map +1 -1
- package/lib/metadata-register/permissionFields.d.ts +7 -0
- package/lib/metadata-register/permissionFields.js +18 -0
- package/lib/metadata-register/permissionFields.js.map +1 -0
- package/lib/metadata-register/restrictionRules.d.ts +7 -0
- package/lib/metadata-register/restrictionRules.js +18 -0
- package/lib/metadata-register/restrictionRules.js.map +1 -0
- package/lib/metadata-register/shareRules.d.ts +7 -0
- package/lib/metadata-register/shareRules.js +18 -0
- package/lib/metadata-register/shareRules.js.map +1 -0
- package/lib/types/field_permission.d.ts +4 -0
- package/lib/types/field_permission.js +50 -0
- package/lib/types/field_permission.js.map +1 -0
- package/lib/types/object.d.ts +1 -0
- package/lib/types/object.js +302 -133
- package/lib/types/object.js.map +1 -1
- package/lib/types/object_dynamic_load.js +13 -4
- package/lib/types/object_dynamic_load.js.map +1 -1
- package/lib/types/object_permission.d.ts +1 -0
- package/lib/types/object_permission.js +31 -0
- package/lib/types/object_permission.js.map +1 -1
- package/lib/types/restrictionRule.d.ts +13 -0
- package/lib/types/restrictionRule.js +75 -0
- package/lib/types/restrictionRule.js.map +1 -0
- package/lib/types/shareRule.d.ts +13 -0
- package/lib/types/shareRule.js +75 -0
- package/lib/types/shareRule.js.map +1 -0
- package/lib/util/field.js +4 -4
- package/lib/util/field.js.map +1 -1
- package/lib/util/function_expression.d.ts +2 -0
- package/lib/util/function_expression.js +66 -0
- package/lib/util/function_expression.js.map +1 -0
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.js +1 -0
- package/lib/util/index.js.map +1 -1
- package/package.json +8 -8
- package/src/dynamic-load/preload_data.ts +44 -0
- package/src/dynamic-load/restrictionRules.ts +19 -0
- package/src/dynamic-load/shareRules.ts +19 -0
- package/src/index.ts +4 -1
- package/src/metadata-register/_base.ts +14 -3
- package/src/metadata-register/permissionFields.ts +13 -0
- package/src/metadata-register/restrictionRules.ts +12 -0
- package/src/metadata-register/shareRules.ts +13 -0
- package/src/types/field_permission.ts +26 -0
- package/src/types/object.ts +198 -22
- package/src/types/object_dynamic_load.ts +4 -1
- package/src/types/object_permission.ts +32 -0
- package/src/types/restrictionRule.ts +57 -0
- package/src/types/shareRule.ts +57 -0
- package/src/util/field.ts +4 -4
- package/src/util/function_expression.ts +63 -0
- package/src/util/index.ts +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { registerPermissionFields } from '../metadata-register/permissionFields';
|
|
2
|
+
import { getSteedosSchema } from '../types'
|
|
3
|
+
import * as _ from 'lodash'
|
|
4
|
+
|
|
5
|
+
export class FieldPermission {
|
|
6
|
+
|
|
7
|
+
static async getObjectFieldsPermission(objectApiName, permissionSetApiName) {
|
|
8
|
+
const schema = getSteedosSchema();
|
|
9
|
+
return await registerPermissionFields.find(schema.broker, {
|
|
10
|
+
pattern: `${permissionSetApiName}.${objectApiName}.*`
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static async getObjectFieldsPermissionGroupRole(objectApiName) {
|
|
15
|
+
const permissions = await this.getObjectFieldsPermission(objectApiName, '*');
|
|
16
|
+
const result = {};
|
|
17
|
+
_.each(permissions, (permission) => {
|
|
18
|
+
const { permission_set_id, field, editable, readable } = permission.metadata;
|
|
19
|
+
if (!result[permission_set_id]) {
|
|
20
|
+
result[permission_set_id] = [];
|
|
21
|
+
}
|
|
22
|
+
result[permission_set_id].push({ field: field, read: readable, edit: editable })
|
|
23
|
+
})
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/types/object.ts
CHANGED
|
@@ -15,7 +15,10 @@ import { brokeEmitEvents } from "./object_events";
|
|
|
15
15
|
import { translationObject } from "@steedos/i18n";
|
|
16
16
|
import { getObjectLayouts } from "./object_layouts";
|
|
17
17
|
import { sortBy, forEach } from 'lodash';
|
|
18
|
-
|
|
18
|
+
import { ShareRules } from './shareRule';
|
|
19
|
+
import { RestrictionRule } from './restrictionRule';
|
|
20
|
+
import { FieldPermission } from './field_permission';
|
|
21
|
+
|
|
19
22
|
const clone = require('clone')
|
|
20
23
|
|
|
21
24
|
// 主子表有层级限制,超过3层就报错,该函数判断当前对象作为主表对象往下的层级最多不越过3层,
|
|
@@ -634,18 +637,27 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
634
637
|
disabled_actions: null,
|
|
635
638
|
unreadable_fields: null,
|
|
636
639
|
uneditable_fields: null,
|
|
637
|
-
unrelated_objects: null
|
|
640
|
+
unrelated_objects: null,
|
|
641
|
+
field_permissions: null,
|
|
642
|
+
// read_filters: [],
|
|
643
|
+
// edit_filters: []
|
|
638
644
|
}
|
|
639
645
|
|
|
640
646
|
if (_.isEmpty(roles)) {
|
|
641
647
|
throw new Error('not find user permission');
|
|
642
648
|
}
|
|
643
649
|
|
|
650
|
+
const rolesFieldsPermission = await FieldPermission.getObjectFieldsPermissionGroupRole(this.name);
|
|
651
|
+
|
|
644
652
|
roles.forEach((role) => {
|
|
645
|
-
let rolePermission = objectRolesPermission[role]
|
|
653
|
+
let rolePermission = objectRolesPermission[role];
|
|
646
654
|
if (rolePermission) {
|
|
655
|
+
let roleFieldsPermission = rolesFieldsPermission[role];
|
|
647
656
|
_.each(userObjectPermission, (v, k) => {
|
|
648
|
-
let _v = rolePermission[k]
|
|
657
|
+
let _v = rolePermission[k];
|
|
658
|
+
if (k === 'field_permissions') {
|
|
659
|
+
_v = roleFieldsPermission
|
|
660
|
+
}
|
|
649
661
|
if (_.isBoolean(v)) {
|
|
650
662
|
if (v === false && _v === true) {
|
|
651
663
|
userObjectPermission[k] = _v
|
|
@@ -654,20 +666,56 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
654
666
|
if(_.isBoolean(_v)){
|
|
655
667
|
userObjectPermission[k] = _v
|
|
656
668
|
}
|
|
657
|
-
} else if (
|
|
669
|
+
} else if (['read_filters', 'edit_filters'].indexOf(k) > -1) {
|
|
670
|
+
if ('edit_filters' === k) {
|
|
671
|
+
if (!_.isEmpty(_v)) {
|
|
672
|
+
userObjectPermission['read_filters'].push(_v);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (!_.isEmpty(_v)) {
|
|
676
|
+
userObjectPermission[k].push(_v);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
else if ((_.isArray(v) || _.isNull(v))) {
|
|
658
680
|
if (!_.isArray(_v)) {
|
|
659
681
|
_v = []
|
|
660
682
|
}
|
|
661
683
|
if (_.isNull(v)) {
|
|
662
684
|
userObjectPermission[k] = _v
|
|
663
685
|
} else {
|
|
664
|
-
|
|
686
|
+
if (k === 'field_permissions') {
|
|
687
|
+
userObjectPermission[k] = _.union(v, _v)
|
|
688
|
+
} else {
|
|
689
|
+
userObjectPermission[k] = _.intersection(v, _v)
|
|
690
|
+
}
|
|
665
691
|
}
|
|
666
692
|
}
|
|
667
693
|
})
|
|
668
694
|
}
|
|
669
|
-
})
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
const field_permissions = {};
|
|
698
|
+
if (userObjectPermission.field_permissions) {
|
|
699
|
+
_.each(userObjectPermission.field_permissions, (field_permission) => {
|
|
700
|
+
const { field, read, edit } = field_permission;
|
|
701
|
+
if (field_permissions[field]) {
|
|
702
|
+
field_permissions[field].edit = field_permissions[field].edit || edit;
|
|
703
|
+
if (field_permissions[field].edit) {
|
|
704
|
+
field_permissions[field].read = true
|
|
705
|
+
} else {
|
|
706
|
+
field_permissions[field].read = field_permissions[field].read || read;
|
|
707
|
+
}
|
|
708
|
+
} else {
|
|
709
|
+
field_permissions[field] = {
|
|
710
|
+
field: field,
|
|
711
|
+
read: edit || read,
|
|
712
|
+
edit: edit
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
})
|
|
716
|
+
}
|
|
670
717
|
|
|
718
|
+
userObjectPermission.field_permissions = field_permissions;
|
|
671
719
|
|
|
672
720
|
userObjectPermission.disabled_list_views = userObjectPermission.disabled_list_views || []
|
|
673
721
|
userObjectPermission.disabled_actions = userObjectPermission.disabled_actions || []
|
|
@@ -680,7 +728,6 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
680
728
|
return Object.assign({}, userObjectPermission, { allowRead: true, viewAllRecords: true, viewCompanyRecords: true })
|
|
681
729
|
}
|
|
682
730
|
|
|
683
|
-
Creator.processPermissions(userObjectPermission)
|
|
684
731
|
return userObjectPermission;
|
|
685
732
|
}
|
|
686
733
|
|
|
@@ -1021,6 +1068,27 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1021
1068
|
})
|
|
1022
1069
|
}
|
|
1023
1070
|
|
|
1071
|
+
// 使用字段级安全性作为限制用户对字段的访问权限的手段;然后使用页面布局主要在选项卡中组织详细信息和编辑页面。这可以减少需要维护的页面布局数量。
|
|
1072
|
+
// 例如,如果字段在页面布局中是必需的,并且在字段级安全性设置中是只读的,则字段级安全性将覆盖页面布局,并且该字段将对用户是只读的。
|
|
1073
|
+
const userObjectFields = objectConfig.fields;
|
|
1074
|
+
_.each(objectConfig.permissions.field_permissions, (field_permission, field) => {
|
|
1075
|
+
const { read, edit } = field_permission;
|
|
1076
|
+
if (read) {
|
|
1077
|
+
userObjectFields[field].omit = true;
|
|
1078
|
+
}
|
|
1079
|
+
if (edit) {
|
|
1080
|
+
userObjectFields[field].omit = false;
|
|
1081
|
+
userObjectFields[field].hidden = false;
|
|
1082
|
+
userObjectFields[field].readonly = false;
|
|
1083
|
+
userObjectFields[field].disabled = false;
|
|
1084
|
+
}
|
|
1085
|
+
if (!read && !edit) {
|
|
1086
|
+
delete userObjectFields[field]
|
|
1087
|
+
}
|
|
1088
|
+
})
|
|
1089
|
+
|
|
1090
|
+
objectConfig.fields = userObjectFields
|
|
1091
|
+
|
|
1024
1092
|
// TODO object layout 是否需要控制审批记录显示?
|
|
1025
1093
|
let spaceProcessDefinition = await getObject("process_definition").directFind({ filters: [['space', '=', userSession.spaceId], ['object_name', '=', this.name], ['active', '=', true]] })
|
|
1026
1094
|
if (spaceProcessDefinition.length > 0) {
|
|
@@ -1256,6 +1324,32 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1256
1324
|
return await this.runTriggerActions(when, context)
|
|
1257
1325
|
}
|
|
1258
1326
|
|
|
1327
|
+
// private async appendRecordPermission(records, userSession) {
|
|
1328
|
+
// const _ids = _.pluck(records, '_id');
|
|
1329
|
+
// const objPm = await this.getUserObjectPermission(userSession);
|
|
1330
|
+
// const permissionFilters = this.getObjectPermissionFilters(objPm, userSession, true);
|
|
1331
|
+
// if (_.isEmpty(permissionFilters)) {
|
|
1332
|
+
// return;
|
|
1333
|
+
// }
|
|
1334
|
+
// const filters = formatFiltersToODataQuery(['_id', 'in', _ids])
|
|
1335
|
+
|
|
1336
|
+
// const results = await this.directFind({
|
|
1337
|
+
// fields: ['_id'],
|
|
1338
|
+
// filters: `(${filters}) and (${permissionFilters.join(' or ')})`
|
|
1339
|
+
// });
|
|
1340
|
+
// const allowEditIds = _.pluck(results, '_id');
|
|
1341
|
+
// _.each(records, (record) => {
|
|
1342
|
+
// if (_.include(allowEditIds, record._id)) {
|
|
1343
|
+
// record.record_permissions = {
|
|
1344
|
+
// allowRead: true,
|
|
1345
|
+
// allowEdit: true,
|
|
1346
|
+
// allowDelete: true,
|
|
1347
|
+
// }
|
|
1348
|
+
// }
|
|
1349
|
+
// })
|
|
1350
|
+
|
|
1351
|
+
// }
|
|
1352
|
+
|
|
1259
1353
|
private async getTriggerContext(when: string, method: string, args: any[], recordId?: string) {
|
|
1260
1354
|
|
|
1261
1355
|
let userSession = args[args.length - 1]
|
|
@@ -1406,7 +1500,16 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1406
1500
|
let values = returnValue || {}
|
|
1407
1501
|
if (method === 'count') {
|
|
1408
1502
|
values = returnValue || 0
|
|
1409
|
-
}
|
|
1503
|
+
}
|
|
1504
|
+
// else{
|
|
1505
|
+
// if (userSession) {
|
|
1506
|
+
// let _records = returnValue
|
|
1507
|
+
// if (method == 'findOne' && returnValue) {
|
|
1508
|
+
// _records = [_records]
|
|
1509
|
+
// }
|
|
1510
|
+
// await this.appendRecordPermission(_records, userSession);
|
|
1511
|
+
// }
|
|
1512
|
+
// }
|
|
1410
1513
|
Object.assign(afterTriggerContext, { data: { values: values } })
|
|
1411
1514
|
}
|
|
1412
1515
|
// console.log("==returnValue==", returnValue);
|
|
@@ -1484,6 +1587,33 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1484
1587
|
}
|
|
1485
1588
|
}
|
|
1486
1589
|
|
|
1590
|
+
// private getObjectPermissionFilters(objectPermission, userSession, isEdit) {
|
|
1591
|
+
// const objectPermissionFilters = [];
|
|
1592
|
+
|
|
1593
|
+
// let permissionFiltersKey = 'read_filters';
|
|
1594
|
+
// if (isEdit) {
|
|
1595
|
+
// permissionFiltersKey = 'edit_filters';
|
|
1596
|
+
// }
|
|
1597
|
+
|
|
1598
|
+
// const globalData = Object.assign({}, userSession, { now: new Date() });
|
|
1599
|
+
|
|
1600
|
+
// let permissionFilters = objectPermission[permissionFiltersKey];
|
|
1601
|
+
|
|
1602
|
+
// _.each(permissionFilters, (permissionFilter) => {
|
|
1603
|
+
// if (_.isString(permissionFilter) && isExpression(permissionFilter.trim())) {
|
|
1604
|
+
// try {
|
|
1605
|
+
// const filters = parseSingleExpression(permissionFilter, {}, "#", globalData);
|
|
1606
|
+
// if (filters && !_.isString(filters)) {
|
|
1607
|
+
// objectPermissionFilters.push(`(${formatFiltersToODataQuery(filters, userSession)})`)
|
|
1608
|
+
// }
|
|
1609
|
+
// } catch (error) {
|
|
1610
|
+
// console.error(`getObjectPermissionFilters error`, permissionFilter, error.message);
|
|
1611
|
+
// }
|
|
1612
|
+
// }
|
|
1613
|
+
// })
|
|
1614
|
+
// return objectPermissionFilters;
|
|
1615
|
+
// }
|
|
1616
|
+
|
|
1487
1617
|
/**
|
|
1488
1618
|
* 把query.filters用formatFiltersToODataQuery转为odata query
|
|
1489
1619
|
* 主要是为了把userSession中的utcOffset逻辑传入formatFiltersToODataQuery函数处理
|
|
@@ -1514,7 +1644,6 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1514
1644
|
if (method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
|
|
1515
1645
|
query = args[args.length - 3];
|
|
1516
1646
|
}
|
|
1517
|
-
|
|
1518
1647
|
if (query.filters && !_.isString(query.filters)) {
|
|
1519
1648
|
query.filters = formatFiltersToODataQuery(query.filters);
|
|
1520
1649
|
}
|
|
@@ -1527,7 +1656,7 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1527
1656
|
return
|
|
1528
1657
|
}
|
|
1529
1658
|
|
|
1530
|
-
let spaceFilter, companyFilter, ownerFilter, sharesFilter, clientFilter = query.filters, filters, permissionFilters = [], userFilters = [];
|
|
1659
|
+
let spaceFilter, companyFilter, ownerFilter, sharesFilter, shareRuleFilters, restrictionRuleFilters, clientFilter = query.filters, filters, permissionFilters = [], userFilters = [];
|
|
1531
1660
|
|
|
1532
1661
|
if (spaceId) {
|
|
1533
1662
|
spaceFilter = `(space eq '${spaceId}')`;
|
|
@@ -1547,12 +1676,27 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1547
1676
|
ownerFilter = `(owner eq '${userId}')`;
|
|
1548
1677
|
}
|
|
1549
1678
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1679
|
+
shareRuleFilters = await ShareRules.getUserObjectFilters(this.name, userSession);
|
|
1680
|
+
|
|
1681
|
+
if (!_.isEmpty(shareRuleFilters)) {
|
|
1682
|
+
permissionFilters.push(`(${shareRuleFilters.join(' or ')})`);
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
restrictionRuleFilters = await RestrictionRule.getUserObjectFilters(this.name, userSession);
|
|
1686
|
+
|
|
1687
|
+
if (!_.isEmpty(restrictionRuleFilters)) {
|
|
1688
|
+
userFilters.push(`(${restrictionRuleFilters.join(' or ')})`);
|
|
1552
1689
|
}
|
|
1690
|
+
// objectPermissionFilters = this.getObjectPermissionFilters(objPm, userSession, false);
|
|
1691
|
+
|
|
1692
|
+
// if (!_.isEmpty(objectPermissionFilters)) {
|
|
1693
|
+
// permissionFilters.push(`(${objectPermissionFilters.join(' or ')})`);
|
|
1694
|
+
// }
|
|
1695
|
+
|
|
1696
|
+
sharesFilter = getUserObjectSharesFilters(this.name, userSession);
|
|
1553
1697
|
|
|
1554
1698
|
if (!_.isEmpty(companyFilter)) {
|
|
1555
|
-
permissionFilters.push(`(${companyFilter.join('
|
|
1699
|
+
permissionFilters.push(`(${companyFilter.join(' and ')})`);
|
|
1556
1700
|
}
|
|
1557
1701
|
|
|
1558
1702
|
if (ownerFilter) {
|
|
@@ -1587,9 +1731,14 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1587
1731
|
}
|
|
1588
1732
|
}
|
|
1589
1733
|
else if (method === 'update' || method === 'updateOne') {
|
|
1590
|
-
|
|
1734
|
+
const permissionFilters = null; //this.getObjectPermissionFilters(objPm, userSession, true);
|
|
1735
|
+
if (!objPm.allowEdit && _.isEmpty(permissionFilters)) {
|
|
1591
1736
|
throw new Error(`no ${method} permission!`);
|
|
1592
1737
|
}
|
|
1738
|
+
let objectPermissionEditFilters = '';
|
|
1739
|
+
if (!_.isEmpty(permissionFilters)) {
|
|
1740
|
+
objectPermissionEditFilters = ` or (${permissionFilters.join(' or ')})`
|
|
1741
|
+
}
|
|
1593
1742
|
let id = args[args.length - 3];
|
|
1594
1743
|
if (!objPm.modifyAllRecords && objPm.modifyCompanyRecords) {
|
|
1595
1744
|
let companyFilters = _.map(userSession.companies, function (comp: any) {
|
|
@@ -1597,25 +1746,35 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1597
1746
|
}).join(' or ')
|
|
1598
1747
|
if (companyFilters) {
|
|
1599
1748
|
if (_.isString(id)) {
|
|
1600
|
-
id = { filters: `(_id eq \'${id}\') and (${companyFilters})` }
|
|
1749
|
+
id = { filters: `(_id eq \'${id}\') and (${companyFilters}${objectPermissionEditFilters})` }
|
|
1601
1750
|
}
|
|
1602
1751
|
else if (_.isObject(id)) {
|
|
1603
1752
|
if (id.filters && !_.isString(id.filters)) {
|
|
1604
1753
|
id.filters = formatFiltersToODataQuery(id.filters);
|
|
1605
1754
|
}
|
|
1606
|
-
id.filters = id.filters ? `(${id.filters}) and (${companyFilters})` : `(${companyFilters})`;
|
|
1755
|
+
id.filters = id.filters ? `(${id.filters}) and (${companyFilters}${objectPermissionEditFilters})` : `(${companyFilters}${objectPermissionEditFilters})`;
|
|
1607
1756
|
}
|
|
1608
1757
|
}
|
|
1609
1758
|
}
|
|
1610
1759
|
else if (!objPm.modifyAllRecords && !objPm.modifyCompanyRecords && objPm.allowEdit) {
|
|
1611
1760
|
if (_.isString(id)) {
|
|
1612
|
-
id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\')` }
|
|
1761
|
+
id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\' ${objectPermissionEditFilters})` }
|
|
1613
1762
|
}
|
|
1614
1763
|
else if (_.isObject(id)) {
|
|
1615
1764
|
if (id.filters && !_.isString(id.filters)) {
|
|
1616
1765
|
id.filters = formatFiltersToODataQuery(id.filters);
|
|
1617
1766
|
}
|
|
1618
|
-
id.filters = id.filters ? `(${id.filters}) and (owner eq \'${userId}\')` : `(owner eq \'${userId}\')`;
|
|
1767
|
+
id.filters = id.filters ? `(${id.filters}) and (owner eq \'${userId}\' ${objectPermissionEditFilters})` : `(owner eq \'${userId}\' ${objectPermissionEditFilters})`;
|
|
1768
|
+
}
|
|
1769
|
+
} else if (objectPermissionEditFilters) {
|
|
1770
|
+
if (_.isString(id)) {
|
|
1771
|
+
id = { filters: `(_id eq \'${id}\') and (${objectPermissionEditFilters})` }
|
|
1772
|
+
}
|
|
1773
|
+
else if (_.isObject(id)) {
|
|
1774
|
+
if (id.filters && !_.isString(id.filters)) {
|
|
1775
|
+
id.filters = formatFiltersToODataQuery(id.filters);
|
|
1776
|
+
}
|
|
1777
|
+
id.filters = id.filters ? `(${id.filters}) and (${objectPermissionEditFilters})` : `(${objectPermissionEditFilters})`;
|
|
1619
1778
|
}
|
|
1620
1779
|
}
|
|
1621
1780
|
args[args.length - 3] = id;
|
|
@@ -1639,20 +1798,37 @@ export class SteedosObjectType extends SteedosObjectProperties {
|
|
|
1639
1798
|
}
|
|
1640
1799
|
}
|
|
1641
1800
|
else if (method === 'delete') {
|
|
1642
|
-
|
|
1801
|
+
const permissionFilters = null; //this.getObjectPermissionFilters(objPm, userSession, true);
|
|
1802
|
+
if (!objPm.allowDelete && _.isEmpty(permissionFilters)) {
|
|
1643
1803
|
throw new Error(`no ${method} permission!`);
|
|
1644
1804
|
}
|
|
1805
|
+
|
|
1806
|
+
let objectPermissionEditFilters = '';
|
|
1807
|
+
if (!_.isEmpty(permissionFilters)) {
|
|
1808
|
+
objectPermissionEditFilters = ` or (${permissionFilters.join(' or ')})`
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1645
1811
|
let id = args[args.length - 2];
|
|
1646
1812
|
if (!objPm.modifyAllRecords && objPm.modifyCompanyRecords) {
|
|
1647
1813
|
let companyFilters = _.map(userSession.companies, function (comp: any) {
|
|
1648
1814
|
return `(company_id eq '${comp._id}') or (company_ids eq '${comp._id}')`
|
|
1649
1815
|
}).join(' or ')
|
|
1650
1816
|
if (companyFilters) {
|
|
1651
|
-
id = { filters: `(_id eq \'${id}\') and (${companyFilters})` };
|
|
1817
|
+
id = { filters: `(_id eq \'${id}\') and (${companyFilters}${objectPermissionEditFilters})` };
|
|
1652
1818
|
}
|
|
1653
1819
|
}
|
|
1654
1820
|
else if (!objPm.modifyAllRecords && !objPm.modifyCompanyRecords) {
|
|
1655
|
-
id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\')` };
|
|
1821
|
+
id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\'${objectPermissionEditFilters})` };
|
|
1822
|
+
} else if (objectPermissionEditFilters) {
|
|
1823
|
+
if (_.isString(id)) {
|
|
1824
|
+
id = { filters: `(_id eq \'${id}\') and (${objectPermissionEditFilters})` }
|
|
1825
|
+
}
|
|
1826
|
+
else if (_.isObject(id)) {
|
|
1827
|
+
if (id.filters && !_.isString(id.filters)) {
|
|
1828
|
+
id.filters = formatFiltersToODataQuery(id.filters);
|
|
1829
|
+
}
|
|
1830
|
+
id.filters = id.filters ? `(${id.filters}) and (${objectPermissionEditFilters})` : `(${objectPermissionEditFilters})`;
|
|
1831
|
+
}
|
|
1656
1832
|
}
|
|
1657
1833
|
args[args.length - 2] = id;
|
|
1658
1834
|
}
|
|
@@ -3,7 +3,7 @@ import path = require('path')
|
|
|
3
3
|
import { SteedosObjectTypeConfig, SteedosObjectPermissionTypeConfig, SteedosActionTypeConfig, getDataSource } from '.'
|
|
4
4
|
// import { isMeteor } from '../util'
|
|
5
5
|
import { Dictionary } from '@salesforce/ts-types';
|
|
6
|
-
import { loadObjectFields, loadObjectListViews, loadObjectButtons, loadObjectMethods, loadObjectActions, loadObjectTriggers, addObjectListenerConfig, loadObjectLayouts, getLazyLoadFields, getLazyLoadButtons, loadObjectPermissions, loadSourceProfiles, loadSourcePermissionset, loadObjectValidationRules, loadSourceRoles, loadSourceFlowRoles, loadSourceApprovalProcesses, loadSourceWorkflows, loadStandardProfiles, loadStandardPermissionsets, preloadDBObjectFields, preloadDBObjectButtons, preloadDBApps, preloadDBObjectLayouts, preloadDBTabs } from '../dynamic-load'
|
|
6
|
+
import { loadObjectFields, loadObjectListViews, loadObjectButtons, loadObjectMethods, loadObjectActions, loadObjectTriggers, addObjectListenerConfig, loadObjectLayouts, getLazyLoadFields, getLazyLoadButtons, loadObjectPermissions, loadSourceProfiles, loadSourcePermissionset, loadObjectValidationRules, loadSourceRoles, loadSourceFlowRoles, loadSourceApprovalProcesses, loadSourceWorkflows, loadStandardProfiles, loadStandardPermissionsets, preloadDBObjectFields, preloadDBObjectButtons, preloadDBApps, preloadDBObjectLayouts, preloadDBTabs, preloadDBShareRules, preloadDBRestrictionRules, preloadDBPermissionFields } from '../dynamic-load'
|
|
7
7
|
import { transformListenersToTriggers } from '..';
|
|
8
8
|
import { getSteedosSchema } from './schema';
|
|
9
9
|
|
|
@@ -338,6 +338,9 @@ export const loadStandardMetadata = async (serviceName: string, datasourceApiNam
|
|
|
338
338
|
await preloadDBObjectLayouts(datasource);
|
|
339
339
|
await preloadDBObjectFields(datasource);
|
|
340
340
|
await preloadDBObjectButtons(datasource);
|
|
341
|
+
await preloadDBShareRules(datasource);
|
|
342
|
+
await preloadDBRestrictionRules(datasource);
|
|
343
|
+
await preloadDBPermissionFields(datasource);
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
346
|
}
|
|
@@ -22,6 +22,7 @@ abstract class SteedosObjectPermissionTypeProperties {
|
|
|
22
22
|
unreadable_fields?: string[]
|
|
23
23
|
uneditable_fields?: string[]
|
|
24
24
|
unrelated_objects?: string[]
|
|
25
|
+
field_permissions?: any
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export interface SteedosObjectPermissionTypeConfig extends SteedosObjectPermissionTypeProperties { }
|
|
@@ -71,6 +72,37 @@ export class SteedosObjectPermissionType extends SteedosObjectPermissionTypeProp
|
|
|
71
72
|
this.allowRead = true;
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
if (this.allowRead) {
|
|
76
|
+
typeof this.allowReadFiles !== "boolean" && (this.allowReadFiles = true);
|
|
77
|
+
typeof this.viewAllFiles !== "boolean" && (this.viewAllFiles = true);
|
|
78
|
+
}
|
|
79
|
+
if (this.allowEdit) {
|
|
80
|
+
typeof this.allowCreateFiles !== "boolean" && (this.allowCreateFiles = true);
|
|
81
|
+
typeof this.allowEditFiles !== "boolean" && (this.allowEditFiles = true);
|
|
82
|
+
typeof this.allowDeleteFiles !== "boolean" && (this.allowDeleteFiles = true);
|
|
83
|
+
}
|
|
84
|
+
if (this.modifyAllRecords) {
|
|
85
|
+
typeof this.modifyAllFiles !== "boolean" && (this.modifyAllFiles = true);
|
|
86
|
+
}
|
|
87
|
+
if (this.allowCreateFiles) {
|
|
88
|
+
this.allowReadFiles = true;
|
|
89
|
+
}
|
|
90
|
+
if (this.allowEditFiles) {
|
|
91
|
+
this.allowReadFiles = true;
|
|
92
|
+
}
|
|
93
|
+
if (this.allowDeleteFiles) {
|
|
94
|
+
this.allowEditFiles = true;
|
|
95
|
+
this.allowReadFiles = true;
|
|
96
|
+
}
|
|
97
|
+
if (this.viewAllFiles) {
|
|
98
|
+
this.allowReadFiles = true;
|
|
99
|
+
}
|
|
100
|
+
if (this.modifyAllFiles) {
|
|
101
|
+
this.allowReadFiles = true;
|
|
102
|
+
this.allowEditFiles = true;
|
|
103
|
+
this.allowDeleteFiles = true;
|
|
104
|
+
this.viewAllFiles = true;
|
|
105
|
+
}
|
|
74
106
|
this.object_name = object_name
|
|
75
107
|
}
|
|
76
108
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { registerRestrictionRules } from '../metadata-register/restrictionRules';
|
|
2
|
+
import { getSteedosSchema } from '../types'
|
|
3
|
+
import * as _ from 'lodash'
|
|
4
|
+
import { isExpression, parseSingleExpression } from '../util'
|
|
5
|
+
import { formatFiltersToODataQuery } from "@steedos/filters";
|
|
6
|
+
|
|
7
|
+
export type SteedosRestrictionRuleConfig = {
|
|
8
|
+
_id: string,
|
|
9
|
+
name: string,
|
|
10
|
+
object_name: string,
|
|
11
|
+
active: boolean,
|
|
12
|
+
record_filter: string,
|
|
13
|
+
entry_criteria: string,
|
|
14
|
+
description: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class RestrictionRule {
|
|
18
|
+
static async find(objectApiName) {
|
|
19
|
+
const schema = getSteedosSchema();
|
|
20
|
+
return await registerRestrictionRules.find(schema.broker, {
|
|
21
|
+
pattern: `${objectApiName}.*`
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
static async getUserObjectFilters(objectApiName, userSession: any) {
|
|
25
|
+
const rules = await this.find(objectApiName);
|
|
26
|
+
if (_.isEmpty(rules)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const rulesFilters = [];
|
|
30
|
+
const globalData = { now: new Date() };
|
|
31
|
+
_.each(rules, (rule) => {
|
|
32
|
+
const { active, entry_criteria, record_filter } = rule.metadata;
|
|
33
|
+
if (active) {
|
|
34
|
+
if (_.isString(entry_criteria) && isExpression(entry_criteria.trim())) {
|
|
35
|
+
try {
|
|
36
|
+
const meetCriteria = parseSingleExpression(entry_criteria, {}, "#", globalData, userSession);
|
|
37
|
+
if (_.isBoolean(meetCriteria) && meetCriteria) {
|
|
38
|
+
if (_.isString(record_filter) && isExpression(record_filter.trim())) {
|
|
39
|
+
try {
|
|
40
|
+
const filters = parseSingleExpression(record_filter, {}, "#", globalData, userSession);
|
|
41
|
+
if (filters && !_.isString(filters)) {
|
|
42
|
+
rulesFilters.push(`(${formatFiltersToODataQuery(filters, userSession)})`)
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`RestrictionRule.getUserObjectFilters record_filter error`, objectApiName, record_filter, error.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(`RestrictionRule.getUserObjectFilters entry_criteria error`, objectApiName, entry_criteria, error.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
return rulesFilters;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { registerShareRules } from '../metadata-register/shareRules';
|
|
2
|
+
import { getSteedosSchema } from '../types'
|
|
3
|
+
import * as _ from 'lodash'
|
|
4
|
+
import { isExpression, parseSingleExpression } from '../util'
|
|
5
|
+
import { formatFiltersToODataQuery } from "@steedos/filters";
|
|
6
|
+
|
|
7
|
+
export type SteedosShareRuleConfig = {
|
|
8
|
+
_id: string,
|
|
9
|
+
name: string,
|
|
10
|
+
object_name: string,
|
|
11
|
+
active: boolean,
|
|
12
|
+
record_filter: string,
|
|
13
|
+
entry_criteria: string,
|
|
14
|
+
description: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class ShareRules {
|
|
18
|
+
static async find(objectApiName) {
|
|
19
|
+
const schema = getSteedosSchema();
|
|
20
|
+
return await registerShareRules.find(schema.broker, {
|
|
21
|
+
pattern: `${objectApiName}.*`
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
static async getUserObjectFilters(objectApiName, userSession: any) {
|
|
25
|
+
const rules = await this.find(objectApiName);
|
|
26
|
+
if (_.isEmpty(rules)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const rulesFilters = [];
|
|
30
|
+
const globalData = { now: new Date() };
|
|
31
|
+
_.each(rules, (rule) => {
|
|
32
|
+
const { active, entry_criteria, record_filter } = rule.metadata;
|
|
33
|
+
if (active) {
|
|
34
|
+
if (_.isString(entry_criteria) && isExpression(entry_criteria.trim())) {
|
|
35
|
+
try {
|
|
36
|
+
const meetCriteria = parseSingleExpression(entry_criteria, {}, "#", globalData, userSession);
|
|
37
|
+
if (_.isBoolean(meetCriteria) && meetCriteria) {
|
|
38
|
+
if (_.isString(record_filter) && isExpression(record_filter.trim())) {
|
|
39
|
+
try {
|
|
40
|
+
const filters = parseSingleExpression(record_filter, {}, "#", globalData, userSession);
|
|
41
|
+
if (filters && !_.isString(filters)) {
|
|
42
|
+
rulesFilters.push(`(${formatFiltersToODataQuery(filters, userSession)})`)
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`ShareRules.getUserObjectFilters record_filter error`, objectApiName, record_filter, error.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(`ShareRules.getUserObjectFilters entry_criteria error`, objectApiName, entry_criteria, error.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
return rulesFilters;
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/util/field.ts
CHANGED
|
@@ -71,13 +71,13 @@ export const getFieldsByType = (doc, type: string, dataType?: string) => {
|
|
|
71
71
|
fields.push({ name: 'formula_blank_value', required: false });
|
|
72
72
|
fields.push({ name: 'summary_object', required: true });
|
|
73
73
|
fields.push({ name: 'summary_type', required: true });
|
|
74
|
-
fields.push({ name: 'summary_filters', required:
|
|
74
|
+
fields.push({ name: 'summary_filters', required: false });
|
|
75
75
|
if (doc.summary_type != 'count') {
|
|
76
76
|
fields.push({ name: 'summary_field', required: true });
|
|
77
77
|
}
|
|
78
|
-
fields.push({ name: 'data_type', required:
|
|
79
|
-
fields.push({ name: 'precision', required:
|
|
80
|
-
fields.push({ name: 'scale', required:
|
|
78
|
+
fields.push({ name: 'data_type', required: false });
|
|
79
|
+
fields.push({ name: 'precision', required: true });
|
|
80
|
+
fields.push({ name: 'scale', required: true });
|
|
81
81
|
fields.push({ name: 'filters' });
|
|
82
82
|
fields.push({ name: 'filters.$' });
|
|
83
83
|
fields.push({ name: 'filters.$.field' });
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as _ from 'lodash'
|
|
2
|
+
|
|
3
|
+
const globalTag = '__G_L_O_B_A_L__';
|
|
4
|
+
|
|
5
|
+
const getParentPath = function (path) {
|
|
6
|
+
var pathArr;
|
|
7
|
+
if (typeof path === 'string') {
|
|
8
|
+
pathArr = path.split('.');
|
|
9
|
+
if (pathArr.length === 1) {
|
|
10
|
+
return '#';
|
|
11
|
+
}
|
|
12
|
+
pathArr.pop();
|
|
13
|
+
return pathArr.join('.');
|
|
14
|
+
}
|
|
15
|
+
return '#';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getValueByPath = function (formData, path) {
|
|
19
|
+
if (path === '#' || !path) {
|
|
20
|
+
return formData || {};
|
|
21
|
+
} else if (typeof path === 'string') {
|
|
22
|
+
return _.get(formData, path);
|
|
23
|
+
} else {
|
|
24
|
+
console.error('path has to be a string');
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const isExpression = function (func) {
|
|
29
|
+
var pattern, reg1, reg2;
|
|
30
|
+
if (typeof func !== 'string') {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
pattern = /^{{(.+)}}$/;
|
|
34
|
+
reg1 = /^{{(function.+)}}$/;
|
|
35
|
+
reg2 = /^{{(.+=>.+)}}$/;
|
|
36
|
+
if (typeof func === 'string' && func.match(pattern) && !func.match(reg1) && !func.match(reg2)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const parseSingleExpression = function (func, formData, dataPath, global, userSession = {}) {
|
|
43
|
+
var error, funcBody, parent, parentPath, str;
|
|
44
|
+
|
|
45
|
+
if (formData === void 0) {
|
|
46
|
+
formData = {};
|
|
47
|
+
}
|
|
48
|
+
parentPath = getParentPath(dataPath);
|
|
49
|
+
parent = getValueByPath(formData, parentPath) || {};
|
|
50
|
+
if (typeof func === 'string') {
|
|
51
|
+
funcBody = func.substring(2, func.length - 2);
|
|
52
|
+
str = `\n var $user=${JSON.stringify(userSession)}; return ` + funcBody.replace(/\bformData\b/g, JSON.stringify(formData).replace(/\bglobal\b/g, globalTag)).replace(/\bglobal\b/g, JSON.stringify(global)).replace(new RegExp('\\b' + globalTag + '\\b', 'g'), 'global').replace(/rootValue/g, JSON.stringify(parent));
|
|
53
|
+
try {
|
|
54
|
+
return Function(str)();
|
|
55
|
+
} catch (_error) {
|
|
56
|
+
error = _error;
|
|
57
|
+
console.log(error, func, dataPath);
|
|
58
|
+
return func;
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
return func;
|
|
62
|
+
}
|
|
63
|
+
};
|
package/src/util/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * from './permission_shares'
|
|
|
27
27
|
export * from './suffix'
|
|
28
28
|
export * from './locale'
|
|
29
29
|
export * from './field'
|
|
30
|
+
export * from './function_expression'
|
|
30
31
|
|
|
31
32
|
exports.loadJSONFile = (filePath: string)=>{
|
|
32
33
|
return JSON.parse(fs.readFileSync(filePath, 'utf8').normalize('NFC'));
|