@steedos/standard-permission 2.5.0-beta.17 → 2.5.0-beta.19

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.
@@ -107,5 +107,6 @@ label: 复制
107
107
  type: amis_button
108
108
  visible: !!js/function |
109
109
  function (object_name, record_id, record_permissions, record) {
110
+ return false;
110
111
  return record.record.type == 'profile';
111
112
  }
@@ -2,8 +2,10 @@
2
2
  * @Author: sunhaolin@hotoa.com
3
3
  * @Date: 2022-05-26 16:56:54
4
4
  * @LastEditors: sunhaolin@hotoa.com
5
- * @LastEditTime: 2023-04-25 17:13:09
5
+ * @LastEditTime: 2023-04-28 14:59:28
6
6
  * @Description: 复制已有简档来创建新简档
7
+ * 使用mongodb的事务处理,保证数据的一致性
8
+ * 复制对象包括:简档、对象权限、字段权限、选项卡权限
7
9
  */
8
10
  'use strict';
9
11
  // @ts-check
@@ -12,6 +14,8 @@ const express = require("express");
12
14
  const router = express.Router();
13
15
  const core = require('@steedos/core');
14
16
  const objectql = require('@steedos/objectql');
17
+ const InternalData = require('@steedos/standard-objects').internalData;
18
+ const _ = require('underscore');
15
19
 
16
20
  /**
17
21
  * body {
@@ -38,11 +42,8 @@ router.post('/api/permission/permission_set/copy', core.requireAuthentication, a
38
42
 
39
43
  const psObj = objectql.getObject('permission_set');
40
44
  const poObj = objectql.getObject('permission_objects');
41
- const pfObj = objectql.getObject('permission_fields');
42
45
  const ptObj = objectql.getObject('permission_tabs');
43
46
 
44
- // const originalPermissionSet = (await psObj.find({ filters:[ ['name', '=', originalPermissionSetId], ['space', '=', spaceId] ] }, userSession))[0]
45
-
46
47
  const originalPermissionSet = await psObj.findOne(originalPermissionSetId, {}, userSession);
47
48
  if (!originalPermissionSet) {
48
49
  throw new Error("permission_set not found");
@@ -51,88 +52,239 @@ router.post('/api/permission/permission_set/copy', core.requireAuthentication, a
51
52
  if (originalPermissionSet.type !== 'profile') {
52
53
  throw new Error("permission_set is not profile type");
53
54
  }
55
+ // API名称不能重复
56
+ const existPermissionSetCount = await psObj.count({
57
+ filters: [
58
+ ['name', '=', name],
59
+ ['space', '=', spaceId],
60
+ ]
61
+ }, userSession);
62
+ if (existPermissionSetCount > 0) {
63
+ throw new Error("API名称不能重复");
64
+ }
54
65
 
55
- // 基础信息
56
- const baseInfo = {
57
- created: new Date(),
58
- created_by: userId,
59
- modified: new Date(),
60
- modified_by: userId,
61
- space: spaceId,
62
- company_id: company_id
63
- };
64
-
65
- // 创建新简档
66
- let newPermissionSetData = {
67
- ...originalPermissionSet,
68
- ...baseInfo,
69
- is_system: false,
70
- name,
71
- label
72
- };
73
-
74
- delete newPermissionSetData._id;
75
- delete newPermissionSetData.record_permissions;
76
- const newPermissionSet = await psObj.insert(newPermissionSetData);
77
-
78
-
79
- // 创建对象权限和选项卡权限
80
- if (newPermissionSet) {
81
- const orininalPermissionSetName = originalPermissionSet.name;
82
- const { _id: newPermissionSetId, name: newPermissionSetName } = newPermissionSet;
83
- const originalPermissionObjects = await poObj.find({ filters: [['space', '=', spaceId], ['permission_set_id', '=', originalPermissionSetId]] }, userSession);
84
- // 遍历原有的对象权限
85
- for (const poDoc of originalPermissionObjects) {
86
- // 创建新的对象权限
87
- delete poDoc._id;
88
- const newPermissionObject = await poObj.directInsert({
89
- ...poDoc,
90
- ...baseInfo,
91
- permission_set_id: newPermissionSetId,
92
- });
93
- // 创建新的字段权限
94
- // 由于 15.permission_objects.observe.object.js 中的 _change 函数中,调用了 permission_fields.resetFieldPermissions 方法,会自动创建新的字段权限,为防止重复创建故这里不手动创建
95
- // if (newPermissionObject) {
96
- // const newPermissionObjectName = newPermissionObject.name;
97
- // const originalPermissionFields = await pfObj.find({ filters: [['space', '=', spaceId], ['permission_set_id', '=', orininalPermissionSetName], ['permission_object', '=', poDoc.name]] }, userSession);
98
- // // 遍历原有的字段权限
99
- // for (const pfDoc of originalPermissionFields) {
100
- // // 创建新的字段权限
101
- // delete pfDoc._id;
102
- // const newPermissionField = await pfObj.insert({
103
- // ...pfDoc,
104
- // ...baseInfo,
105
- // permission_set_id: newPermissionSetName,
106
- // permission_object_id: newPermissionObjectName
107
- // });
108
- // }
109
- // }
110
- }
66
+ // 事务 https://www.mongodb.com/docs/v4.4/core/transactions-in-applications/#core-api
67
+ const config = objectql.getSteedosConfig();
68
+ let datasourceConfig = config.datasources['default'];
69
+ const driver = new objectql.SteedosMongoDriver(datasourceConfig.connection);
70
+ await driver.connect();
71
+ const client = driver._client;
72
+ const db = client.db();
73
+
74
+ // Start a session.
75
+ const session = client.startSession();
76
+
77
+ const permissionObjectsColl = db.collection('permission_objects');
78
+ const permissionFieldsColl = db.collection('permission_fields');
79
+ const permissionTabsColl = db.collection('permission_tabs');
80
+ const permissionSetColl = db.collection('permission_set');
81
+
82
+ // Start a transaction
83
+ session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
84
+
85
+ let newPermissionSet = null;
86
+
87
+ // Operations inside the transaction
88
+ try {
89
+ // 基础信息
90
+ const baseInfo = {
91
+ created: new Date(),
92
+ created_by: userId,
93
+ modified: new Date(),
94
+ modified_by: userId,
95
+ space: spaceId,
96
+ company_id: company_id,
97
+ company_ids: [company_id],
98
+ owner: userId,
99
+ };
100
+
101
+ // 创建新简档
102
+ let newPermissionSetData = {
103
+ ...originalPermissionSet,
104
+ ...baseInfo,
105
+ is_system: false,
106
+ name,
107
+ label,
108
+ _id: driver._makeNewID(),
109
+ copy_from: originalPermissionSetId,
110
+ };
111
111
 
112
+ delete newPermissionSetData.record_permissions;
113
+ const insertPermissionSetResult = await permissionSetColl.insertOne(newPermissionSetData);
114
+ newPermissionSet = insertPermissionSetResult.ops[0];
115
+ console.log('newPermissionSet', newPermissionSet)
112
116
 
113
- // 创建选项卡权限
114
- const originalPermissionTabs = await ptObj.find({ filters: [['space', '=', spaceId], ['permission_set', '=', originalPermissionSet.name]] }, userSession);
115
- // 遍历原有的选项卡权限
116
- for (const ptDoc of originalPermissionTabs) {
117
- delete ptDoc._id;
118
- ptDoc.permission_set = name;
119
- const newPermissionTabs = await ptObj.directInsert({
120
- ...ptDoc,
121
- ...baseInfo,
122
- });
117
+ // 创建对象权限和选项卡权限
118
+ if (newPermissionSet) {
119
+ const { _id: newPermissionSetId, name: newPermissionSetName } = newPermissionSet;
120
+ // 对象权限数据来源于两个部分,1、内存 2、数据库
121
+ const internalPermissionObjects = await getInternalPermissionObjects(originalPermissionSetId);
122
+ const dbPermissionObjects = await poObj.directFind({ filters: [['space', '=', spaceId], ['permission_set_id', '=', originalPermissionSetId]] });
123
+ const originalPermissionObjects = getCombinedPermissionObjects(internalPermissionObjects, dbPermissionObjects);
124
+ const newPermissionObjects = []
125
+ const newPermissionFields = []
126
+ // 遍历原有的对象权限
127
+ for (const poDoc of originalPermissionObjects) {
128
+ const fromId = poDoc._id;
129
+ const newId = driver._makeNewID();
130
+ // 由于 15.permission_objects.observe.object.js 中的 _change 函数中,调用了 permission_fields.resetFieldPermissions 方法,会阻塞redis查询,需要调整15.permission_objects.observe.object.js, 避免调用 resetFieldPermissions 方法
131
+ const newPermissionObject = {
132
+ ...poDoc,
133
+ ...baseInfo,
134
+ permission_set_id: newPermissionSetId,
135
+ name: `${poDoc.object_name}.${newPermissionSetName}`,
136
+ _id: newId,
137
+ copy_from: fromId
138
+ };
139
+ newPermissionObjects.push(newPermissionObject)
140
+ // 获取对象所有字段
141
+ const fields = await objectql.getObject('object_fields').find({ filters: [['object', '=', newPermissionObject.object_name]] });
142
+ for (const field of fields) {
143
+ const apiName = `${newPermissionSetName}.${newPermissionObject.object_name}.${field.name}`
144
+ const fieldPermission = await getFieldPermission(apiName)
145
+ newPermissionFields.push({
146
+ ...baseInfo,
147
+ name: apiName,
148
+ permission_set_id: newPermissionSetName,
149
+ permission_object: newPermissionObject.name,
150
+ object_name: newPermissionObject.object_name,
151
+ field: field.name,
152
+ editable: fieldPermission ? fieldPermission.editable : getFieldDefaultEditable(field),
153
+ readable: fieldPermission ? fieldPermission.readable : getFieldDefaultReadable(field),
154
+ _id: driver._makeNewID(),
155
+ })
156
+ }
157
+ }
158
+
159
+ const originalPermissionTabs = await ptObj.find({ filters: [['space', '=', spaceId], ['permission_set', '=', originalPermissionSet.name]] }, userSession);
160
+ const newPermissionTabs = [];
161
+ // 遍历原有的选项卡权限
162
+ for (const ptDoc of originalPermissionTabs) {
163
+ const fromId = ptDoc._id;
164
+ const newId = driver._makeNewID();
165
+ delete ptDoc.record_permissions;
166
+ newPermissionTabs.push({
167
+ ...ptDoc,
168
+ ...baseInfo,
169
+ permission_set: newPermissionSetName,
170
+ _id: newId,
171
+ is_system: false,
172
+ copy_from: fromId
173
+ })
174
+ }
175
+
176
+ // 批量创建对象权限
177
+ await permissionObjectsColl.insertMany(newPermissionObjects, { session });
178
+
179
+ // 批量创建字段权限
180
+ await permissionFieldsColl.insertMany(newPermissionFields, { session });
181
+
182
+ // 批量创建选项卡权限
183
+ await permissionTabsColl.insertMany(newPermissionTabs, { session });
123
184
  }
124
185
 
186
+ } catch (error) {
187
+ // Abort transaction on error
188
+ await session.abortTransaction();
189
+ throw error;
125
190
  }
126
191
 
127
- res.status(200).send({
128
- message: 'success' ,
192
+ // Commit the transaction using write concern set at transaction start
193
+ await session.commitTransaction();
194
+ await session.endSession();
195
+ await client.close();
196
+
197
+ if (!newPermissionSet) {
198
+ throw new Error("create permission_set failed");
199
+ }
200
+
201
+ res.status(200).send({
202
+ message: 'success',
129
203
  recordId: newPermissionSet._id
130
204
  });
131
-
205
+
132
206
  } catch (error) {
133
207
  console.error(error);
134
208
  res.status(500).send({ error: error.message });
135
209
  }
136
210
 
137
211
  });
138
- exports.default = router;
212
+ exports.default = router;
213
+
214
+ // 获取内存中的对象权限
215
+ async function getInternalPermissionObjects(permissionSetId) {
216
+ // 查找permissionSetId对应的permissionSet
217
+ const permissionSetDoc = (await objectql.getObject('permission_set').directFind({
218
+ filters: [
219
+ ['_id', '=', permissionSetId],
220
+ ]
221
+ })[0]);
222
+ // 如果库中有记录则使用库中的name作为判断条件,否则使用permissionSetId
223
+ const permissionSetName = permissionSetDoc ? permissionSetDoc.name : permissionSetId;
224
+
225
+ let objectsPermissions = [];
226
+ const datasources = objectql.getSteedosSchema().getDataSources();
227
+ for (const datasourceName in datasources) {
228
+ let datasource = datasources[datasourceName];
229
+ let datasourceObjects = await datasource.getObjects();
230
+ _.each(datasourceObjects, function (object) {
231
+ const objectJSON = object.metadata;
232
+ const objectName = objectJSON.name;
233
+ if (!objectJSON._id && !_.include(InternalData.hiddenObjects, objectName)) {
234
+ let permission_set = objectJSON.permission_set
235
+ _.each(permission_set, function (v, code) {
236
+ if (code === permissionSetName) {
237
+ objectsPermissions.push(Object.assign({}, v, { _id: `${code}_${objectName}`, name: `${code}_${objectName}`, permission_set_id: code, object_name: objectName }))
238
+ }
239
+ })
240
+ }
241
+ });
242
+ }
243
+ return objectsPermissions;
244
+ }
245
+ // 合并内存中的对象权限和数据库中的对象权限
246
+ // 如果dbPermissionObjects和internalPermissionObjects中permission_set_id存在相同的值,则以dbPermissionObjects中数据为准
247
+ function getCombinedPermissionObjects(internalPermissionObjects, dbPermissionObjects) {
248
+ const dbPermissionObjectsIds = _.pluck(dbPermissionObjects, 'permission_set_id');
249
+ const internalPermissionObjectsIds = _.pluck(internalPermissionObjects, 'permission_set_id');
250
+ const sameIds = _.intersection(dbPermissionObjectsIds, internalPermissionObjectsIds);
251
+ if (sameIds.length > 0) {
252
+ for (const sameId of sameIds) {
253
+ const dbPermissionObject = _.findWhere(dbPermissionObjects, { permission_set_id: sameId });
254
+ const internalPermissionObject = _.findWhere(internalPermissionObjects, { permission_set_id: sameId });
255
+ if (dbPermissionObject && internalPermissionObject) {
256
+ const index = internalPermissionObjects.indexOf(internalPermissionObject);
257
+ internalPermissionObjects.splice(index, 1, dbPermissionObject);
258
+ }
259
+ }
260
+ }
261
+ return [...internalPermissionObjects, ...dbPermissionObjects];
262
+ }
263
+
264
+ async function getFieldPermission(apiName) {
265
+ const schema = objectql.getSteedosSchema();
266
+ const config = await objectql.registerPermissionFields.get(schema.broker, apiName)
267
+ return config ? config.metadata : null;
268
+ }
269
+
270
+ const systemFields = ['owner', 'created', 'created_by', 'modified', 'modified_by', 'locked', 'company_id', 'company_ids', 'instance_state'];
271
+
272
+ const getFieldDefaultEditable = (field) => {
273
+ if (_.includes(systemFields, field.name) && (field.omit || field.hidden || field.readonly || field.disabled)) {
274
+ return false;
275
+ }
276
+ if (field.omit || field.hidden || field.readonly || field.disabled) {
277
+ return false;
278
+ }
279
+ return true;
280
+ }
281
+
282
+ const getFieldDefaultReadable = (field) => {
283
+ if (_.includes(systemFields, field.name) && !field.hidden) {
284
+ return true;
285
+ }
286
+ if (field.hidden) {
287
+ return false
288
+ }
289
+ return true;
290
+ }
@@ -99,7 +99,11 @@ module.exports = {
99
99
  if (matches) {
100
100
  const permissionSetId = matches[0];
101
101
  // 查找permissionSetId对应的permissionSet
102
- const permissionSetDoc = await objectql.getObject('permission_set').findOne(permissionSetId);
102
+ const permissionSetDoc = (await objectql.getObject('permission_set').directFind({
103
+ filters: [
104
+ ['_id', '=', permissionSetId],
105
+ ]
106
+ })[0]);
103
107
  if (permissionSetDoc) {
104
108
  // 替换this.query.filters中全部的的permission_set_id为permissionSetDoc.name
105
109
  this.query.filters = this.query.filters.replace(regex, permissionSetDoc.name).replace(`permission_set_id eq '${permissionSetDoc.name}'`, `(permission_set_id eq '${permissionSetDoc.name}') or (permission_set_id eq '${permissionSetId}')`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos/standard-permission",
3
- "version": "2.5.0-beta.17",
3
+ "version": "2.5.0-beta.19",
4
4
  "main": "package.service.js",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -12,5 +12,5 @@
12
12
  "description": "steedos package",
13
13
  "repository": {},
14
14
  "license": "MIT",
15
- "gitHead": "e91f79af27e59f8c53e5a947e3dfe5ef2e53dcda"
15
+ "gitHead": "99f85803376a6096f0262ff47689572818bf655b"
16
16
  }