@steedos/objectql 2.2.50 → 2.2.51-beta.4

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.
Files changed (143) hide show
  1. package/lib/services/helpers/graphql/consts.d.ts +17 -0
  2. package/lib/services/helpers/graphql/consts.js +28 -0
  3. package/lib/services/helpers/graphql/consts.js.map +1 -0
  4. package/lib/services/helpers/graphql/getQueryFields.js +17 -2
  5. package/lib/services/helpers/graphql/getQueryFields.js.map +1 -1
  6. package/lib/services/helpers/graphql/index.d.ts +1 -1
  7. package/lib/services/helpers/graphql/index.js +31 -46
  8. package/lib/services/helpers/graphql/index.js.map +1 -1
  9. package/lib/util/index.js +7 -0
  10. package/lib/util/index.js.map +1 -1
  11. package/package.json +11 -12
  12. package/src/actions/field_updates.ts +0 -118
  13. package/src/actions/index.ts +0 -3
  14. package/src/actions/types/field_update_target.ts +0 -7
  15. package/src/actions/types/workflow_notification.ts +0 -9
  16. package/src/actions/types/workflow_rule.ts +0 -11
  17. package/src/actions/workflow_notifications.ts +0 -81
  18. package/src/actions/workflow_rule.ts +0 -136
  19. package/src/driver/driver.ts +0 -102
  20. package/src/driver/field-encrytion/index.ts +0 -8
  21. package/src/driver/field-encrytion/sharedconst.ts +0 -34
  22. package/src/driver/fieldDBType.ts +0 -14
  23. package/src/driver/format.ts +0 -36
  24. package/src/driver/index.ts +0 -20
  25. package/src/driver/metadata.ts +0 -226
  26. package/src/driver/meteorMongo.ts +0 -639
  27. package/src/driver/mongo.ts +0 -416
  28. package/src/driver/mysql.ts +0 -47
  29. package/src/driver/oracle.ts +0 -60
  30. package/src/driver/postgres.ts +0 -46
  31. package/src/driver/sqlite3.ts +0 -40
  32. package/src/driver/sqlserver.ts +0 -52
  33. package/src/dynamic-load/actions.ts +0 -146
  34. package/src/dynamic-load/approval_process.ts +0 -73
  35. package/src/dynamic-load/button.ts +0 -75
  36. package/src/dynamic-load/chart.ts +0 -22
  37. package/src/dynamic-load/client_script.ts +0 -65
  38. package/src/dynamic-load/field.ts +0 -77
  39. package/src/dynamic-load/flow_role.ts +0 -46
  40. package/src/dynamic-load/index.ts +0 -21
  41. package/src/dynamic-load/layout.ts +0 -53
  42. package/src/dynamic-load/listview.ts +0 -57
  43. package/src/dynamic-load/method.ts +0 -63
  44. package/src/dynamic-load/object_translations.ts +0 -61
  45. package/src/dynamic-load/originalObject.ts +0 -8
  46. package/src/dynamic-load/package.ts +0 -312
  47. package/src/dynamic-load/page.ts +0 -23
  48. package/src/dynamic-load/permission.ts +0 -71
  49. package/src/dynamic-load/permissionset.ts +0 -78
  50. package/src/dynamic-load/preload_data.ts +0 -104
  51. package/src/dynamic-load/profile.ts +0 -90
  52. package/src/dynamic-load/query.ts +0 -22
  53. package/src/dynamic-load/restrictionRules.ts +0 -23
  54. package/src/dynamic-load/role.ts +0 -46
  55. package/src/dynamic-load/shareRules.ts +0 -23
  56. package/src/dynamic-load/tab.ts +0 -17
  57. package/src/dynamic-load/tabs.ts +0 -13
  58. package/src/dynamic-load/translations.ts +0 -54
  59. package/src/dynamic-load/trigger.ts +0 -236
  60. package/src/dynamic-load/validation_rule.ts +0 -77
  61. package/src/dynamic-load/workflow.ts +0 -114
  62. package/src/errors/index.ts +0 -111
  63. package/src/formula/core.ts +0 -490
  64. package/src/formula/field_formula.ts +0 -107
  65. package/src/formula/index.ts +0 -81
  66. package/src/formula/params.ts +0 -197
  67. package/src/formula/recompute.ts +0 -65
  68. package/src/formula/simple_params.ts +0 -92
  69. package/src/formula/type.ts +0 -107
  70. package/src/formula/util.ts +0 -207
  71. package/src/index.ts +0 -24
  72. package/src/metadata-register/_base.ts +0 -85
  73. package/src/metadata-register/app.ts +0 -30
  74. package/src/metadata-register/chart.ts +0 -9
  75. package/src/metadata-register/index.ts +0 -123
  76. package/src/metadata-register/layout.ts +0 -38
  77. package/src/metadata-register/object.ts +0 -68
  78. package/src/metadata-register/page.ts +0 -9
  79. package/src/metadata-register/permissionFields.ts +0 -13
  80. package/src/metadata-register/permissionset.ts +0 -25
  81. package/src/metadata-register/process.ts +0 -16
  82. package/src/metadata-register/processTrigger.ts +0 -24
  83. package/src/metadata-register/profile.ts +0 -25
  84. package/src/metadata-register/query.ts +0 -9
  85. package/src/metadata-register/restrictionRules.ts +0 -12
  86. package/src/metadata-register/shareRules.ts +0 -13
  87. package/src/metadata-register/tab.ts +0 -9
  88. package/src/metadata-register/tabs.ts +0 -43
  89. package/src/services/datasourceServiceFactory.ts +0 -55
  90. package/src/services/helpers/graphql/getPrimaryFieldType.ts +0 -48
  91. package/src/services/helpers/graphql/getQueryFields.ts +0 -36
  92. package/src/services/helpers/graphql/index.ts +0 -681
  93. package/src/services/helpers/rest.ts +0 -57
  94. package/src/services/index.ts +0 -13
  95. package/src/services/objectService.ts +0 -846
  96. package/src/services/objectServiceDispatcher.ts +0 -209
  97. package/src/services/objectServiceFactory.ts +0 -29
  98. package/src/summary/core.ts +0 -263
  99. package/src/summary/field_summary.ts +0 -71
  100. package/src/summary/index.ts +0 -96
  101. package/src/summary/recompute.ts +0 -31
  102. package/src/summary/type.ts +0 -60
  103. package/src/ts-types/index.ts +0 -3
  104. package/src/ts-types/permissionset.ts +0 -8
  105. package/src/ts-types/profile.ts +0 -11
  106. package/src/ts-types/triggerActionParams.ts +0 -22
  107. package/src/typeorm/driver.ts +0 -379
  108. package/src/typeorm/index.ts +0 -3
  109. package/src/typeorm/util.ts +0 -147
  110. package/src/types/action.ts +0 -52
  111. package/src/types/app.ts +0 -280
  112. package/src/types/config.ts +0 -152
  113. package/src/types/connection.ts +0 -87
  114. package/src/types/dashboard.ts +0 -91
  115. package/src/types/datasource.ts +0 -570
  116. package/src/types/field.ts +0 -370
  117. package/src/types/field_permission.ts +0 -42
  118. package/src/types/field_types.ts +0 -1
  119. package/src/types/index.ts +0 -21
  120. package/src/types/list_view.ts +0 -56
  121. package/src/types/listeners.ts +0 -18
  122. package/src/types/object.ts +0 -2076
  123. package/src/types/object_dynamic_load.ts +0 -426
  124. package/src/types/object_events.ts +0 -43
  125. package/src/types/object_layouts.ts +0 -20
  126. package/src/types/object_permission.ts +0 -134
  127. package/src/types/query.ts +0 -28
  128. package/src/types/report.ts +0 -128
  129. package/src/types/restrictionRule.ts +0 -57
  130. package/src/types/schema.ts +0 -273
  131. package/src/types/shareRule.ts +0 -57
  132. package/src/types/trigger.ts +0 -88
  133. package/src/types/userSession.ts +0 -45
  134. package/src/types/validation_rules.ts +0 -29
  135. package/src/util/convert.ts +0 -131
  136. package/src/util/field.ts +0 -93
  137. package/src/util/function_expression.ts +0 -63
  138. package/src/util/index.ts +0 -1058
  139. package/src/util/locale.ts +0 -24
  140. package/src/util/permission_shares.ts +0 -25
  141. package/src/util/suffix.ts +0 -78
  142. package/src/util/transform.ts +0 -239
  143. package/src/validators/index.ts +0 -36
@@ -1,2076 +0,0 @@
1
- import { Dictionary, JsonMap } from "@salesforce/ts-types";
2
- import { SteedosTriggerType, SteedosFieldType, SteedosFieldTypeConfig, SteedosSchema, SteedosListenerConfig, SteedosObjectListViewTypeConfig, SteedosObjectListViewType, SteedosIDType, SteedosObjectPermissionTypeConfig, SteedosActionType, SteedosActionTypeConfig, SteedosUserSession, getSteedosSchema } from ".";
3
- import { getUserObjectSharesFilters, isTemplateSpace, isCloudAdminSpace, generateActionParams, absoluteUrl } from '../util'
4
- import _ = require("underscore");
5
- import { SteedosTriggerTypeConfig, SteedosTriggerContextConfig } from "./trigger";
6
- import { SteedosQueryOptions, SteedosQueryFilters } from "./query";
7
- import { SteedosDataSourceType, SteedosDatabaseDriverType, getDataSource } from "./datasource";
8
- import { SteedosFieldDBType } from '../driver/fieldDBType';
9
- import { runCurrentObjectFieldFormulas, runQuotedByObjectFieldFormulas } from '../formula';
10
- import { runQuotedByObjectFieldSummaries, runCurrentObjectFieldSummaries } from '../summary';
11
- import { formatFiltersToODataQuery } from "@steedos/filters";
12
- import { WorkflowRulesRunner } from '../actions';
13
- import { runValidationRules } from './validation_rules';
14
- import { brokeEmitEvents } from "./object_events";
15
- import { translationObject } from "@steedos/i18n";
16
- import { getObjectLayouts } from "./object_layouts";
17
- import { sortBy, forEach } from 'lodash';
18
- import { ShareRules } from './shareRule';
19
- import { RestrictionRule } from './restrictionRule';
20
- import { FieldPermission } from './field_permission';
21
- import { getPatternListeners } from '../dynamic-load';
22
- import { getCacher } from '@steedos/cachers';
23
-
24
- const clone = require('clone')
25
-
26
- // 主子表有层级限制,超过3层就报错,该函数判断当前对象作为主表对象往下的层级最多不越过3层,
27
- // 其3层指的是A-B-C-D,它们都有父子关系,A作为最顶层,该对象上不可以再创建主表子表关系字段,但是B、C、D上可以;
28
- // 或者如果当前对象上创建的主表子表关系字段指向的对象是D,那么也会超过3层的层级限制;
29
- // 又或者中间加一层M先连接B再连接C,形成A-B-M-C-D,也会超过3层的层级限制;
30
- export const MAX_MASTER_DETAIL_LEAVE = 3;
31
-
32
- /**
33
- * 判断传入的paths中每条path下是否有重复对象名称,返回第一个重复的对象名称
34
- * 有可能传入的paths有多个链条,只要其中任何一个链条上有同名对象名说明异常,返回第一个异常的同名对象名即可
35
- * 比如传入下面示例中的paths,表示当前对象b向下有4条主子关系链,将返回第三条链中的重复对象名b
36
- * @param paths 对象上getDetailPaths或getMasterPaths函数返回的当前对象向下或向上取主表子表关联对象名称列表链条
37
- * [
38
- [ 'b', 't1', 't2' ],
39
- [ 'b', 't1', 'm1', 'm2' ],
40
- [ 'b', 't1', 'm2', 'b' ],
41
- [ 'b', 'c', 'd' ]
42
- * ]
43
- */
44
- export const getRepeatObjectNameFromPaths = (paths: string[]) => {
45
- let repeatItem: string;
46
- for (let p of paths) {
47
- if (repeatItem) {
48
- break;
49
- }
50
- let g = _.groupBy(p);
51
- for (let k in g) {
52
- if (g[k].length > 1) {
53
- repeatItem = k;
54
- break;
55
- }
56
- }
57
- }
58
- return repeatItem;
59
- }
60
-
61
- abstract class SteedosObjectProperties {
62
- _id?: string
63
- abstract name?: string
64
- extend?: string
65
- abstract table_name?: string
66
- label?: string
67
- icon?: string
68
- enable_search?: boolean
69
- is_enable?: boolean
70
- enable_files?: boolean
71
- enable_tasks?: boolean
72
- enable_notes?: boolean
73
- enable_events?: boolean
74
- enable_api?: boolean //TODO 未开放功能
75
- abstract enable_share?: boolean
76
- abstract enable_instances?: boolean
77
- enable_chatter?: boolean
78
- abstract enable_audit?: boolean
79
- abstract enable_trash?: boolean
80
- enable_space_global?: boolean
81
- enable_tree?: boolean
82
- parent_field?: string
83
- children_field?: string
84
- enable_enhanced_lookup?: boolean
85
- enable_inline_edit?: boolean
86
- enable_approvals?: boolean
87
- enable_process?: boolean
88
- is_view?: boolean
89
- hidden?: boolean
90
- description?: string
91
- custom?: boolean
92
- owner?: string
93
- // triggers?: object
94
- sidebar?: object //TODO
95
- calendar?: object //TODO
96
- abstract actions?: Dictionary<SteedosActionTypeConfig>
97
- abstract fields?: Dictionary<SteedosFieldTypeConfig>
98
- abstract listeners?: Dictionary<SteedosListenerConfig>
99
- abstract list_views?: Dictionary<SteedosObjectListViewTypeConfig>
100
- permissions?: Dictionary<SteedosObjectPermissionTypeConfig>
101
- methods?: Dictionary<Function>
102
- fields_serial_number?: number
103
- }
104
-
105
-
106
-
107
- export interface SteedosObjectTypeConfig extends SteedosObjectProperties {
108
- __filename?: string
109
- name?: string
110
- isMain?: boolean
111
- datasource?: string
112
- fields?: Dictionary<SteedosFieldTypeConfig>
113
- actions?: Dictionary<SteedosActionTypeConfig>
114
- listeners?: Dictionary<SteedosListenerConfig>
115
- permission_set?: Dictionary<SteedosObjectPermissionTypeConfig> //TODO remove ; 目前为了兼容现有object的定义保留
116
- }
117
-
118
- export const _TRIGGERKEYS = ['beforeFind', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterFind', 'afterCount', 'afterFindOne', 'afterInsert', 'afterUpdate', 'afterDelete', 'beforeAggregate', 'afterAggregate']
119
-
120
- const properties = ['label', 'icon', 'enable_search', 'sidebar', 'is_enable', 'enable_files', 'enable_tasks', 'enable_notes', 'enable_events', 'enable_api', 'enable_share', 'enable_instances', 'enable_chatter', 'enable_audit', 'enable_web_forms', 'enable_inline_edit', 'enable_approvals', 'enable_trash', 'enable_space_global', 'enable_tree', 'parent_field', 'children_field', 'enable_enhanced_lookup', 'enable_workflow', 'is_view', 'hidden', 'description', 'custom', 'owner', 'methods', '_id', 'relatedList', 'fields_serial_number', "is_enable", "in_development", "version", "paging"]
121
-
122
- export class SteedosObjectType extends SteedosObjectProperties {
123
-
124
- private _schema: SteedosSchema;
125
- private _datasource: SteedosDataSourceType;
126
- public get datasource(): SteedosDataSourceType {
127
- return this._datasource;
128
- }
129
- private _name: string;
130
- private _fields: Dictionary<SteedosFieldType> = {};
131
- private _actions: Dictionary<SteedosActionType> = {};
132
- private _listeners: Dictionary<SteedosListenerConfig> = {};
133
- private _triggers: Dictionary<SteedosTriggerType> = {};
134
- private _list_views: Dictionary<SteedosObjectListViewType> = {};
135
- private _table_name: string;
136
- private _triggersQueue: Dictionary<Dictionary<SteedosTriggerType>> = {}
137
- private _idFieldName: string;
138
- private _idFieldNames: string[] = [];
139
- private _NAME_FIELD_KEY: string;
140
- private _masters: string[] = [];
141
- private _details: string[] = [];
142
-
143
- private _enable_audit: boolean;
144
- public get enable_audit(): boolean {
145
- return this._enable_audit;
146
- }
147
- public set enable_audit(value: boolean) {
148
- if (value && !this._datasource.enable_space) {
149
- throw new Error(`not support, please set ${this._name}.enable_audit to false or remove the enable_audit attribute`)
150
- }
151
- this._enable_audit = value;
152
- }
153
-
154
- private _enable_instances: boolean;
155
- public get enable_instances(): boolean {
156
- return this._enable_instances;
157
- }
158
- public set enable_instances(value: boolean) {
159
- if (value && !this._datasource.enable_space) {
160
- throw new Error(`not support, please set ${this._name}.enable_instances to false or remove the enable_instances attribute`)
161
- }
162
- this._enable_instances = value;
163
- }
164
-
165
- private _enable_trash: boolean;
166
- public get enable_trash(): boolean {
167
- return this._enable_trash;
168
- }
169
- public set enable_trash(value: boolean) {
170
- if (value && !this._datasource.enable_space) {
171
- throw new Error(`not support, please set ${this._name}.enable_trash to false or remove the enable_trash attribute`)
172
- }
173
- this._enable_trash = value;
174
- }
175
-
176
- private _enable_share;
177
- public get enable_share(): boolean {
178
- return this._enable_share;
179
- }
180
- public set enable_share(value: boolean) {
181
- if (value && !this._datasource.enable_space) {
182
- throw new Error(`not support, please set ${this._name}.enable_share to false or remove the enable_share attribute`)
183
- }
184
- this._enable_share = value;
185
- }
186
-
187
- public get NAME_FIELD_KEY(): string {
188
- return this._NAME_FIELD_KEY;
189
- }
190
-
191
- getMethod(method_name: string) {
192
- return this.methods[method_name]
193
- }
194
-
195
- public get idFieldName(): string {
196
- return this._idFieldName;
197
- }
198
-
199
- public get idFieldNames(): string[] {
200
- return this._idFieldNames;
201
- }
202
-
203
- public get masters(): string[] {
204
- return this._masters;
205
- }
206
-
207
- public get details(): string[] {
208
- return this._details;
209
- }
210
-
211
- private async callMetadataObjectServiceAction(action, params?){
212
- const actionFullName = `objects.${action}`
213
- const result = await this.schema.metadataBroker.call(actionFullName, params);
214
- return result;
215
- }
216
-
217
- private checkField() {
218
- let driverSupportedColumnTypes = this._datasource.adapter.getSupportedColumnTypes()
219
- _.each(this.fields, (field: SteedosFieldType, key: string) => {
220
- if (SteedosFieldDBType[field.fieldDBType] && !driverSupportedColumnTypes.includes(field.fieldDBType)) {
221
- throw new Error(`driver ${this._datasource.driver} can not support field ${key} config`)
222
- }
223
- })
224
- }
225
-
226
- constructor(object_name: string, datasource: SteedosDataSourceType, config: SteedosObjectTypeConfig) {
227
- super();
228
- this._name = object_name
229
- this._datasource = datasource
230
- this._schema = datasource.schema
231
- if (this._datasource.driver != SteedosDatabaseDriverType.MeteorMongo)
232
- this._enable_share = false
233
-
234
- if (/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(object_name) != true) {
235
- throw new Error('invalid character, object_name can only be start with _ or a-zA-Z and contain only _ or _a-zA-Z0-9. you can set table_name');
236
- }
237
-
238
- if (config.table_name) {
239
- this._table_name = config.table_name
240
- } else {
241
- this._table_name = this._name
242
- }
243
-
244
- _.each(properties, (property) => {
245
- if (_.has(config, property)) {
246
- this[property] = config[property]
247
- }
248
- })
249
-
250
- _.each(config.fields, (field, field_name) => {
251
- this.setField(field_name, field)
252
- })
253
-
254
- this.checkField()
255
-
256
- _.each(config.actions, (action, action_name) => {
257
- this.setAction(action_name, action)
258
- })
259
-
260
- _.each(config.listeners, (listener, listener_name) => {
261
- this.setListener(listener_name, listener)
262
- })
263
-
264
- _.each(config.list_views, (list_view, name) => {
265
- this.setListView(name, list_view)
266
- })
267
-
268
- _.each(config.permissions, (permission, name) => {
269
- permission.name = name
270
- this.setPermission(permission)
271
- })
272
-
273
- //TODO remove ; 目前为了兼容现有object的定义保留
274
- _.each(config.permission_set, (permission, name) => {
275
- permission.name = name
276
- this.setPermission(permission)
277
- })
278
-
279
- if (this._datasource.driver == SteedosDatabaseDriverType.Mongo || this._datasource.driver == SteedosDatabaseDriverType.MeteorMongo) {
280
- this._idFieldName = '_id'
281
- }
282
-
283
- this.schema.setObjectMap(this.name, { datasourceName: this.datasource.name, _id: config._id })
284
- }
285
-
286
- getConfig(){
287
- return this.datasource.getObjectConfig(this.name);
288
- }
289
-
290
- setPermission(config: SteedosObjectPermissionTypeConfig) {
291
- this._datasource.setObjectPermission(this._name, config)
292
- }
293
-
294
- setListener(listener_name: string, config: SteedosListenerConfig) {
295
- this.listeners[listener_name] = config
296
- _TRIGGERKEYS.forEach((key) => {
297
- let event = config[key];
298
- if (_.isFunction(event)) {
299
- this.setTrigger(`${listener_name}_${event.name}`, key, event);
300
- }
301
- })
302
- }
303
-
304
- removeListener(listener_name: string, config: SteedosListenerConfig) {
305
- this.listeners[listener_name] = config
306
- _TRIGGERKEYS.forEach((key) => {
307
- try {
308
- let event = config[key];
309
- delete this._triggersQueue[key][`${listener_name}_${event.name}`]
310
- } catch (error) {
311
-
312
- }
313
- })
314
- }
315
-
316
- private setTrigger(name: string, when: string, todo: Function, on = 'server') {
317
- let triggerConfig: SteedosTriggerTypeConfig = {
318
- name: name,
319
- on: on,
320
- when: when,
321
- todo: todo,
322
- }
323
- let trigger = new SteedosTriggerType(triggerConfig)
324
- this.triggers[name] = trigger
325
- this.registerTrigger(trigger)
326
- }
327
-
328
- registerTrigger(trigger: SteedosTriggerType) {
329
- //如果是meteor mongo 则不做任何处理
330
- if (!_.isString(this._datasource.driver) || this._datasource.driver != SteedosDatabaseDriverType.MeteorMongo || trigger.when === 'beforeFind' || trigger.when === 'afterFind' || trigger.when === 'afterFindOne' || trigger.when === 'afterCount' || trigger.when === 'beforeAggregate' || trigger.when === 'afterAggregate') {
331
- if (!trigger.todo) {
332
- return;
333
- }
334
- if (!this._triggersQueue[trigger.when]) {
335
- this._triggersQueue[trigger.when] = {}
336
- }
337
- this._triggersQueue[trigger.when][trigger.name] = trigger
338
- }
339
- }
340
-
341
- unregisterTrigger(trigger: SteedosTriggerType) {
342
- delete this._triggersQueue[trigger.when][trigger.name]
343
- }
344
-
345
- private async runTirgger(trigger: SteedosTriggerType, context: SteedosTriggerContextConfig) {
346
- let object_name = this.name
347
- let event = trigger.todo
348
- let todoWrapper = async function (...args) {
349
- // Object.setPrototypeOf(thisArg, Object.getPrototypeOf(trigger))
350
- return await event.apply(thisArg, args)
351
- }
352
- let thisArg = {
353
- ...context,
354
- object_name: object_name,
355
- datasource_name: this._datasource.name,
356
- getObject: (object_name: string) => {
357
- return this._schema.getObject(object_name)
358
- }
359
- }
360
-
361
- return await todoWrapper.call(thisArg)
362
- }
363
-
364
- async runTriggers(when: string, context: SteedosTriggerContextConfig) {
365
- let triggers = this._triggersQueue[when]
366
- if (triggers) {
367
- let triggerKeys = _.keys(triggers)
368
-
369
- for (let index = 0; index < triggerKeys.length; index++) {
370
- let trigger = triggers[triggerKeys[index]];
371
- await this.runTirgger(trigger, context)
372
- }
373
- }
374
-
375
- // 获取通配的trigger,如果有则生成SteedosTriggerType执行
376
- let wildcardListeners = getPatternListeners(this.name);
377
- if (wildcardListeners) {
378
- for (const key in wildcardListeners) {
379
- if (Object.prototype.hasOwnProperty.call(wildcardListeners, key)) {
380
- const listener = wildcardListeners[key];
381
- if (listener && listener[when]) {
382
- let triggerConfig: SteedosTriggerTypeConfig = {
383
- name: `${key}_${when}`,
384
- on: 'server',
385
- when: when,
386
- todo: listener[when],
387
- }
388
- let trigger = new SteedosTriggerType(triggerConfig)
389
- await this.runTirgger(trigger, context)
390
- }
391
- }
392
- }
393
- }
394
-
395
- }
396
-
397
- getTriggerActions(when: string){
398
-
399
- const triggers = [];
400
-
401
- const cache = getCacher('action-triggers');
402
- const triggerActions = cache.get('triggerActions');
403
-
404
- if(!_.isEmpty(triggerActions)){
405
- _.map(triggerActions, (item)=>{
406
- if(item && item.metadata){
407
- const { metadata } = item
408
- if(metadata.isPattern){
409
- try {
410
- if(metadata.listenTo === '*'){
411
- triggers.push(item);
412
- }else if(_.isArray(metadata.listenTo) && _.include(metadata.listenTo, this.name)){
413
- triggers.push(item);
414
- }else if(_.isRegExp(metadata.listenTo) && metadata.listenTo.test(this.name)){
415
- triggers.push(item);
416
- }else if(_.isString(metadata.listenTo) && metadata.listenTo.startsWith("/")){
417
- try {
418
- if(_.isRegExp(eval(metadata.listenTo)) && eval(metadata.listenTo).test(this.name)){
419
- triggers.push(item);
420
- }
421
- } catch (error) {
422
- }
423
- }
424
- } catch (error) {
425
- console.log(`error`, error);
426
- }
427
- }else{
428
- if(metadata.when === when && metadata.listenTo === this.name){
429
- triggers.push(item);
430
- }
431
- }
432
-
433
- }
434
- })
435
- }
436
-
437
- return triggers;
438
- }
439
-
440
- async runTriggerActions(when: string, context: SteedosTriggerContextConfig) {
441
- let triggers = this.getTriggerActions(when);
442
- if (_.isEmpty(triggers)) {
443
- return;
444
- }
445
-
446
- for (const trigger of triggers) {
447
- let params = generateActionParams(when, context); //参考sf
448
- await this._schema.metadataBroker.call(`${trigger.service.name}.${trigger.metadata.action}`, params).catch((error)=>{
449
- //如果action trigger 下线,则只打印error
450
- if(error && _.isObject(error) && error.type === 'SERVICE_NOT_AVAILABLE'){
451
- console.error(`runTriggerActions error`, error)
452
- }else{
453
- throw error
454
- }
455
- })
456
- }
457
-
458
- }
459
-
460
- toConfig() {
461
- let config: JsonMap = {
462
- name: this.name,
463
- fields: {}
464
- }
465
-
466
- _.each(properties, (property) => {
467
- if (this[property] != null && this[property] != undefined) {
468
- config[property] = this[property]
469
- }
470
- })
471
-
472
- if (this.fields) {
473
- config.fields = {}
474
- _.each(this.fields, (field: SteedosFieldType, key: string) => {
475
- config.fields[key] = field.toConfig();
476
- })
477
- }
478
-
479
- if (this.list_views) {
480
- config.list_views = {}
481
- _.each(this.list_views, (list_view: SteedosObjectListViewType, key: string) => {
482
- config.list_views[key] = list_view.toConfig()
483
- })
484
- }
485
-
486
- if (this.actions) {
487
- config.actions = {}
488
- _.each(this.actions, (action: SteedosActionType, key: string) => {
489
- config.actions[key] = action.toConfig()
490
- })
491
- }
492
-
493
- if (this.triggers) {
494
- config.triggers = {}
495
- _.each(this.triggers, (trigger: SteedosTriggerType, key: string) => {
496
- config.triggers[key] = trigger.toConfig();
497
- })
498
- }
499
-
500
- let rolePermission = this.getObjectRolesPermission()
501
- if (rolePermission) {
502
- config.permission_set = {}
503
- _.each(rolePermission, (v, k) => {
504
- config.permission_set[k] = v
505
- })
506
- }
507
-
508
- config.datasource = this.datasource.name;
509
-
510
- return config
511
- }
512
-
513
- setField(field_name: string, fieldConfig: SteedosFieldTypeConfig) {
514
- let field = new SteedosFieldType(field_name, this, fieldConfig)
515
- this.fields[field_name] = field
516
-
517
- if (field.primary && this._datasource.driver != SteedosDatabaseDriverType.Mongo && this._datasource.driver != SteedosDatabaseDriverType.MeteorMongo) {
518
- this._idFieldName = field.name
519
- if (this._idFieldNames.indexOf(field.name) < 0) {
520
- this._idFieldNames.push(field.name);
521
- }
522
- }
523
-
524
- if (field.is_name) {
525
- this._NAME_FIELD_KEY = field_name
526
- } else if (field_name == 'name' && !this._NAME_FIELD_KEY) {
527
- this._NAME_FIELD_KEY = field_name
528
- }
529
- }
530
-
531
- getField(field_name: string) {
532
- return this.fields[field_name]
533
- }
534
-
535
- getFields(){
536
- return this.toConfig().fields
537
- }
538
-
539
- getNameFieldKey(){
540
- return this.NAME_FIELD_KEY;
541
- }
542
-
543
- async getDetailPaths(){
544
- return await this.callMetadataObjectServiceAction(`getDetailPaths`, {objectApiName: this.name});
545
- }
546
-
547
- async getMasterPaths(){
548
- return await this.callMetadataObjectServiceAction(`getMasterPaths`, {objectApiName: this.name});
549
- }
550
-
551
- async getMaxDetailsLeave(paths?){
552
- return await this.callMetadataObjectServiceAction(`getMaxDetailsLeave`, {objectApiName: this.name, paths});
553
- }
554
-
555
- async getMaxMastersLeave(paths?){
556
- return await this.callMetadataObjectServiceAction(`getMaxMastersLeave`, {objectApiName: this.name, paths});
557
- }
558
-
559
- addMaster(object_name: string) {
560
- let index = this._masters.indexOf(object_name);
561
- if (index < 0) {
562
- this._masters.push(object_name);
563
- return true;
564
- }
565
- return false;
566
- }
567
-
568
- removeMaster(object_name: string) {
569
- let index = this._masters.indexOf(object_name);
570
- if (index >= 0) {
571
- this._masters.splice(index, 1);
572
- }
573
- }
574
-
575
- addDetail(object_name: string) {
576
- let index = this._details.indexOf(object_name);
577
- if (index < 0) {
578
- this._details.push(object_name);
579
- return true;
580
- }
581
- return false;
582
- }
583
-
584
- removeDetail(object_name: string) {
585
- let index = this._details.indexOf(object_name);
586
- if (index >= 0) {
587
- this._details.splice(index, 1);
588
- }
589
- }
590
-
591
- setListView(list_view_name: string, config: SteedosObjectListViewTypeConfig) {
592
- this.list_views[list_view_name] = new SteedosObjectListViewType(list_view_name, this, config)
593
- }
594
-
595
- setAction(action_name: string, actionConfig: SteedosActionTypeConfig) {
596
- this._actions[action_name] = new SteedosActionType(action_name, this, actionConfig)
597
- }
598
-
599
- getAction(action_name: string) {
600
- return this._actions[action_name]
601
- }
602
-
603
- async refreshIndexes(){
604
- if(this.datasource.driver === SteedosDatabaseDriverType.Mongo || this.datasource.driver === SteedosDatabaseDriverType.MeteorMongo){
605
- const adapter = this.datasource.adapter;
606
- await adapter.connect()
607
- let collection = (adapter as any).collection(this.name);
608
- if (this.datasource.driver === SteedosDatabaseDriverType.MeteorMongo) {
609
- let defaultAdapter = getDataSource('default').adapter
610
- await defaultAdapter.connect();
611
- collection = (defaultAdapter as any).collection(this.name);
612
- }
613
- const indexesInfo = [];
614
- const dropIndexNames = [];
615
- for (const key in this.fields) {
616
- const field = this.fields[key];
617
- const info = field.getIndexInfo();
618
- if(info){
619
- indexesInfo.push(info);
620
- }else{
621
- dropIndexNames.push(field.getIndexName());
622
- }
623
- }
624
- if(indexesInfo && indexesInfo.length > 0){
625
- try {
626
- for await (const indexInfo of indexesInfo) {
627
- const key = indexInfo.key;
628
- delete indexInfo.key;
629
- try {
630
- await collection.createIndex(key, indexInfo)
631
- } catch (error) {
632
- // DO NOTHING
633
- }
634
- }
635
- // await collection.createIndexes(indexesInfo)
636
- } catch (error) {
637
- console.error(error)
638
- }
639
- }
640
- // if(dropIndexNames && dropIndexNames.length > 0){
641
- // try {
642
- // for await (const indexName of dropIndexNames) {
643
- // try {
644
- // await collection.dropIndex(indexName)
645
- // } catch (error) {
646
-
647
- // }
648
- // }
649
-
650
- // } catch (error) {
651
- // console.error(error)
652
- // }
653
- // }
654
- }
655
- }
656
-
657
- //TODO 处理对象继承
658
- extend_TODO(config: SteedosObjectTypeConfig) {
659
- if (this.name != config.name)
660
- throw new Error("You can not extend on different object");
661
-
662
- // override each fields
663
- _.each(config.fields, (field, field_name) => {
664
- this.setField(field_name, field)
665
- })
666
-
667
- // override each actions
668
- // if (config.actions) {
669
- // _.each(config.actions, (action) => {
670
- // this.actions[action.name] = action
671
- // })
672
- // }
673
-
674
- // override each triggers
675
- // if (config.triggers) {
676
- // _.each(config.triggers, (trigger) => {
677
- // this.triggers[trigger.name] = trigger
678
- // })
679
- // }
680
- }
681
-
682
- getObjectRolesPermission(spaceId?: string) {
683
- let globalPermission = this._datasource.getObjectRolesPermission(this._name)
684
- if (spaceId) {
685
- let permission = this._datasource.getObjectSpaceRolesPermission(this._name, spaceId);
686
- if (!_.isEmpty(permission)) {
687
- return Object.assign({}, globalPermission || {}, permission);
688
- }
689
- }
690
- return globalPermission
691
- }
692
-
693
-
694
- /**
695
- * @description:
696
- * @param {SteedosUserSession} userSession
697
- * @param {any} rolesFieldsPermission: 如果为false, 则不计算字段集权限,提交计算效率.
698
- * @return {*}
699
- */
700
- async getUserObjectPermission(userSession: SteedosUserSession, rolesFieldsPermission?: any) {
701
-
702
- if (!userSession) {
703
- throw new Error('userSession is required')
704
- }
705
-
706
- let roles = userSession.roles
707
- let objectRolesPermission = this.getObjectRolesPermission(userSession.spaceId)
708
-
709
- let userObjectPermission = {
710
- allowRead: false,
711
- allowCreate: false,
712
- allowEdit: false,
713
- allowDelete: false,
714
- viewAllRecords: false,
715
- modifyAllRecords: false,
716
- viewCompanyRecords: false,
717
- modifyCompanyRecords: false,
718
- allowReadFiles: null,
719
- viewAllFiles: null,
720
- allowCreateFiles: null,
721
- allowEditFiles: null,
722
- allowDeleteFiles: null,
723
- modifyAllFiles: null,
724
- disabled_list_views: null,
725
- disabled_actions: null,
726
- unreadable_fields: null,
727
- uneditable_fields: null,
728
- unrelated_objects: null,
729
- field_permissions: null,
730
- viewAssignCompanysRecords: [],
731
- modifyAssignCompanysRecords: [],
732
- // read_filters: [],
733
- // edit_filters: []
734
- }
735
-
736
- if (_.isEmpty(roles)) {
737
- throw new Error('not find user permission');
738
- }
739
-
740
- if(rolesFieldsPermission === false){
741
- rolesFieldsPermission = {};
742
- }else{
743
- if (!rolesFieldsPermission) {
744
- rolesFieldsPermission = await FieldPermission.getObjectFieldsPermissionGroupRole(this.name);
745
- }
746
- }
747
-
748
- roles.forEach((role) => {
749
- let rolePermission = objectRolesPermission[role];
750
- if (rolePermission) {
751
- let roleFieldsPermission = rolesFieldsPermission[role];
752
- _.each(userObjectPermission, (v, k) => {
753
- let _v = rolePermission[k];
754
- if (k === 'field_permissions') {
755
- _v = roleFieldsPermission
756
- }
757
- if (_.isBoolean(v)) {
758
- if (v === false && _v === true) {
759
- userObjectPermission[k] = _v
760
- }
761
- } else if (['allowReadFiles','viewAllFiles','allowCreateFiles','allowEditFiles','allowDeleteFiles','modifyAllFiles'].indexOf(k) > -1){
762
- if(_.isBoolean(_v)){
763
- userObjectPermission[k] = _v
764
- }
765
- } else if (['read_filters', 'edit_filters'].indexOf(k) > -1) {
766
- if ('edit_filters' === k) {
767
- if (!_.isEmpty(_v)) {
768
- userObjectPermission['read_filters'].push(_v);
769
- }
770
- }
771
- if (!_.isEmpty(_v)) {
772
- userObjectPermission[k].push(_v);
773
- }
774
- } else if (['viewAssignCompanysRecords', 'modifyAssignCompanysRecords'].indexOf(k) > -1) {
775
- if ('modifyAssignCompanysRecords' === k) {
776
- if (!_.isEmpty(_v) && _.isArray(_v)) {
777
- userObjectPermission['viewAssignCompanysRecords'].push(..._v);
778
- }
779
- }
780
- if (!_.isEmpty(_v) && _.isArray(_v)) {
781
- userObjectPermission[k].push(..._v);
782
- }
783
- }
784
- else if ((_.isArray(v) || _.isNull(v))) {
785
- if (!_.isArray(_v)) {
786
- _v = []
787
- }
788
- if (_.isNull(v)) {
789
- userObjectPermission[k] = _v
790
- } else {
791
- if (k === 'field_permissions') {
792
- userObjectPermission[k] = _.union(v, _v)
793
- } else {
794
- userObjectPermission[k] = _.intersection(v, _v)
795
- }
796
- }
797
- }
798
- })
799
- }
800
- });
801
-
802
- const field_permissions = {};
803
- if (userObjectPermission.field_permissions) {
804
- _.each(userObjectPermission.field_permissions, (field_permission) => {
805
- const { field, read, edit } = field_permission;
806
- if (field_permissions[field]) {
807
- field_permissions[field].edit = field_permissions[field].edit || edit;
808
- if (field_permissions[field].edit) {
809
- field_permissions[field].read = true
810
- } else {
811
- field_permissions[field].read = field_permissions[field].read || read;
812
- }
813
- } else {
814
- field_permissions[field] = {
815
- field: field,
816
- read: edit || read,
817
- edit: edit
818
- }
819
- }
820
- })
821
- }
822
-
823
- userObjectPermission.field_permissions = field_permissions;
824
-
825
- userObjectPermission.disabled_list_views = userObjectPermission.disabled_list_views || []
826
- userObjectPermission.disabled_actions = userObjectPermission.disabled_actions || []
827
- userObjectPermission.unreadable_fields = userObjectPermission.unreadable_fields || []
828
- userObjectPermission.uneditable_fields = userObjectPermission.uneditable_fields || []
829
- userObjectPermission.unrelated_objects = userObjectPermission.unrelated_objects || []
830
-
831
- let spaceId = userSession.spaceId
832
- if (isTemplateSpace(spaceId)) {
833
- return Object.assign({}, userObjectPermission, { allowRead: true, viewAllRecords: true, viewCompanyRecords: true })
834
- }
835
-
836
- return userObjectPermission;
837
- }
838
-
839
- async allowRead(userSession: SteedosUserSession) {
840
- if (!userSession)
841
- return true
842
- let userObjectPermission = await this.getUserObjectPermission(userSession, false)
843
- if (userObjectPermission.allowRead) {
844
- return true
845
- } else {
846
- return false
847
- }
848
- }
849
-
850
- async allowInsert(userSession: SteedosUserSession) {
851
- if (!userSession)
852
- return true
853
- let userObjectPermission = await this.getUserObjectPermission(userSession, false)
854
- if (userObjectPermission.allowCreate) {
855
- return true
856
- } else {
857
- return false
858
- }
859
- }
860
-
861
- async allowUpdate(userSession: SteedosUserSession) {
862
- if (!userSession)
863
- return true
864
- let userObjectPermission = await this.getUserObjectPermission(userSession, false)
865
- if (userObjectPermission.allowEdit) {
866
- return true
867
- } else {
868
- return false
869
- }
870
- }
871
-
872
- async allowDelete(userSession: SteedosUserSession) {
873
- if (!userSession)
874
- return true
875
- let userObjectPermission = await this.getUserObjectPermission(userSession, false)
876
- if (userObjectPermission.allowDelete) {
877
- return true
878
- } else {
879
- return false
880
- }
881
- }
882
-
883
- async find(query: SteedosQueryOptions, userSession?: SteedosUserSession) {
884
- let clonedQuery = Object.assign({}, query);
885
- if(userSession)
886
- await this.processUnreadableField(userSession, clonedQuery);
887
- return await this.callAdapter('find', this.table_name, clonedQuery, userSession)
888
- }
889
-
890
- // 此函数支持driver: MeteorMongo
891
- async aggregate(query: SteedosQueryOptions, externalPipeline, userSession?: SteedosUserSession) {
892
- let clonedQuery = Object.assign({}, query);
893
- if(userSession)
894
- await this.processUnreadableField(userSession, clonedQuery);
895
- return await this.callAdapter('aggregate', this.table_name, clonedQuery, externalPipeline, userSession)
896
- }
897
-
898
- // 此函数支持driver: MeteorMongo
899
- async directAggregate(query: SteedosQueryOptions, externalPipeline: any[], userSession?: SteedosUserSession) {
900
- let clonedQuery = Object.assign({}, query);
901
- if(userSession)
902
- await this.processUnreadableField(userSession, clonedQuery);
903
- return await this.callAdapter('directAggregate', this.table_name, clonedQuery, externalPipeline, userSession)
904
- }
905
-
906
- // 此函数支持driver: MeteorMongo,类似于aggregate,其参数externalPipeline放在最前面而已
907
- async directAggregatePrefixalPipeline(query: SteedosQueryOptions, prefixalPipeline: any[], userSession?: SteedosUserSession) {
908
- let clonedQuery = Object.assign({}, query);
909
- if(userSession)
910
- await this.processUnreadableField(userSession, clonedQuery);
911
- return await this.callAdapter('directAggregatePrefixalPipeline', this.table_name, clonedQuery, prefixalPipeline, userSession)
912
- }
913
-
914
- async findOne(id: SteedosIDType, query: SteedosQueryOptions, userSession?: SteedosUserSession) {
915
- let clonedQuery = Object.assign({}, query);
916
- if(userSession)
917
- await this.processUnreadableField(userSession, clonedQuery);
918
- const result = await this.callAdapter('findOne', this.table_name, id, clonedQuery, userSession);
919
- return result
920
- }
921
-
922
- async insert(doc: Dictionary<any>, userSession?: SteedosUserSession) {
923
- doc = this.formatRecord(doc);
924
- return await this.callAdapter('insert', this.table_name, doc, userSession)
925
- }
926
-
927
- async update(id: SteedosIDType, doc: Dictionary<any>, userSession?: SteedosUserSession) {
928
- doc = this.formatRecord(doc);
929
- // await this.processUneditableFields(userSession, doc)
930
- let clonedId = id;
931
- return await this.callAdapter('update', this.table_name, clonedId, doc, userSession)
932
- }
933
-
934
- async updateOne(id: SteedosIDType, doc: Dictionary<any>, userSession?: SteedosUserSession) {
935
- doc = this.formatRecord(doc);
936
- // await this.processUneditableFields(userSession, doc)
937
- let clonedId = id;
938
- return await this.callAdapter('updateOne', this.table_name, clonedId, doc, userSession)
939
- }
940
- // 此函数支持driver: MeteorMongo、Mongo
941
- async updateMany(queryFilters: SteedosQueryFilters, doc: Dictionary<any>, userSession?: SteedosUserSession) {
942
- doc = this.formatRecord(doc);
943
- // await this.processUneditableFields(userSession, doc)
944
- let clonedQueryFilters = queryFilters;
945
- return await this.callAdapter('updateMany', this.table_name, clonedQueryFilters, doc, userSession)
946
- }
947
-
948
- async delete(id: SteedosIDType, userSession?: SteedosUserSession) {
949
- let clonedId = id;
950
- return await this.callAdapter('delete', this.table_name, clonedId, userSession)
951
- }
952
-
953
- async directFind(query: SteedosQueryOptions, userSession?: SteedosUserSession) {
954
- let clonedQuery = Object.assign({}, query);
955
- await this.processUnreadableField(userSession, clonedQuery);
956
- return await this.callAdapter('directFind', this.table_name, clonedQuery, userSession)
957
- }
958
-
959
- async directInsert(doc: Dictionary<any>, userSession?: SteedosUserSession) {
960
- doc = this.formatRecord(doc);
961
- return await this.callAdapter('directInsert', this.table_name, doc, userSession)
962
- }
963
-
964
- async directUpdate(id: SteedosIDType, doc: Dictionary<any>, userSession?: SteedosUserSession) {
965
- doc = this.formatRecord(doc);
966
- // await this.processUneditableFields(userSession, doc)
967
- let clonedId = id;
968
- return await this.callAdapter('directUpdate', this.table_name, clonedId, doc, userSession)
969
- }
970
-
971
- async directDelete(id: SteedosIDType, userSession?: SteedosUserSession) {
972
- let clonedId = id;
973
- return await this.callAdapter('directDelete', this.table_name, clonedId, userSession)
974
- }
975
-
976
- async _makeNewID(){
977
- return await this._datasource._makeNewID(this.table_name);
978
- }
979
-
980
- async getFirstListView(){
981
- return this.list_views[0];
982
- }
983
-
984
- async getAbsoluteUrl(app_id, record_id?){
985
- const object_name = this.name;
986
- const list_view:any = await this.getFirstListView();
987
- const list_view_id = list_view ? list_view._id || list_view.name : 'all'
988
- if(record_id)
989
- return absoluteUrl("/app/" + app_id + "/" + object_name + "/view/" + record_id)
990
- else{
991
- if(object_name === 'meeting'){
992
- return absoluteUrl("/app/" + app_id + "/" + object_name + "/calendar/")
993
- }else{
994
- return absoluteUrl("/app/" + app_id + "/" + object_name + "/grid/" + list_view_id)
995
- }
996
- }
997
- }
998
-
999
- async getRecordAbsoluteUrl(app_id, record_id){
1000
- return await this.getAbsoluteUrl(app_id, record_id)
1001
- }
1002
-
1003
- async getGridAbsoluteUrl(app_id){
1004
- return await this.getAbsoluteUrl(app_id)
1005
- }
1006
-
1007
- async isEnableAudit(){
1008
- return this.enable_audit;
1009
- }
1010
-
1011
- async getDetails(){
1012
- return await this.callMetadataObjectServiceAction(`getDetails`, {objectApiName: this.name});
1013
- }
1014
-
1015
- async getMasters(){
1016
- return await this.callMetadataObjectServiceAction(`getMasters`, {objectApiName: this.name});
1017
- }
1018
-
1019
- async getLookupDetails(){
1020
- return await this.callMetadataObjectServiceAction(`getLookupDetails`, {objectApiName: this.name});
1021
- }
1022
-
1023
- async getDetailsInfo(){
1024
- return await this.callMetadataObjectServiceAction(`getDetailsInfo`, {objectApiName: this.name});
1025
- }
1026
-
1027
- async getMastersInfo(){
1028
- return await this.callMetadataObjectServiceAction(`getMastersInfo`, {objectApiName: this.name});
1029
- }
1030
-
1031
- async getLookupDetailsInfo(){
1032
- return await this.callMetadataObjectServiceAction(`getLookupDetailsInfo`, {objectApiName: this.name});
1033
- }
1034
-
1035
- /**
1036
- * 此函数返回getDetailsInfo、getMastersInfo、getLookupDetailsInfo 3个请求的结果,用于优化访问速度
1037
- */
1038
- async getRelationsInfo() {
1039
- return await this.callMetadataObjectServiceAction(`getRelationsInfo`, { objectApiName: this.name });
1040
- }
1041
-
1042
- async getRecordPermissions(record, userSession){
1043
- const permissions = await this.getUserObjectPermission(userSession);
1044
- const { userId, company_ids: user_company_ids } = userSession;
1045
- if(record){
1046
- if(record.record_permissions){
1047
- return record.record_permissions
1048
- }
1049
- let recordOwnerId = record.owner;
1050
- if(_.isObject(recordOwnerId)){
1051
- recordOwnerId = recordOwnerId._id;
1052
- }
1053
- const isOwner = recordOwnerId == userId;
1054
- let record_company_id = record.company_id;
1055
- if(record_company_id && _.isObject(record_company_id) && record_company_id._id){
1056
- record_company_id = record_company_id._id;
1057
- }
1058
- let record_company_ids = record.company_ids;
1059
- if(record_company_ids && record_company_ids.length && _.isObject(record_company_ids[0])){
1060
- record_company_ids = record_company_ids.map((n)=> n._id)
1061
- }
1062
- record_company_ids = _.union(record_company_ids, [record_company_id]);
1063
- record_company_ids = _.compact(record_company_ids);
1064
- if(!permissions.modifyAllRecords && !isOwner && !permissions.modifyCompanyRecords){
1065
- permissions.allowEdit = false
1066
- permissions.allowDelete = false
1067
- }else if(!permissions.modifyAllRecords && permissions.modifyCompanyRecords){
1068
- if(record_company_ids && record_company_ids.length){
1069
- if(user_company_ids && user_company_ids.length){
1070
- if(!_.intersection(user_company_ids, record_company_ids).length){
1071
- permissions.allowEdit = false
1072
- permissions.allowDelete = false
1073
- }
1074
- }else{
1075
- permissions.allowEdit = false
1076
- permissions.allowDelete = false
1077
- }
1078
- }
1079
- }
1080
- if(record.locked && !permissions.modifyAllRecords){
1081
- permissions.allowEdit = false
1082
- permissions.allowDelete = false
1083
- }
1084
- if(!permissions.viewAllRecords && !isOwner && !permissions.viewCompanyRecords){
1085
- permissions.allowRead = false
1086
- }else if(!permissions.viewAllRecords && permissions.viewCompanyRecords){
1087
- if(record_company_ids && record_company_ids.length){
1088
- if(user_company_ids && user_company_ids.length){
1089
- if(!_.intersection(user_company_ids, record_company_ids).length){
1090
- permissions.allowRead = false
1091
- }
1092
- }else{
1093
- permissions.allowRead = false
1094
- }
1095
- }
1096
- }
1097
- }
1098
- return permissions
1099
- }
1100
-
1101
- /**
1102
- * 获取用户可访问字段
1103
- * 字段权限设计: https://github.com/steedos/steedos-platform/issues/2943
1104
- * 字段配置为必填字段:
1105
- * 1 字段级权限不能设置为只读。
1106
- * 2 页面布局中不能修改必填选项,始终必填。
1107
- * 3 页面布局中不能设置为只读。
1108
- * 4 字段如果不在页面布局中, 则显示在最后
1109
- * @param objectFields
1110
- * @param objectLayout
1111
- * @param objectPermission
1112
- */
1113
- getAccessFields(objectFields, objectLayout, objectPermission){
1114
- const accessFields = {};
1115
- const universallyRequiredFields = _.filter(objectFields, (objectFile)=>{
1116
- return _.isBoolean(objectFile.required) && objectFile.required;
1117
- });
1118
-
1119
- const universallyRequiredFieldsName = _.pluck(universallyRequiredFields, 'name');
1120
-
1121
- _.each(objectFields, (field)=>{
1122
- if(field){
1123
- const fieldPermission = objectPermission.field_permissions[field.name];
1124
-
1125
- let fieldLayout = objectLayout && objectLayout.fields ? _.find(objectLayout.fields, (item)=>{return item.field_name == field.name}) : null;
1126
-
1127
- const isUniversallyRequiredField = _.contains(universallyRequiredFieldsName, field.name);
1128
-
1129
- if(isUniversallyRequiredField){
1130
- fieldLayout = Object.assign({}, fieldLayout, {
1131
- field_name: field.name,
1132
- is_required: true,
1133
- is_readonly: false,
1134
- })
1135
- }
1136
-
1137
- // 如果配置了页面布局且没有授权字段时, 不显示此字段
1138
- if(objectLayout && !fieldLayout){
1139
- return ;
1140
- }
1141
-
1142
- let {read, edit} = fieldPermission || {read: !field.hidden, edit: !field.hidden && !field.readonly};
1143
-
1144
- // 通用必填字段始终可见、可编辑
1145
- if(isUniversallyRequiredField){
1146
- read = true;
1147
- edit = true;
1148
- }
1149
-
1150
- if(fieldLayout && fieldLayout.is_readonly){
1151
- edit = false;
1152
- }
1153
-
1154
- //不可查看: 配置了字段权限且不可查看; 没有配置字段权限,字段的hidden为true
1155
- if(read === false){
1156
- return;
1157
- }
1158
-
1159
- //可查看不可编辑: 配置了字段权限可查看不可编辑; 没有配置字段权限 字段的hidden 为false 且字段的readonly为true
1160
- if(read === true && edit === false){
1161
- accessFields[field.name] = Object.assign({}, field, {
1162
- hidden: false,
1163
- required: false,
1164
- readonly: true,
1165
- disabled: true
1166
- })
1167
- return;
1168
- }
1169
-
1170
- //可查看可编辑: 配置了字段权限可查看可编辑; 没有配置字段权限 字段的hidden 为false 且字段的readonly为false
1171
- if(read === true && edit === true){
1172
- accessFields[field.name] = Object.assign({}, field, {
1173
- hidden: false,
1174
- readonly: false,
1175
- disabled: false,
1176
- required: _.isString(field.required) ? field.required : (fieldLayout ? fieldLayout.is_required : false),
1177
- })
1178
- return;
1179
- }
1180
- console.error('字段权限处理异常', field, read, edit);
1181
- }
1182
- });
1183
-
1184
- if(objectLayout){
1185
- let sort_no = 1;
1186
- _.each(objectLayout.fields, function(_item){
1187
- if(accessFields[_item.field_name]){
1188
- if(_.has(_item, 'group')){
1189
- accessFields[_item.field_name].group = _item.group
1190
- }
1191
-
1192
- if(_item.visible_on){
1193
- accessFields[_item.field_name].visible_on = _item.visible_on
1194
- }
1195
-
1196
- accessFields[_item.field_name].sort_no = sort_no;
1197
- sort_no++;
1198
- }
1199
- })
1200
-
1201
- //处理通用必填字段默认显示顺序
1202
- _.each(universallyRequiredFieldsName, function(fieldName){
1203
- const fieldLayout = _.find(objectLayout.fields, (item)=>{return item.field_name == fieldName});
1204
- if(!fieldLayout){
1205
- accessFields[fieldName].sort_no = sort_no;
1206
- sort_no++;
1207
- }
1208
- })
1209
- }
1210
-
1211
- return accessFields;
1212
- }
1213
-
1214
- async getRecordView(userSession, context: any = {}) {
1215
- let { objectConfig, layouts, spaceProcessDefinition, dbListViews, rolesFieldsPermission, relationsInfo} = context;
1216
- const lng = userSession.language;
1217
- if (!objectConfig) {
1218
- const objectMetadataConfig: any = await this.callMetadataObjectServiceAction('get', { objectApiName: this.name });
1219
- objectConfig = objectMetadataConfig.metadata;
1220
- }
1221
- objectConfig.name = this.name
1222
- objectConfig.datasource = this.datasource.name;
1223
- objectConfig.permissions = await this.getUserObjectPermission(userSession, rolesFieldsPermission);
1224
- if(!relationsInfo){
1225
- relationsInfo = await this.getRelationsInfo();
1226
- }
1227
- objectConfig.details = relationsInfo.details;
1228
- objectConfig.masters = relationsInfo.masters;
1229
- objectConfig.lookup_details = relationsInfo.lookup_details;
1230
- delete objectConfig.db
1231
- translationObject(lng, objectConfig.name, objectConfig, true);
1232
- if (!layouts) {
1233
- layouts = await getObjectLayouts(userSession.profile, userSession.spaceId, this.name);
1234
- }
1235
-
1236
- let objectLayout = null
1237
- if(layouts && layouts.length > 0){
1238
- objectLayout = layouts[0];
1239
- _.each(objectLayout.buttons, function(button){
1240
- const action = objectConfig.actions[button.button_name];
1241
- if(action){
1242
- if(button.visible_on){
1243
- action._visible = button.visible_on;
1244
- }
1245
- }
1246
- })
1247
-
1248
- const layoutButtonsName = _.pluck(objectLayout.buttons,'button_name');
1249
- _.each(objectConfig.actions, function(action){
1250
- if(!_.include(layoutButtonsName, action.name)){
1251
- action.visible = false
1252
- action._visible = function(){return false}.toString()
1253
- }
1254
- })
1255
- objectConfig.related_lists = objectLayout.related_lists || []
1256
- _.each(objectConfig.related_lists, (related_list)=>{
1257
- if(related_list.sort_field_name && _.isArray(related_list.sort_field_name) && related_list.sort_field_name.length > 0){
1258
- related_list.sort = [];
1259
- _.each(related_list.sort_field_name, (fName)=>{
1260
- related_list.sort.push({field_name: fName, order: related_list.sort_order || 'asc'})
1261
- })
1262
- }
1263
- })
1264
- }
1265
- objectConfig.fields = this.getAccessFields(objectConfig.fields, objectLayout, objectConfig.permissions)
1266
- // TODO object layout 是否需要控制审批记录显示?
1267
- if (!spaceProcessDefinition) {
1268
- spaceProcessDefinition = await getObject("process_definition").directFind({ filters: [['space', '=', userSession.spaceId], ['object_name', '=', this.name], ['active', '=', true]] })
1269
- }
1270
- if (spaceProcessDefinition.length > 0) {
1271
- objectConfig.enable_process = true
1272
- }
1273
- //清理数据
1274
- _.each(objectConfig.triggers, function(trigger, key){
1275
- if(trigger?.on != 'client'){
1276
- delete objectConfig.triggers[key];
1277
- }
1278
- })
1279
- if (!dbListViews) {
1280
- dbListViews = await getObject("object_listviews").directFind({ filters: [['space', '=', userSession.spaceId], ['object_name', '=', this.name], [['owner', '=', userSession.userId], 'or', ['shared', '=', true]]] })
1281
- }
1282
- objectConfig.list_views = Object.assign({}, objectConfig.list_views)
1283
- _.each(dbListViews, function(dbListView){
1284
- delete dbListView.created;
1285
- delete dbListView.created_by;
1286
- delete dbListView.modified;
1287
- delete dbListView.modified_by;
1288
- objectConfig.list_views[dbListView.name] = dbListView;
1289
- })
1290
- delete objectConfig.listeners
1291
- delete objectConfig.__filename
1292
- delete objectConfig.extend
1293
- return objectConfig;
1294
- }
1295
-
1296
- async getDefaultRecordView(userSession){
1297
- const object_name = this.name;
1298
- const type = 'record';
1299
- const buttons = [];
1300
- const fields = [];
1301
- const related_lists = [];
1302
-
1303
- const objectConfig: any = await this.callMetadataObjectServiceAction('getOriginalObject', {objectApiName: this.name});
1304
- let sortedFields = [];
1305
- forEach(objectConfig.fields, (fieldItem, key)=>{
1306
- sortedFields.push(Object.assign({}, {name: key}, fieldItem));
1307
- });
1308
- sortedFields = sortBy(sortedFields, function(o) { return o.sort_no; });
1309
- _.each(sortedFields, function(field, key){
1310
- const layoutField: any = {};
1311
- layoutField.field_name = field.name;
1312
- layoutField.is_readonly = field.readonly;
1313
- layoutField.is_required = field.required;
1314
- layoutField.group = field.group;
1315
- // layoutField.visible_on = `${!field.hidden}`;
1316
- fields.push(layoutField);
1317
- });
1318
-
1319
- let relatedLists = []
1320
- if(this.enable_files){
1321
- relatedLists.push("cms_files.parent")
1322
- }
1323
-
1324
- const details = await this.getDetailsInfo();
1325
- const lookup_details = await this.getLookupDetailsInfo();
1326
- relatedLists = relatedLists.concat(_.union(details, lookup_details));
1327
-
1328
- if(this.enable_tasks){
1329
- relatedLists.push("tasks.related_to")
1330
- }
1331
- if(this.enable_notes){
1332
- relatedLists.push("notes.related_to")
1333
- }
1334
- if(this.enable_events){
1335
- relatedLists.push("events.related_to")
1336
- }
1337
- if(this.enable_instances){
1338
- relatedLists.push("instances.record_ids")
1339
- }
1340
- if(this.enable_approvals){
1341
- relatedLists.push("approvals.related_to")
1342
- }
1343
- if(this.enable_process){
1344
- relatedLists.push("process_instance_history.target_object")
1345
- }
1346
- for await (const related of relatedLists) {
1347
- if(related){
1348
- const relatedItem: any = {}
1349
- relatedItem.related_field_fullname = related;
1350
- let foo = (related as any).split('.');
1351
- let rObjectName = foo[0];
1352
-
1353
- const relatedObject = await getObject(rObjectName).toConfig();
1354
- const relatedObjectAllListView = _.find(relatedObject.list_views, function(listview){
1355
- return listview.name === 'all'
1356
- })
1357
-
1358
- if(relatedObjectAllListView && relatedObjectAllListView.columns){
1359
- const fieldNames = [];
1360
- _.each(relatedObjectAllListView.columns, (column)=>{
1361
- if(_.isString(column)){
1362
- fieldNames.push(column);
1363
- }else if(_.isObject(column)){
1364
- fieldNames.push(column.field);
1365
- }
1366
- })
1367
-
1368
- relatedItem.field_names = fieldNames
1369
- }
1370
- related_lists.push(relatedItem)
1371
- }
1372
- }
1373
-
1374
- buttons.push({
1375
- button_name: 'standard_new'
1376
- })
1377
-
1378
- buttons.push({
1379
- button_name: 'standard_edit'
1380
- })
1381
-
1382
- buttons.push({
1383
- button_name: 'standard_delete'
1384
- })
1385
-
1386
- _.each(objectConfig.actions, function(action, key){
1387
- if(action.is_enable){
1388
- buttons.push({
1389
- button_name: action.name
1390
- })
1391
- }
1392
- });
1393
-
1394
- return {
1395
- object_name, type, buttons, fields, related_lists,
1396
- space: userSession.spaceId
1397
- }
1398
- }
1399
-
1400
- async createDefaultRecordView(userSession){
1401
- const name = 'default';
1402
- const label = 'Default';
1403
- const profiles = ['user'];
1404
- try {
1405
- let defaultRecordView = await this.getDefaultRecordView(userSession);
1406
- return await getObject('object_layouts').insert(Object.assign({},defaultRecordView, {name, label, profiles}), userSession)
1407
- } catch (error) {
1408
- return {error: error.message}
1409
- }
1410
- }
1411
-
1412
- async getRelateds(){
1413
- const related_objects = [];
1414
- if(this.enable_files){
1415
- related_objects.push({object_name:"cms_files", foreign_key: "parent"})
1416
- }
1417
- let detailsInfo = await this.getDetailsInfo();
1418
- let lookupsInfo = await this.getLookupDetailsInfo();
1419
- let relatedInfos = detailsInfo.concat(lookupsInfo);
1420
- for (const info of relatedInfos) {
1421
- if (!info.startsWith('__')) {
1422
- let infos = info.split('.');
1423
- let detailObjectApiName = infos[0];
1424
- let detailFieldName = infos[1];
1425
- let related_field = await getObject(detailObjectApiName).getField(detailFieldName);
1426
- if(related_field){
1427
- if((related_field.type == "master_detail" || (related_field.type == "lookup" && related_field.relatedList)) && related_field.reference_to && related_field.reference_to == this.name){
1428
- if(detailObjectApiName == "object_fields"){
1429
- related_objects.splice(0, 0, {object_name: detailObjectApiName, foreign_key: detailFieldName})
1430
- }else{
1431
- related_objects.push({object_name:detailObjectApiName, foreign_key: detailFieldName, write_requires_master_read: related_field.write_requires_master_read})
1432
- }
1433
- }
1434
- }
1435
- }
1436
- }
1437
- if(this.enable_tasks){
1438
- related_objects.push({object_name:"tasks", foreign_key: "related_to"})
1439
- }
1440
- if(this.enable_notes){
1441
- related_objects.push({object_name:"notes", foreign_key: "related_to"})
1442
- }
1443
- if(this.enable_events){
1444
- related_objects.push({object_name:"events", foreign_key: "related_to"});
1445
- }
1446
- if(this.enable_instances){
1447
- related_objects.push({object_name:"instances", foreign_key: "record_ids"})
1448
- }
1449
-
1450
- if(this.enable_approvals){
1451
- related_objects.push({object_name:"approvals", foreign_key: "related_to"})
1452
- }
1453
-
1454
- if(this.enable_process){
1455
- related_objects.push({object_name:"process_instance_history", foreign_key: "target_object"})
1456
- }
1457
- return related_objects;
1458
- }
1459
-
1460
- private isDirectCRUD(methodName: string) {
1461
- return methodName.startsWith("direct");
1462
- }
1463
-
1464
-
1465
- async count(query: SteedosQueryOptions, userSession?: SteedosUserSession) {
1466
- let clonedQuery = Object.assign({}, query);
1467
- return await this.callAdapter('count', this.table_name, clonedQuery, userSession)
1468
- }
1469
-
1470
- private async allow(method: string, userSession: SteedosUserSession) {
1471
- if (_.isNull(userSession) || _.isUndefined(userSession)) {
1472
- return true
1473
- }
1474
- if (method === 'find' || method === 'findOne' || method === 'count' || method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1475
- return await this.allowRead(userSession)
1476
- } else if (method === 'insert') {
1477
- return await this.allowInsert(userSession)
1478
- } else if (method === 'update' || method === 'updateOne' || method === 'updateMany') {
1479
- return await this.allowUpdate(userSession)
1480
- } else if (method === 'delete') {
1481
- return await this.allowDelete(userSession)
1482
- }
1483
- }
1484
-
1485
- private async runBeforeTriggers(method: string, context: SteedosTriggerContextConfig) {
1486
- if (method === 'count' || method === "findOne") {
1487
- method = 'find';
1488
- }
1489
- let meteorWhen = `before${method.charAt(0).toLocaleUpperCase()}${_.rest([...method]).join('')}`
1490
- let when = `before.${method}`;
1491
- await this.runTriggers(meteorWhen, context);
1492
- return await this.runTriggerActions(when, context)
1493
- }
1494
-
1495
- private async runAfterTriggers(method: string, context: SteedosTriggerContextConfig) {
1496
- let meteorWhen = `after${method.charAt(0).toLocaleUpperCase()}${_.rest([...method]).join('')}`
1497
- let when = `after.${method}`;
1498
- await this.runTriggers(meteorWhen, context);
1499
- return await this.runTriggerActions(when, context)
1500
- }
1501
-
1502
- private async appendRecordPermission(records, userSession) {
1503
- const _ids = _.pluck(records, '_id');
1504
- const objPm = await this.getUserObjectPermission(userSession, false);
1505
- const permissionFilters = this.getObjectEditPermissionFilters(objPm, userSession);
1506
- if (_.isEmpty(permissionFilters)) {
1507
- return;
1508
- }
1509
- const filters = formatFiltersToODataQuery(['_id', 'in', _ids])
1510
-
1511
- const results = await this.directFind({
1512
- fields: ['_id'],
1513
- filters: `(${filters}) and (${permissionFilters.join(' or ')})`
1514
- });
1515
- const allowEditIds = _.pluck(results, '_id');
1516
- _.each(records, (record) => {
1517
- if (_.include(allowEditIds, record._id)) {
1518
- record.record_permissions = {
1519
- allowRead: true,
1520
- allowEdit: true,
1521
- allowDelete: true,
1522
- }
1523
- }
1524
- })
1525
-
1526
- }
1527
-
1528
- private async getTriggerContext(when: string, method: string, args: any[], recordId?: string) {
1529
-
1530
- let userSession = args[args.length - 1]
1531
-
1532
- let context: SteedosTriggerContextConfig = { objectName: this.name, userId: userSession ? userSession.userId : undefined, spaceId: userSession ? userSession.spaceId : undefined }
1533
-
1534
- if (method === 'find' || method === 'findOne' || method === 'count') {
1535
- context.query = args[args.length - 2]
1536
- }
1537
-
1538
- if (method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1539
- context.query = args[args.length - 3]
1540
- }
1541
-
1542
- if (method === 'findOne' || method === 'update' || method === 'delete') {
1543
- context.id = args[1]
1544
- }
1545
-
1546
- if (method === 'insert' || method === 'update') {
1547
- context.doc = args[args.length - 2]
1548
- }
1549
-
1550
- if (when === 'after' && (method === 'update' || method === 'delete')) {
1551
- context.previousDoc = await this.findOne(recordId, {}, userSession)
1552
- }
1553
-
1554
- return context
1555
- }
1556
-
1557
- private async processUnreadableField(userSession: SteedosUserSession, query: SteedosQueryOptions) {
1558
- if (!userSession) {
1559
- return
1560
- }
1561
- let userObjectPermission = await this.getUserObjectPermission(userSession, false)
1562
- let userObjectUnreadableFields = userObjectPermission.unreadable_fields
1563
- if (userObjectUnreadableFields.length > 0) {
1564
- let queryFields = [];
1565
-
1566
- if (_.isArray(query.fields)) {
1567
- queryFields = query.fields
1568
- } else if (_.isString(query.fields)) {
1569
- queryFields = query.fields.split(',')
1570
- }
1571
-
1572
- if (!(query.fields && query.fields.length)) {
1573
- queryFields = _.keys(this.toConfig().fields)
1574
- _.each(queryFields, function (fieldName, index) {
1575
- if (fieldName && fieldName.indexOf("$") > -1) {
1576
- delete queryFields[index];
1577
- }
1578
- })
1579
- queryFields = _.compact(queryFields)
1580
- }
1581
- queryFields = _.difference(queryFields, userObjectUnreadableFields)
1582
-
1583
- if (queryFields.length < 1) {
1584
- queryFields.push()
1585
- }
1586
-
1587
- if (this.idFieldName) {
1588
- queryFields.unshift(this.idFieldName)
1589
- queryFields = _.compact(_.uniq(queryFields))
1590
- }
1591
-
1592
- query.fields = queryFields.join(',')
1593
- }
1594
- }
1595
-
1596
- // private async processUneditableFields(userSession: SteedosUserSession, doc: JsonMap) {
1597
- // 后台直接去掉uneditable_fields相关判断逻辑
1598
- // [签约对象同时配置了company_ids必填及uneditable_fields造成部分用户新建签约对象时报错 #192](https://github.com/steedos/steedos-project-dzug/issues/192)
1599
- // if (!userSession) {
1600
- // return
1601
- // }
1602
-
1603
- // let userObjectPermission = await this.getUserObjectPermission(userSession)
1604
- // let userObjectUneditableFields = userObjectPermission.uneditable_fields
1605
-
1606
- // let intersection = _.intersection(userObjectUneditableFields, _.keys(doc))
1607
- // if (intersection.length > 0) {
1608
- // throw new Error(`no permissions to edit fields ${intersection.join(', ')}`)
1609
- // }
1610
-
1611
- // // _.each(userObjectUneditableFields, (name: string)=>{
1612
- // // delete doc[name]
1613
- // // })
1614
- // }
1615
-
1616
- private formatRecord(doc: JsonMap) {
1617
- let adapterFormat = this._datasource["formatRecord"];
1618
- if (typeof adapterFormat == 'function') {
1619
- doc = adapterFormat.apply(this._datasource, [doc, this.toConfig()]);
1620
- }
1621
- return doc;
1622
- }
1623
-
1624
- private async callAdapter(method: string, ...args: any[]) {
1625
-
1626
- const adapterMethod = this._datasource[method];
1627
- if (typeof adapterMethod !== 'function') {
1628
- throw new Error('Adapted does not support "' + method + '" method');
1629
- }
1630
- const userSession: SteedosUserSession = args[args.length - 1];
1631
- if(!_.isEmpty(userSession)){
1632
- let allow = await this.allow(method, userSession)
1633
- if (!allow) {
1634
- throw new Error('not find permission')
1635
- }
1636
- }
1637
-
1638
- let objectName = args[0], recordId: string, doc: JsonMap;
1639
- if (["insert", "update", "updateMany", "delete"].indexOf(method) > -1) {
1640
- // 因下面的代码,比如函数dealWithMethodPermission可能改写args变量,所以需要提前从args取出对应变量值。
1641
- if (method === "insert") {
1642
- // 此处doc不带_id值,得执行完adapterMethod.apply后,doc中才有_id属性,所以这里的doc及recordId都不准确
1643
- doc = args[1];
1644
- recordId = <string>doc._id;
1645
- }
1646
- else {
1647
- recordId = args[1];
1648
- doc = args[2];
1649
- }
1650
- }
1651
-
1652
- let paramRecordId; // 用于记录原始的id参数值
1653
- if (method === 'findOne' || method === 'update' || method === 'delete') {
1654
- paramRecordId = args[1];
1655
- }
1656
-
1657
- // 判断处理工作区权限,公司级权限,owner权限
1658
- if (!_.isEmpty(userSession) && this._datasource.enable_space) {
1659
- this.dealWithFilters(method, args);
1660
- await this.dealWithMethodPermission(method, args);
1661
- }
1662
- let returnValue: any;
1663
- if (this.isDirectCRUD(method)) {
1664
- args.splice(args.length - 1, 1, userSession ? userSession.userId : undefined)
1665
- returnValue = await adapterMethod.apply(this._datasource, args);
1666
- } else {
1667
- let beforeTriggerContext = await this.getTriggerContext('before', method, args)
1668
- if (paramRecordId) {
1669
- beforeTriggerContext = Object.assign({} , beforeTriggerContext, { id: paramRecordId });
1670
- }
1671
- await this.runBeforeTriggers(method, beforeTriggerContext)
1672
- await runValidationRules(method, beforeTriggerContext, args[0], userSession)
1673
- let afterTriggerContext = await this.getTriggerContext('after', method, args, paramRecordId)
1674
- if (paramRecordId) {
1675
- afterTriggerContext = Object.assign({}, afterTriggerContext, { id: paramRecordId });
1676
- }
1677
- let previousDoc = clone(afterTriggerContext.previousDoc);
1678
- args.splice(args.length - 1, 1, userSession ? userSession.userId : undefined)
1679
-
1680
- returnValue = await adapterMethod.apply(this._datasource, args);
1681
- if (method === 'find' || method == 'findOne' || method == 'count' || method == 'aggregate' || method == 'aggregatePrefixalPipeline') {
1682
- let values = returnValue || {}
1683
- if (method === 'count') {
1684
- values = returnValue || 0
1685
- }
1686
- else {
1687
- if (userSession) {
1688
- let _records = returnValue
1689
- if (method == 'findOne' && returnValue) {
1690
- _records = [_records]
1691
- }
1692
- await this.appendRecordPermission(_records, userSession);
1693
- }
1694
- }
1695
- Object.assign(afterTriggerContext, { data: { values: values } })
1696
- }
1697
- // console.log("==returnValue==", returnValue);
1698
- if(method == 'insert' && _.has(returnValue, '_id')){
1699
- afterTriggerContext.doc = returnValue;
1700
- afterTriggerContext = Object.assign({}, afterTriggerContext, { id: returnValue._id });
1701
- }
1702
- if (method == "update") {
1703
- if (returnValue) {
1704
- afterTriggerContext.doc = returnValue;
1705
- await this.runAfterTriggers(method, afterTriggerContext)
1706
- }
1707
- }
1708
- else {
1709
- await this.runAfterTriggers(method, afterTriggerContext)
1710
- }
1711
- if (method === 'find' || method == 'findOne' || method == 'count' || method == 'aggregate' || method == 'aggregatePrefixalPipeline') {
1712
- if (_.isEmpty(afterTriggerContext.data) || (_.isEmpty(afterTriggerContext.data.values) && !_.isNumber(afterTriggerContext.data.values))) {
1713
- return returnValue
1714
- } else {
1715
- return afterTriggerContext.data.values
1716
- }
1717
- }
1718
- await new WorkflowRulesRunner({
1719
- object_name: this.name,
1720
- event: method,
1721
- record: returnValue,
1722
- user_session: userSession,
1723
- previous_record: afterTriggerContext.previousDoc
1724
- }).run();
1725
- if (returnValue) {
1726
- if (method === "insert") {
1727
- // 当为insert时,上面代码执行后的doc不带_id,只能从returnValue中取
1728
- doc = returnValue;
1729
- recordId = <string>doc._id;
1730
- }
1731
- // 一定要先运行公式再运行汇总,以下两个函数顺序不能反
1732
- await this.runRecordFormula(method, objectName, recordId, doc, userSession);
1733
- await this.runRecordSummaries(method, objectName, recordId, doc, previousDoc, userSession);
1734
- }
1735
- await brokeEmitEvents(objectName, method, afterTriggerContext);
1736
- }
1737
- return returnValue
1738
- };
1739
-
1740
- private async runRecordFormula(method: string, objectName: string, recordId: string, doc: any, userSession: any) {
1741
- if (["insert", "update", "updateMany", "delete"].indexOf(method) > -1) {
1742
- if (method === "updateMany") {
1743
- // TODO:暂时不支持updateMany公式计算,因为拿不到修改了哪些数据
1744
- // let filters: SteedosQueryFilters = args[1];
1745
- // await runManyCurrentObjectFieldFormulas(objectName, filters, userSession);
1746
- }
1747
- else {
1748
- let currentUserId = userSession ? userSession.userId : undefined;
1749
- if(method !== "delete"){
1750
- await runCurrentObjectFieldFormulas(objectName, recordId, doc, currentUserId, true);
1751
- }
1752
- // 新建记录时肯定不会有字段被其它对象引用,但是会有当前对象上的字段之间互相引用,所以也需要重算被引用的公式字段值
1753
- // 见issue: a公式字段,其中应用了b公式字段,记录保存后a字段没计算,编辑后再保存字段计算 #2946
1754
- const onlyForOwn = method === "insert";
1755
- // 删除记录时需要考虑其他对象记录中的公式字段引用了被删除的记录,其公式需要重新计算,但是不可以再重新计算自身公式字段,因为记录被删除了会报错
1756
- // 见issue:删除记录时并不会触发公式字段重新计算,需要评估考虑加上 #2375 删除包含公式字段的记录时报错 #3427
1757
- const withoutCurrent = method === "delete";
1758
- await runQuotedByObjectFieldFormulas(objectName, recordId, userSession, { onlyForOwn, withoutCurrent });
1759
- }
1760
- }
1761
- }
1762
-
1763
- private async runRecordSummaries(method: string, objectName: string, recordId: string, doc: any, previousDoc: any, userSession: any) {
1764
- if (["insert", "update", "updateMany", "delete"].indexOf(method) > -1) {
1765
- if (method === "updateMany") {
1766
- // TODO:暂时不支持updateMany汇总计算,因为拿不到修改了哪些数据
1767
- }
1768
- else {
1769
- if (method === "insert") {
1770
- await runCurrentObjectFieldSummaries(objectName, recordId);
1771
- }
1772
- await runQuotedByObjectFieldSummaries(objectName, recordId, previousDoc, userSession);
1773
- }
1774
- }
1775
- }
1776
-
1777
- private getObjectEditPermissionFilters(objectPermission, userSession) {
1778
- const objectPermissionFilters = [];
1779
- if (!_.isEmpty(objectPermission.modifyAssignCompanysRecords)) {
1780
- objectPermissionFilters.push(`(${formatFiltersToODataQuery([['company_id', 'in', objectPermission.modifyAssignCompanysRecords], 'or', ['company_ids', 'in', objectPermission.modifyAssignCompanysRecords]], userSession)})`)
1781
- }
1782
- return objectPermissionFilters;
1783
- }
1784
-
1785
- /**
1786
- * 把query.filters用formatFiltersToODataQuery转为odata query
1787
- * 主要是为了把userSession中的utcOffset逻辑传入formatFiltersToODataQuery函数处理
1788
- */
1789
- private dealWithFilters(method: string, args: any[]) {
1790
- let userSession = args[args.length - 1];
1791
- if (userSession) {
1792
- if (method === 'find' || method === 'count' || method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1793
- let query = args[args.length - 2];
1794
- if (method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1795
- query = args[args.length - 3];
1796
- }
1797
- if (query.filters && !_.isString(query.filters)) {
1798
- query.filters = formatFiltersToODataQuery(query.filters, userSession);
1799
- }
1800
- }
1801
- }
1802
- }
1803
-
1804
- private async dealWithMethodPermission(method: string, args: any[]) {
1805
- let userSession = args[args.length - 1];
1806
- if (userSession) {
1807
- let spaceId = userSession.spaceId;
1808
- let userId = userSession.userId;
1809
- let objPm = await this.getUserObjectPermission(userSession, false);
1810
- if (method === 'find' || method === 'count' || method === 'findOne' || method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1811
- let query = args[args.length - 2];
1812
- if (method === 'aggregate' || method === 'aggregatePrefixalPipeline') {
1813
- query = args[args.length - 3];
1814
- }
1815
- if (query.filters && !_.isString(query.filters)) {
1816
- query.filters = formatFiltersToODataQuery(query.filters);
1817
- }
1818
-
1819
- if (this.table_name == 'cfs.files.filerecord' || this.table_name == 'cfs.instances.filerecord') {
1820
- return;
1821
- }
1822
-
1823
- if (isCloudAdminSpace(spaceId)) {
1824
- return
1825
- }
1826
-
1827
- let spaceFilter, companyFilter, ownerFilter, sharesFilter, shareRuleFilters, restrictionRuleFilters, clientFilter = query.filters, filters, permissionFilters = [], userFilters = [];
1828
-
1829
- //space 权限
1830
- if (spaceId) {
1831
- spaceFilter = `(space eq '${spaceId}')`;
1832
- }
1833
-
1834
- // 本公司权限
1835
- if (spaceId && !objPm.viewAllRecords && objPm.viewCompanyRecords) {
1836
- if (_.isEmpty(userSession.companies)) {
1837
- console.log('objPm', objPm);
1838
- throw new Error("user not belong any company!");
1839
- }
1840
- companyFilter = _.map(userSession.companies, function (comp: any) {
1841
- return `(company_id eq '${comp._id}') or (company_ids eq '${comp._id}')`
1842
- });
1843
- }
1844
-
1845
- if (!objPm.viewAllRecords && !objPm.viewCompanyRecords && objPm.allowRead) { // owner
1846
- ownerFilter = `(owner eq '${userId}')`;
1847
- }
1848
-
1849
- // 指定公司权限
1850
- let viewAssignCompanysRecordsFilter = [];
1851
- if (objPm.viewAssignCompanysRecords) {
1852
- _.each(objPm.viewAssignCompanysRecords, (assignCompanyId) => {
1853
- viewAssignCompanysRecordsFilter.push(`((company_id eq '${assignCompanyId}') or (company_ids eq '${assignCompanyId}'))`)
1854
- })
1855
- }
1856
- if (!_.isEmpty(viewAssignCompanysRecordsFilter)) {
1857
- permissionFilters.push(`(${viewAssignCompanysRecordsFilter.join(' or ')})`);
1858
- }
1859
-
1860
- //共享规则
1861
- shareRuleFilters = await ShareRules.getUserObjectFilters(this.name, userSession);
1862
-
1863
- if (!_.isEmpty(shareRuleFilters)) {
1864
- permissionFilters.push(`(${shareRuleFilters.join(' or ')})`);
1865
- }
1866
-
1867
- // 限制规则
1868
- restrictionRuleFilters = await RestrictionRule.getUserObjectFilters(this.name, userSession);
1869
-
1870
- if (!_.isEmpty(restrictionRuleFilters)) {
1871
- userFilters.push(`(${restrictionRuleFilters.join(' or ')})`);
1872
- }
1873
- // objectPermissionFilters = this.getObjectPermissionFilters(objPm, userSession, false);
1874
-
1875
- // if (!_.isEmpty(objectPermissionFilters)) {
1876
- // permissionFilters.push(`(${objectPermissionFilters.join(' or ')})`);
1877
- // }
1878
-
1879
- //共享规则(旧)
1880
- sharesFilter = getUserObjectSharesFilters(this.name, userSession);
1881
-
1882
- if (!_.isEmpty(companyFilter)) {
1883
- permissionFilters.push(`(${companyFilter.join(' or ')})`);
1884
- }
1885
-
1886
- if (ownerFilter) {
1887
- permissionFilters.push(ownerFilter);
1888
- }
1889
-
1890
- if (!_.isEmpty(sharesFilter)) {
1891
- permissionFilters.push(`(${sharesFilter.join(' or ')})`);
1892
- }
1893
-
1894
- if (clientFilter) {
1895
- userFilters.push(clientFilter);
1896
- }
1897
-
1898
- if (spaceFilter) {
1899
- userFilters.push(spaceFilter);
1900
- }
1901
-
1902
- if (!userSession.is_space_admin && !_.isEmpty(permissionFilters)) {
1903
- filters = permissionFilters.join(' or ');
1904
- }
1905
-
1906
- if (!_.isEmpty(userFilters)) {
1907
- filters = filters ? `(${filters}) and (${userFilters.join(' and ')})` : userFilters.join(' and ')
1908
- }
1909
-
1910
- query.filters = filters;
1911
- }
1912
- else if (method === 'insert') {
1913
- if (!objPm.allowCreate) {
1914
- throw new Error(`no ${method} permission!`);
1915
- }
1916
- }
1917
- else if (method === 'update' || method === 'updateOne') {
1918
- const permissionFilters = this.getObjectEditPermissionFilters(objPm, userSession);
1919
- if (!objPm.allowEdit && _.isEmpty(permissionFilters)) {
1920
- throw new Error(`no ${method} permission!`);
1921
- }
1922
- let objectPermissionEditFilters = '';
1923
- if (!_.isEmpty(permissionFilters)) {
1924
- objectPermissionEditFilters = ` or (${permissionFilters.join(' or ')})`
1925
- }
1926
- let id = args[args.length - 3];
1927
- if (!objPm.modifyAllRecords && objPm.modifyCompanyRecords) {
1928
- let companyFilters = _.map(userSession.companies, function (comp: any) {
1929
- return `(company_id eq '${comp._id}') or (company_ids eq '${comp._id}')`
1930
- }).join(' or ')
1931
- if (companyFilters) {
1932
- if (_.isString(id)) {
1933
- id = { filters: `(_id eq \'${id}\') and (${companyFilters}${objectPermissionEditFilters})` }
1934
- }
1935
- else if (_.isObject(id)) {
1936
- if (id.filters && !_.isString(id.filters)) {
1937
- id.filters = formatFiltersToODataQuery(id.filters);
1938
- }
1939
- id.filters = id.filters ? `(${id.filters}) and (${companyFilters}${objectPermissionEditFilters})` : `(${companyFilters}${objectPermissionEditFilters})`;
1940
- }
1941
- }
1942
- }
1943
- else if (!objPm.modifyAllRecords && !objPm.modifyCompanyRecords && objPm.allowEdit) {
1944
- if (_.isString(id)) {
1945
- id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\' ${objectPermissionEditFilters})` }
1946
- }
1947
- else if (_.isObject(id)) {
1948
- if (id.filters && !_.isString(id.filters)) {
1949
- id.filters = formatFiltersToODataQuery(id.filters);
1950
- }
1951
- id.filters = id.filters ? `(${id.filters}) and (owner eq \'${userId}\' ${objectPermissionEditFilters})` : `(owner eq \'${userId}\' ${objectPermissionEditFilters})`;
1952
- }
1953
- } else if (objectPermissionEditFilters) {
1954
- if (_.isString(id)) {
1955
- id = { filters: `(_id eq \'${id}\') and (${objectPermissionEditFilters})` }
1956
- }
1957
- else if (_.isObject(id)) {
1958
- if (id.filters && !_.isString(id.filters)) {
1959
- id.filters = formatFiltersToODataQuery(id.filters);
1960
- }
1961
- id.filters = id.filters ? `(${id.filters}) and (${objectPermissionEditFilters})` : `(${objectPermissionEditFilters})`;
1962
- }
1963
- }
1964
- args[args.length - 3] = id;
1965
- }
1966
- else if (method === 'updateMany') {
1967
- if (!objPm.modifyAllRecords && !objPm.modifyCompanyRecords) {
1968
- throw new Error(`no ${method} permission!`);
1969
- }
1970
- if (!objPm.modifyAllRecords && objPm.modifyCompanyRecords) {
1971
- let queryFilters = args[args.length - 3];
1972
- let companyFilters = _.map(userSession.companies, function (comp: any) {
1973
- return `(company_id eq '${comp._id}') or (company_ids eq '${comp._id}')`
1974
- }).join(' or ')
1975
- if (companyFilters) {
1976
- if (queryFilters && !_.isString(queryFilters)) {
1977
- queryFilters = formatFiltersToODataQuery(queryFilters);
1978
- }
1979
- queryFilters = queryFilters ? `(${queryFilters}) and (${companyFilters})` : `(${companyFilters})`;
1980
- args[args.length - 3] = queryFilters;
1981
- }
1982
- }
1983
- }
1984
- else if (method === 'delete') {
1985
- const permissionFilters = this.getObjectEditPermissionFilters(objPm, userSession);
1986
- if (!objPm.allowDelete && _.isEmpty(permissionFilters)) {
1987
- throw new Error(`no ${method} permission!`);
1988
- }
1989
-
1990
- let objectPermissionEditFilters = '';
1991
- if (!_.isEmpty(permissionFilters)) {
1992
- objectPermissionEditFilters = ` or (${permissionFilters.join(' or ')})`
1993
- }
1994
-
1995
- let id = args[args.length - 2];
1996
- if (!objPm.modifyAllRecords && objPm.modifyCompanyRecords) {
1997
- let companyFilters = _.map(userSession.companies, function (comp: any) {
1998
- return `(company_id eq '${comp._id}') or (company_ids eq '${comp._id}')`
1999
- }).join(' or ')
2000
- if (companyFilters) {
2001
- id = { filters: `(_id eq \'${id}\') and (${companyFilters}${objectPermissionEditFilters})` };
2002
- }
2003
- }
2004
- else if (!objPm.modifyAllRecords && !objPm.modifyCompanyRecords) {
2005
- id = { filters: `(_id eq \'${id}\') and (owner eq \'${userId}\'${objectPermissionEditFilters})` };
2006
- } else if (objectPermissionEditFilters) {
2007
- if (_.isString(id)) {
2008
- id = { filters: `(_id eq \'${id}\') and (${objectPermissionEditFilters})` }
2009
- }
2010
- else if (_.isObject(id)) {
2011
- if (id.filters && !_.isString(id.filters)) {
2012
- id.filters = formatFiltersToODataQuery(id.filters);
2013
- }
2014
- id.filters = id.filters ? `(${id.filters}) and (${objectPermissionEditFilters})` : `(${objectPermissionEditFilters})`;
2015
- }
2016
- }
2017
- args[args.length - 2] = id;
2018
- }
2019
-
2020
- }
2021
-
2022
- }
2023
-
2024
- /***** get/set *****/
2025
- public get schema(): SteedosSchema {
2026
- return this._schema;
2027
- }
2028
-
2029
- public get name(): string {
2030
- return this._name;
2031
- }
2032
-
2033
- public get fields(): Dictionary<SteedosFieldType> {
2034
- return this._fields;
2035
- }
2036
-
2037
- public get actions(): Dictionary<SteedosActionType> {
2038
- return this._actions;
2039
- }
2040
-
2041
- public get triggers(): Dictionary<SteedosTriggerType> {
2042
- return this._triggers;
2043
- }
2044
-
2045
- public get listeners(): Dictionary<SteedosListenerConfig> {
2046
- return this._listeners;
2047
- }
2048
- public set listeners(value: Dictionary<SteedosListenerConfig>) {
2049
- this._listeners = value;
2050
- }
2051
-
2052
- public get list_views(): Dictionary<SteedosObjectListViewType> {
2053
- return this._list_views;
2054
- }
2055
-
2056
- public get table_name(): string {
2057
- return this._table_name;
2058
- }
2059
-
2060
- public get primaryField(): SteedosFieldType {
2061
- return this._fields[this._idFieldName];
2062
- }
2063
-
2064
- public get primaryFields(): SteedosFieldType[] {
2065
- return this._idFieldNames.map((fieldName) => {
2066
- return this._fields[fieldName]
2067
- });
2068
- }
2069
- }
2070
-
2071
- export function getObject(objectName: string, schema?: SteedosSchema) {
2072
- return (schema ? schema : getSteedosSchema()).getObject(objectName);
2073
- }
2074
- export function getLocalObject(objectName: string, schema?: SteedosSchema) {
2075
- return (schema ? schema : getSteedosSchema()).getLocalObject(objectName);
2076
- }