@steedos/standard-ui 2.2.55-beta.16

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.
@@ -0,0 +1,94 @@
1
+ const core = require('@steedos/core');
2
+ db.apps = Creator.Collections.apps ? Creator.Collections.apps : core.newCollection('apps')
3
+
4
+ db.apps.isInternalApp = function (url) {
5
+ var app_url, i, len, ref;
6
+ if (url && db.apps.INTERNAL_APPS) {
7
+ ref = db.apps.INTERNAL_APPS;
8
+ for (i = 0, len = ref.length; i < len; i++) {
9
+ app_url = ref[i];
10
+ if (url.startsWith(app_url)) {
11
+ return true;
12
+ }
13
+ }
14
+ }
15
+ return false;
16
+ };
17
+
18
+ if (Meteor.isServer) {
19
+ db.apps.allow({
20
+ insert: function (userId, doc) {
21
+ if (!Steedos.isSpaceAdmin(doc.space, userId)) {
22
+ return false;
23
+ } else {
24
+ return true;
25
+ }
26
+ },
27
+ update: function (userId, doc) {
28
+ if (!Steedos.isSpaceAdmin(doc.space, userId)) {
29
+ return false;
30
+ } else {
31
+ return true;
32
+ }
33
+ },
34
+ remove: function (userId, doc) {
35
+ if (!Steedos.isSpaceAdmin(doc.space, userId)) {
36
+ return false;
37
+ } else {
38
+ return true;
39
+ }
40
+ }
41
+ });
42
+ }
43
+
44
+ if (Meteor.isServer) {
45
+ // db.apps.before.insert (userId, doc) ->
46
+ // doc.internal = db.apps.isInternalApp(doc.url)
47
+ // return
48
+ db.apps.before.update(function (userId, doc, fieldNames, modifier, options) {
49
+ return modifier.$set = modifier.$set || {};
50
+ });
51
+ }
52
+
53
+ Fiber = require('fibers')
54
+
55
+ var getUserOrganizations = function(userId, spaceId){
56
+ var space_user = db.space_users.findOne({user:userId,space:spaceId}, {fields:{organizations:1}})
57
+ if(!space_user){
58
+ return []
59
+ }
60
+ var organizations = space_user.organizations
61
+ if(!organizations){
62
+ return []
63
+ }
64
+ var userOrgs = db.organizations.find({_id:{$in:organizations}}).fetch()
65
+ var parents = _.flatten(_.pluck(userOrgs, 'parents'))
66
+ return _.union(organizations,parents)
67
+ }
68
+
69
+ var getUserApps = function (userId, spaceId) {
70
+ var userOrgs = getUserOrganizations(userId, spaceId);
71
+ var selector = {
72
+ $or: [
73
+ {$or: [{space: {$exists: false}}, {space: spaceId}]},
74
+ { 'members.organizations': {$in: userOrgs} },
75
+ { 'members.users': {$in: [ userId ]} }
76
+ ]
77
+ }
78
+ return db.apps.find(selector, {sort: {sort: 1}}).fetch();
79
+ };
80
+
81
+ // Creator.Objects['apps'].methods = {
82
+ // safe_apps: function (req, res) {
83
+ // return Fiber(function () {
84
+ // var userSession = req.user
85
+ // var userId = userSession.userId
86
+ // var spaceId = userSession.spaceId
87
+ // var apps = getUserApps(userId, spaceId);
88
+ // return res.send({
89
+ // "@odata.count": apps.length,
90
+ // value: apps
91
+ // });
92
+ // }).run();
93
+ // }
94
+ // }
@@ -0,0 +1,328 @@
1
+ name: apps
2
+ label: App
3
+ icon: apps
4
+ hidden: true
5
+ version: 2
6
+ fields:
7
+ name:
8
+ label: Name
9
+ type: text
10
+ defaultValue: ''
11
+ description: ''
12
+ inlineHelpText: ''
13
+ required: true
14
+ searchable: true
15
+ index: true
16
+ code:
17
+ label: API Name
18
+ type: text
19
+ required: true
20
+ searchable: true
21
+ icon_slds:
22
+ label: SLDS Icon
23
+ type: lookup
24
+ required: true
25
+ optionsFunction: !!js/function |
26
+ function () {
27
+ var options;
28
+ options = [];
29
+
30
+ _.forEach(Creator.resources.sldsIcons.standard, function (svg) {
31
+ return options.push({
32
+ value: svg,
33
+ label: svg,
34
+ icon: svg
35
+ });
36
+ });
37
+
38
+ return options;
39
+ }
40
+ filterable: true
41
+ visible:
42
+ label: Visible
43
+ type: boolean
44
+ defaultValue: true
45
+ description:
46
+ label: Description
47
+ type: textarea
48
+ is_wide: true
49
+ tabs:
50
+ label: Tabs
51
+ type: lookup
52
+ multiple: true
53
+ group: Business object
54
+ is_wide: true
55
+ reference_to: tabs
56
+ reference_to_field: name
57
+ objects:
58
+ label: Objects
59
+ type: lookup
60
+ multiple: true
61
+ group: Business object
62
+ optionsFunction: !!js/function |
63
+ function () {
64
+ return Steedos.getObjectsOptions()
65
+ }
66
+ filterable: true
67
+ mobile_objects:
68
+ label: Mobile Objects
69
+ type: lookup
70
+ multiple: true
71
+ group: Business object
72
+ optionsFunction: !!js/function |
73
+ function () {
74
+ return Steedos.getObjectsOptions()
75
+ }
76
+ filterable: true
77
+ is_creator:
78
+ type: boolean
79
+ label: Item of Menu
80
+ defaultValue: true
81
+ group: Business object
82
+ mobile:
83
+ type: boolean
84
+ label: Mobile App
85
+ defaultValue: true
86
+ group: Business object
87
+ icon:
88
+ label: Icon
89
+ type: text
90
+ hidden: true
91
+ sort:
92
+ label: Sort Number
93
+ type: number
94
+ defaultValue: 9100
95
+ sortable: true
96
+
97
+ # members:
98
+ # type: object
99
+ # label: Members
100
+ # is_wide: true
101
+ # members.users:
102
+ # type: lookup
103
+ # label: User Members
104
+ # reference_to: users
105
+ # multiple: true
106
+ # filterable: true
107
+ # members.organizations:
108
+ # type: lookup
109
+ # label: Department Members
110
+ # reference_to: organizations
111
+ # multiple: true
112
+ # filterable: true
113
+
114
+ url:
115
+ label: URL
116
+ type: url
117
+ group: External Application
118
+ is_use_ie:
119
+ type: boolean
120
+ label: Open in IE (Using Steedos Desktop)
121
+ defaultValue: false
122
+ group: External Application
123
+ is_use_iframe:
124
+ type: boolean
125
+ label: Open with iframe
126
+ defaultValue: false
127
+ group: External Application
128
+ is_new_window:
129
+ type: boolean
130
+ label: Open in New Window
131
+ defaultValue: false
132
+ group: External Application
133
+ on_click:
134
+ type: textarea
135
+ label: onClick
136
+ rows: 2
137
+ is_wide: true
138
+ group: External Application
139
+
140
+ auth_name:
141
+ label: Auth Name
142
+ type: text
143
+ group: External Application
144
+ secret:
145
+ label: API Secret Key
146
+ type: text
147
+ max: 16
148
+ min: 16
149
+ group: External Application
150
+
151
+ oauth2_enabled:
152
+ group: OAuth2
153
+ label: OAuth2 Enabled
154
+ type: boolean
155
+ hidden: true
156
+ oauth2_callback_url:
157
+ group: OAuth2
158
+ label: Callback URL
159
+ type: text
160
+ required: "{{formData.oauth2_enabled}}"
161
+ hidden: true
162
+ oauth2_scopes:
163
+ group: OAuth2
164
+ label: Scopes
165
+ type: select
166
+ hidden: true
167
+ multiple: true
168
+ required: "{{formData.oauth2_enabled}}"
169
+ options:
170
+ - label: Access to Your Unique Identifier (openid)
171
+ value: openid
172
+ - label: Access Basic Information (id, email, address, phone, locale)
173
+ value: profile
174
+ - label: Access Fully (full)
175
+ value: full
176
+ oauth2_logout_enabled:
177
+ group: OAuth2
178
+ label: OAuth2 Logout Enabled
179
+ type: boolean
180
+ hidden: true
181
+ oauth2_logout_url:
182
+ group: OAuth2
183
+ label: OAuth2 Logout URL
184
+ type: url
185
+ hidden: true
186
+ oauth2_home_url:
187
+ group: OAuth2
188
+ label: Homepage URL
189
+ type: url
190
+ required: "{{formData.oauth2_enabled}}"
191
+ hidden: true
192
+ oauth2_logo:
193
+ group: OAuth2
194
+ label: OAuth2 Logo
195
+ type: image
196
+ required: "{{formData.oauth2_enabled}}"
197
+ hidden: true
198
+ oauth2_client_secret:
199
+ group: OAuth2
200
+ label: OAuth2 Client secret
201
+ type: text
202
+ omit: true
203
+ hidden: true
204
+ saml_enabled:
205
+ hidden: true
206
+ group: SAML
207
+ label: SAML Enabled
208
+ type: boolean
209
+ saml_entity_id:
210
+ hidden: true
211
+ group: SAML
212
+ label: Entity Id
213
+ type: text
214
+ saml_issuer:
215
+ hidden: true
216
+ group: SAML
217
+ label: Issuer
218
+ type: text
219
+ saml_idp_cert:
220
+ hidden: true
221
+ group: SAML
222
+ label: IDP Cert
223
+ type: text
224
+ saml_acs_url:
225
+ hidden: true
226
+ group: SAML
227
+ label: ACS URL
228
+ type: url
229
+ saml_name_id_format:
230
+ hidden: true
231
+ group: SAML
232
+ label: Name
233
+ type: text
234
+ saml_logout_enabled:
235
+ hidden: true
236
+ group: SAML
237
+ label: SAML Logout Enabled
238
+ type: boolean
239
+ saml_logout_url:
240
+ hidden: true
241
+ group: SAML
242
+ label: SAML Logout URL
243
+ type: url
244
+ saml_logout_block:
245
+ hidden: true
246
+ group: SAML
247
+ label: SAML Logout Block
248
+ type: select
249
+ options:
250
+ - label: HTTP Redirect
251
+ value: redirect
252
+ - label: HTTP Post
253
+ value: post
254
+ is_system:
255
+ type: boolean
256
+ label: System
257
+ # omit: true
258
+ readonly: true
259
+ visible_on: "{{global.mode ==='read' ? true : false}}"
260
+ disabled: true
261
+ from_code_id:
262
+ type: text
263
+ visible_on: "{{false}}"
264
+ disabled: true
265
+ paging:
266
+ enabled: false
267
+ actions:
268
+ customize:
269
+ label: Customize
270
+ on: record_only
271
+ reset:
272
+ label: Reset
273
+ on: record_only
274
+ createOAuth2App:
275
+ label: 创建 OAuth 应用
276
+ on: list
277
+ sort: 180
278
+ list_views:
279
+ all:
280
+ label: All Apps
281
+ filter_scope: space
282
+ columns:
283
+ - name
284
+ - code
285
+ - description
286
+ - visible
287
+ - sort
288
+ - is_system
289
+ permission_set:
290
+ user:
291
+ allowCreate: false
292
+ allowDelete: false
293
+ allowEdit: false
294
+ allowRead: true
295
+ modifyAllRecords: false
296
+ viewAllRecords: true
297
+ admin:
298
+ allowCreate: true
299
+ allowDelete: true
300
+ allowEdit: true
301
+ allowRead: true
302
+ modifyAllRecords: true
303
+ viewAllRecords: true
304
+ # triggers:
305
+ # before.insert.server.apps:
306
+ # 'on': server
307
+ # when: before.insert
308
+ # todo: !!js/function |
309
+ # function (userId, doc) {
310
+ # return doc.icon = doc.icon_slds;
311
+ # }
312
+ # after.update.server.apps:
313
+ # 'on': server
314
+ # when: after.update
315
+ # todo: !!js/function |
316
+ # function (userId, doc, fieldNames, modifier, options) {
317
+ # var ref;
318
+
319
+ # if (modifier != null ? (ref = modifier.$set) != null ? ref.icon_slds : void 0 : void 0) {
320
+ # return Creator.getCollection("apps").direct.update({
321
+ # _id: doc._id
322
+ # }, {
323
+ # $set: {
324
+ # icon: modifier.$set.icon_slds
325
+ # }
326
+ # });
327
+ # }
328
+ # }
@@ -0,0 +1,149 @@
1
+ name: tabs
2
+ label: Tabs
3
+ icon: apps
4
+ hidden: true
5
+ version: 2.0
6
+ fields:
7
+ label:
8
+ inlineHelpText: This is the label of the tab, for web tabs only.
9
+ type: text
10
+ is_name: true
11
+ required: true
12
+ name:
13
+ label: Api Name
14
+ type: text
15
+ required: true
16
+ icon:
17
+ label: Icon
18
+ type: lookup
19
+ required: true
20
+ optionsFunction: !<tag:yaml.org,2002:js/function> |-
21
+ function () {
22
+ var options;
23
+ options = [];
24
+
25
+ _.forEach(Creator.resources.sldsIcons.standard, function (svg) {
26
+ return options.push({
27
+ value: svg,
28
+ label: svg,
29
+ icon: svg
30
+ });
31
+ });
32
+
33
+ return options;
34
+ }
35
+ parent:
36
+ label: Parent
37
+ type: lookup
38
+ reference_to: tabs
39
+ omit: true
40
+ hidden: true
41
+ type:
42
+ type: select
43
+ options:
44
+ - label: Object
45
+ value: object
46
+ - label: Url
47
+ value: url
48
+ - label: Page
49
+ value: page
50
+ mobile:
51
+ label: Display on the Mobile
52
+ type: boolean
53
+ defaultValue: true
54
+ desktop:
55
+ label: Display on the Desktop
56
+ type: boolean
57
+ defaultValue: true
58
+ frame_height:
59
+ hidden: true
60
+ inlineHelpText: The height, in pixels of the tab frame. Required for frame and page tabs.
61
+ label: Height
62
+ type: number
63
+ has_sidebar:
64
+ hidden: true
65
+ inlineHelpText: Indicates if the tab displays the sidebar panel.
66
+ type: boolean
67
+ object:
68
+ label: Object
69
+ type: lookup
70
+ reference_to: objects
71
+ reference_to_field: name
72
+ optionsFunction: !!js/function |
73
+ function () {
74
+ return Steedos.getObjectsOptions()
75
+ }
76
+ filterable: true
77
+ required: "{{'object' === formData.type ? true: false}}"
78
+ visible_on: "{{'object' === formData.type ? true: false}}"
79
+ url:
80
+ type: url
81
+ label: Url
82
+ required: "{{'url' === formData.type ? true: false}}"
83
+ visible_on: "{{'url' === formData.type ? true: false}}"
84
+ is_new_window:
85
+ type: boolean
86
+ visible_on: "{{'url' === formData.type ? true: false}}"
87
+ page:
88
+ type: lookup
89
+ label: 页面
90
+ required: "{{'page' === formData.type ? true: false}}"
91
+ visible_on: "{{'page' === formData.type ? true: false}}"
92
+ reference_to: pages
93
+ reference_to_field: name
94
+ filters:
95
+ - ['type','notin', ['record','list','form']]
96
+ action_overrides:
97
+ type: text
98
+ hidden: true
99
+ inlineHelpText: A list of the action overrides that are assigned to the tab. Only one override is allowed per formFactor for a given tab.
100
+ description:
101
+ type: textarea
102
+ is_wide: true
103
+ is_system:
104
+ type: boolean
105
+ label: System
106
+ # omit: true
107
+ readonly: true
108
+ visible_on: "{{global.mode ==='read' ? true : false}}"
109
+ disabled: true
110
+ list_views:
111
+ all:
112
+ label: All Apps
113
+ filter_scope: space
114
+ columns:
115
+ - label
116
+ - name
117
+ # - parent
118
+ - desktop
119
+ - mobile
120
+ - type
121
+ - is_system
122
+ permission_set:
123
+ user:
124
+ allowCreate: false
125
+ allowDelete: false
126
+ allowEdit: false
127
+ allowRead: true
128
+ modifyAllRecords: false
129
+ viewAllRecords: true
130
+ admin:
131
+ allowCreate: true
132
+ allowDelete: true
133
+ allowEdit: true
134
+ allowRead: true
135
+ modifyAllRecords: true
136
+ viewAllRecords: true
137
+ # form:
138
+ # beforeEdit: !!js/function |
139
+ # function(){
140
+ # return Steedos.TabsManager.changeSchema(this.doc, this.schema, 'edit');
141
+ # }
142
+ # afterEdit: !!js/function |
143
+ # function(){
144
+ # return Steedos.TabsManager.changeSchema(this.doc, this.schema, 'edit');
145
+ # }
146
+ # beforeView: !!js/function |
147
+ # function(){
148
+ # Steedos.TabsManager.changeSchema(this.doc, this.schema, 'view');
149
+ # }
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,134 @@
1
+ const _ = require('underscore');
2
+ const randomString = require("crypto-random-string");
3
+ const accounts = require('@steedos/accounts');
4
+ const objectql = require('@steedos/objectql')
5
+
6
+ const GrantTypes = ['authorization_code', 'refresh_token']
7
+
8
+ const getOAuth2ClientBody = (clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks) => {
9
+ return {
10
+ client_id: clientId,
11
+ client_name: clientName,
12
+ client_secret: clientSecret,
13
+ client_uri: clientUri,
14
+ logo_uri: logoUri,
15
+ response_types: responseTypes,
16
+ scope: scope,
17
+ callbacks: callbacks,
18
+ redirect_uris: [callbacks],
19
+ grant_types: GrantTypes,
20
+ token_endpoint_auth_method: 'client_secret_post'
21
+ }
22
+ }
23
+
24
+ //grant-types authorization_code,refresh_token
25
+ //token-endpoint-auth-method client_secret_post
26
+ const createOAuth2Client = async (clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks) => {
27
+ console.log(`createOAuth2Client`, clientId);
28
+ return await accounts.hydraAdmin.createOAuth2Client(getOAuth2ClientBody(clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks))
29
+ };
30
+
31
+ const deleteOAuth2Client = async (clientId) => {
32
+ console.log(`deleteOAuth2Client`, clientId);
33
+ return await accounts.hydraAdmin.deleteOAuth2Client(clientId);
34
+ }
35
+
36
+ const updateOAuth2Client = async (clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks) => {
37
+ return await accounts.hydraAdmin.updateOAuth2Client(clientId, getOAuth2ClientBody(clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks))
38
+ };
39
+
40
+ const upsetOAuth2Client = async (clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks) => {
41
+ const client = await accounts.hydraAdmin.getOAuth2Client(clientId);
42
+ if (client) {
43
+ return await updateOAuth2Client(clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks)
44
+ } else {
45
+ return await createOAuth2Client(clientId, clientName, clientSecret, clientUri, logoUri, responseTypes, scope, callbacks)
46
+ }
47
+ }
48
+
49
+ const getResponseTypes = (oauth2_scopes) => {
50
+ const scopes = ['code', 'id_token'];
51
+ _.each(oauth2_scopes, (oauth2_scope) => {
52
+ if (oauth2_scope === 'profile') {
53
+ scopes.push('steedos_id')
54
+ scopes.push('name')
55
+ scopes.push('username')
56
+ scopes.push('mobile')
57
+ scopes.push('email')
58
+ // scopes.push('job_number')
59
+ scopes.push('locale')
60
+ scopes.push('space')
61
+ // scopes.push('profile')
62
+ scopes.push('userId')
63
+ scopes.push('mobile_verified')
64
+ scopes.push('email_verified')
65
+ scopes.push('utcOffset')
66
+ }
67
+ })
68
+ return scopes;
69
+ }
70
+
71
+ module.exports = {
72
+ listenTo: 'apps',
73
+ beforeInsert: async function () {
74
+ const { doc } = this;
75
+ if (doc.oauth2_enabled) {
76
+ doc.oauth2_client_secret = randomString(40);
77
+ };
78
+ },
79
+ afterInsert: async function () {
80
+ const { doc } = this;
81
+
82
+ if (doc.oauth2_enabled) {
83
+ const responseTypes = getResponseTypes(doc.oauth2_scopes)
84
+ const result = await createOAuth2Client(
85
+ doc.code,
86
+ doc.name,
87
+ doc.oauth2_client_secret,
88
+ doc.oauth2_home_url,
89
+ Meteor.absoluteUrl(`/api/files/images/${doc.oauth2_logo}`),
90
+ responseTypes,
91
+ doc.oauth2_scopes.join(','),
92
+ doc.oauth2_callback_url
93
+ )
94
+ console.log(`result`, result);
95
+ };
96
+
97
+ },
98
+ beforeUpdate: async function () {
99
+ const { doc, id } = this
100
+ if (doc.oauth2_enabled) {
101
+ const record = await objectql.getObject('apps').findOne(id);
102
+ if (!record.oauth2_client_secret) {
103
+ doc.oauth2_client_secret = randomString(40);
104
+ }
105
+ }
106
+ },
107
+ afterUpdate: async function () {
108
+ const { previousDoc, id, doc } = this;
109
+ const newDoc = await objectql.getObject('apps').findOne(id)
110
+
111
+ if ((_.has(doc, 'oauth2_enabled') && previousDoc.oauth2_enabled && newDoc.oauth2_enabled != true) || (_.has(doc, 'code') && previousDoc.code != newDoc.code)) {
112
+ await deleteOAuth2Client(newDoc.code)
113
+ }
114
+
115
+ if (newDoc.oauth2_enabled) {
116
+ const responseTypes = getResponseTypes(newDoc.oauth2_scopes)
117
+ await upsetOAuth2Client(
118
+ newDoc.code,
119
+ newDoc.name,
120
+ newDoc.oauth2_client_secret,
121
+ newDoc.oauth2_home_url,
122
+ Meteor.absoluteUrl(`/api/files/images/${newDoc.oauth2_logo}`),
123
+ responseTypes,
124
+ newDoc.oauth2_scopes.join(','),
125
+ newDoc.oauth2_callback_url)
126
+ }
127
+ },
128
+ afterDelete: async function () {
129
+ const { previousDoc } = this;
130
+ if (previousDoc.oauth2_enabled) {
131
+ await deleteOAuth2Client(doc.code)
132
+ }
133
+ }
134
+ }