@live-change/user-service 0.2.25 → 0.2.26

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,17 @@
1
+ function combinations(x, n ,p=[]) {
2
+ if(x.length == 0 || n > x.length) return []
3
+ if(n == 1 || x.length == 1) return x.map(e=>p.concat([e]))
4
+ let acc = []
5
+ for(let i = 0; i < x.length; i++) acc.push(
6
+ ...combinations(x.slice(i+1), n - 1, p.concat([x[i]]))
7
+ )
8
+ return acc
9
+ }
10
+
11
+ function allCombinations(x) {
12
+ let acc = []
13
+ for(let i = 1; i<=x.length; i++) acc.push(...combinations(x,i))
14
+ return acc
15
+ }
16
+
17
+ module.exports = { combinations, allCombinations }
@@ -0,0 +1,266 @@
1
+ const definition = require("./definition.js")
2
+ const App = require("@live-change/framework")
3
+ const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
4
+ const { User } = require("./model.js")
5
+
6
+ const pluralize = require('pluralize')
7
+
8
+ definition.processor(function(service, app) {
9
+
10
+ for(let modelName in service.models) {
11
+ const model = service.models[modelName]
12
+ if(model.contactOrUserItem) {
13
+ if(model.properties.owner) throw new Error('user property already exists!!!')
14
+
15
+ const originalModelProperties = { ...model.properties }
16
+ const modelProperties = Object.keys(model.properties)
17
+ const defaults = App.utils.generateDefault(model.properties)
18
+ const modelPropertyName = modelName.slice(0, 1).toLowerCase() + modelName.slice(1)
19
+
20
+ function modelRuntime() {
21
+ return service._runtime.models[modelName]
22
+ }
23
+
24
+ const config = model.contactOrUserItem
25
+ const writeableProperties = modelProperties || config.writableProperties
26
+
27
+ //console.log("USER ITEM", model)
28
+
29
+ if(model.itemOfAny) throw new Error("model " + modelName + " already have owner")
30
+ model.itemOfAny = {
31
+ ...config
32
+ }
33
+
34
+ /*await service.trigger({
35
+ type: 'contactConnected',
36
+ contactType: 'email',
37
+ contact: email,
38
+ user
39
+ })*/
40
+
41
+ service.trigger({
42
+ name: 'contactConnected',
43
+ properties: {
44
+ contactType: {
45
+ type: String,
46
+ validation: ['nonEmpty']
47
+ },
48
+ contact: {
49
+ type: String,
50
+ validation: ['nonEmpty']
51
+ },
52
+ user: {
53
+ type: User,
54
+ validation: ['nonEmpty']
55
+ }
56
+ },
57
+ async execute({ contactType, contact, user }, { service }, emit) {
58
+ const contactPath = [contactType, contact]
59
+ const contactItems = await modelRuntime().indexRangeGet('byOwner', contactPath, {} )
60
+ if(config.merge) {
61
+ const userPath = ['user_User', user]
62
+ const userItems = await modelRuntime().indexRangeGet('byOwner', userPath, {} )
63
+ const mergeResult = await config.merge(contactItems, userItems)
64
+ if(mergeResult) {
65
+ const { transferred, updated, deleted } = mergeResult
66
+ for(const entity of transferred) {
67
+ emit({
68
+ type: 'ownerOwned' + modelName + 'Transferred',
69
+ [modelPropertyName]: entity.id,
70
+ to: {
71
+ id: entity.id,
72
+ ownerType: 'user_User',
73
+ owner: user
74
+ }
75
+ })
76
+ }
77
+ for(const entity of updated) {
78
+ emit({
79
+ type: 'ownerOwned' + modelName + 'Updated',
80
+ [modelPropertyName]: entity.id,
81
+ identifiers: {
82
+ id: entity.id,
83
+ ownerType: 'user_User',
84
+ owner: user
85
+ },
86
+ data: entity
87
+ })
88
+ }
89
+ for(const entity of deleted) {
90
+ emit({
91
+ type: 'ownerOwned' + modelName + 'Deleted',
92
+ [modelPropertyName]: entity.id,
93
+ })
94
+ }
95
+ }
96
+ } else {
97
+ for(const entity of contactItems) {
98
+ emit({
99
+ type: 'ownerOwned' + modelName + 'Transferred',
100
+ [modelPropertyName]: entity.id,
101
+ identifiers: {
102
+ id: entity.id,
103
+ ownerType: 'user_User',
104
+ owner: user
105
+ }
106
+ })
107
+ }
108
+ }
109
+ }
110
+ })
111
+
112
+ if(config.ownerReadAccess) {
113
+ const viewName = 'my' + pluralize(modelName)
114
+ service.views[viewName] = new ViewDefinition({
115
+ name: viewName,
116
+ access(params, context) {
117
+ return context.client.user && (config.ownerReadAccess ? config.ownerReadAccess(params, context) : true)
118
+ },
119
+ properties: App.rangeProperties,
120
+ daoPath(range, { client, context }) {
121
+ const owner = ['user_User', client.user]
122
+ const path = modelRuntime().indexRangePath('byOwner', owner, range )
123
+ return path
124
+ }
125
+ })
126
+ for(const sortField of config.sortBy || []) {
127
+ const sortFieldUc = sortField.slice(0, 1).toUpperCase() + sortField.slice(1)
128
+ const viewName = 'mySessionOrUser' + pluralize(modelName) + 'By' + sortFieldUc
129
+ service.views[viewName] = new ViewDefinition({
130
+ name: viewName,
131
+ access(params, context) {
132
+ if(!context.client.user) return false
133
+ return config.ownerReadAccess(params, context)
134
+ },
135
+ properties: App.rangeProperties,
136
+ daoPath(range, { client, context }) {
137
+ const owner = ['user_User', client.user]
138
+ return modelRuntime().sortedIndexRangePath('byOwner' + sortFieldUc, owner, range)
139
+ }
140
+ })
141
+ }
142
+ }
143
+
144
+ if(config.ownerCreateAccess || config.ownerWriteAccess) {
145
+ const eventName = 'ownerOwned' + modelName + 'Created'
146
+ const actionName = 'createMy' + modelName
147
+ service.actions[actionName] = new ActionDefinition({
148
+ name: actionName,
149
+ access: (params, context) => context.client.user
150
+ && (config.ownerCreateAccess || config.ownerWriteAccess)(params,context),
151
+ properties: {
152
+ ...originalModelProperties,
153
+ [modelPropertyName]: {
154
+ type: model,
155
+ validation: ['localId']
156
+ }
157
+ },
158
+ queuedBy: (command) => 'u:'+command.client.user,
159
+ waitForEvents: true,
160
+ async execute(properties, { client, service }, emit) {
161
+ const id = properties[modelPropertyName] || app.generateUid()
162
+ const entity = await modelRuntime().get(id)
163
+ if(entity) throw 'exists'
164
+ const identifiers = {
165
+ ownerType: 'user_User',
166
+ owner: client.user,
167
+ }
168
+ emit({
169
+ type: eventName,
170
+ [modelPropertyName]: id,
171
+ identifiers,
172
+ data: properties
173
+ })
174
+ return id
175
+ }
176
+ })
177
+ }
178
+ if(config.ownerUpdateAccess || config.ownerWriteAccess) {
179
+ const eventName = 'ownerOwned' + modelName + 'Updated'
180
+ const actionName = 'updateMy' + modelName
181
+ service.actions[actionName] = new ActionDefinition({
182
+ name: actionName,
183
+ access: (params, context) => context.client.user
184
+ && (config.ownerUpdateAccess || config.ownerWriteAccess)(params,context),
185
+ properties: {
186
+ ...originalModelProperties,
187
+ [modelPropertyName]: {
188
+ type: model,
189
+ validation: ['nonEmpty']
190
+ }
191
+ },
192
+ skipValidation: true,
193
+ queuedBy: (command) => command.client.user ? 'u:'+command.client.user : 's:'+command.client.session,
194
+ waitForEvents: true,
195
+ async execute(properties, { client, service }, emit) {
196
+ const entity = await modelRuntime().get(properties[modelPropertyName])
197
+ if(!entity) throw 'not_found'
198
+ if(entity.ownerType == 'user_User') {
199
+ if(entity.owner != client.user) throw 'not_authorized'
200
+ } else throw 'not_authorized'
201
+ let updateObject = {}
202
+ for(const propertyName of writeableProperties) {
203
+ if(properties.hasOwnProperty(propertyName)) {
204
+ updateObject[propertyName] = properties[propertyName]
205
+ }
206
+ }
207
+ const merged = App.utils.mergeDeep({}, entity, updateObject)
208
+ await App.validation.validate(merged, validators, { source: action, action, service, app, client })
209
+ const identifiers = client.user ? {
210
+ ownerType: 'user_User',
211
+ owner: client.user,
212
+ } : {
213
+ ownerType: 'session_Session',
214
+ owner: client.session,
215
+ }
216
+ emit({
217
+ type: eventName,
218
+ [modelPropertyName]: entity.id,
219
+ identifiers,
220
+ data: properties
221
+ })
222
+ }
223
+ })
224
+ const action = service.actions[actionName]
225
+ const validators = App.validation.getValidators(action, service, action)
226
+ }
227
+ if(config.userDeleteAccess || config.userWriteAccess) {
228
+ const eventName = 'userOwned' + modelName + 'Deleted'
229
+ const actionName = 'deleteMyUser' + modelName
230
+ service.actions[actionName] = new ActionDefinition({
231
+ name: actionName,
232
+ access: (params, context) => context.client.user
233
+ && (config.ownerDeleteAccess || config.ownerWriteAccess)(params,context),
234
+ properties: {
235
+ [modelPropertyName]: {
236
+ type: model,
237
+ validation: ['nonEmpty']
238
+ }
239
+ },
240
+ queuedBy: (command) => command.client.user ? 'u:'+command.client.user : 's:'+command.client.session,
241
+ waitForEvents: true,
242
+ async execute(properties, { client, service }, emit) {
243
+ const entity = await modelRuntime().get(properties[modelPropertyName])
244
+ if(!entity) throw 'not_found'
245
+ if(entity.ownerType == 'user_User') {
246
+ if(entity.owner != client.user) throw 'not_authorized'
247
+ } else throw 'not_authorized'
248
+ const identifiers = client.user ? {
249
+ ownerType: 'user_User',
250
+ owner: client.user,
251
+ } : {
252
+ ownerType: 'session_Session',
253
+ owner: client.session,
254
+ }
255
+ emit({
256
+ type: eventName,
257
+ [modelPropertyName]: entity.id,
258
+ identifiers
259
+ })
260
+ }
261
+ })
262
+ }
263
+ }
264
+ }
265
+
266
+ })
@@ -0,0 +1,243 @@
1
+ const definition = require("./definition.js")
2
+ const App = require("@live-change/framework")
3
+ const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
4
+ const { User } = require("./model.js")
5
+
6
+ definition.processor(function(service, app) {
7
+
8
+ for(let modelName in service.models) {
9
+ const model = service.models[modelName]
10
+
11
+ if(model.contactOrUserProperty) {
12
+ console.log("MODEL " + modelName + " IS SESSION OR USER PROPERTY, CONFIG:", model.userProperty)
13
+ if (model.properties.owner) throw new Error('owner property already exists!!!')
14
+
15
+ const originalModelProperties = { ...model.properties }
16
+ const modelProperties = Object.keys(model.properties)
17
+ const defaults = App.utils.generateDefault(model.properties)
18
+
19
+ function modelRuntime() {
20
+ return service._runtime.models[modelName]
21
+ }
22
+
23
+ const config = model.contactOrUserProperty
24
+ const writeableProperties = modelProperties || config.writableProperties
25
+
26
+ if(model.propertyOfAny) throw new Error("model " + modelName + " already have owner")
27
+ model.propertyOfAny = {
28
+ ...config
29
+ }
30
+
31
+ service.trigger({
32
+ name: 'contactConnected',
33
+ properties: {
34
+ contactType: {
35
+ type: String,
36
+ validation: ['nonEmpty']
37
+ },
38
+ contact: {
39
+ type: String,
40
+ validation: ['nonEmpty']
41
+ },
42
+ user: {
43
+ type: User,
44
+ validation: ['nonEmpty']
45
+ }
46
+ },
47
+ async execute({ contactType, contact, user }, { service }, emit) {
48
+ const contactPath = [contactType, contact]
49
+ const contactPropertyId = contactPath.map(p => JSON.stringify(p)).join(':')
50
+ const contactProperty = await modelRuntime().get(contactPropertyId)
51
+ if(contactProperty) {
52
+ const userPath = ['user_User', user]
53
+ const userPropertyId = userPath.map(p => JSON.stringify(p)).join(':')
54
+ const userProperty = await modelRuntime().get(userPropertyId)
55
+ if(config.merge) {
56
+ const mergeResult = await config.merge(contactProperty, userProperty)
57
+ if(mergeResult && userProperty) {
58
+ emit({
59
+ type: 'ownerOwned' + modelName + 'Updated',
60
+ identifiers: {
61
+ ownerType: 'user_User',
62
+ owner: user
63
+ },
64
+ data: mergeResult
65
+ })
66
+ } else {
67
+ emit({
68
+ type: 'ownerOwned' + modelName + 'Set',
69
+ identifiers: {
70
+ ownerType: 'user_User',
71
+ owner: user
72
+ },
73
+ data: mergeResult
74
+ })
75
+ }
76
+ emit({
77
+ type: 'ownerOwned' + modelName + 'Reset',
78
+ identifiers: {
79
+ ownerType: contactType,
80
+ owner: contact
81
+ }
82
+ })
83
+ } else {
84
+ if(!userProperty) {
85
+ emit({
86
+ type: 'ownerOwned' + modelName + 'Transferred',
87
+ from: {
88
+ ownerType: contactType,
89
+ owner: contact
90
+ },
91
+ to: {
92
+ ownerType: 'user_User',
93
+ owner: user
94
+ }
95
+ })
96
+ }
97
+ }
98
+ }
99
+ }
100
+ })
101
+
102
+ if(config.ownerReadAccess) {
103
+ const viewName = 'my' + modelName
104
+ service.views[viewName] = new ViewDefinition({
105
+ name: viewName,
106
+ access(params, context) {
107
+ return context.client.user && (config.ownerReadAccess ? config.ownerReadAccess(params, context) : true)
108
+ },
109
+ daoPath(params, { client, context }) {
110
+ const owner = ['user_User', client.user]
111
+ const id = owner.map(p => JSON.stringify(p)).join(':')
112
+ return modelRuntime().path(id)
113
+ }
114
+ })
115
+ }
116
+
117
+ if(config.ownerViews) {
118
+ for(const view of config.userViews) {
119
+ const viewName = view.name || ('my' + (view.prefix || '') + modelName + (view.suffix || ''))
120
+ service.views[viewName] = new ViewDefinition({
121
+ name: viewName,
122
+ access(params, context) {
123
+ return context.client.user && (view.access ? view.access(params, context) : true)
124
+ },
125
+ daoPath(params, { client, context }) {
126
+ const owner = ['user_User', client.user]
127
+ const id = owner.map(p => JSON.stringify(p)).join(':')
128
+ return view.fields
129
+ ? modelRuntime().limitedPath(id, view.fields)
130
+ : modelRuntime().path(id)
131
+ }
132
+ })
133
+ }
134
+ }
135
+
136
+ if(config.ownerSetAccess || config.ownerWriteAccess) {
137
+ const eventName = 'ownerOwned' + modelName + 'Set'
138
+ const actionName = 'setMy' + modelName
139
+ service.actions[actionName] = new ActionDefinition({
140
+ name: actionName,
141
+ properties: {
142
+ ...originalModelProperties
143
+ },
144
+ access: (params, context) => context.client.user
145
+ && (config.ownerSetAccess || config.ownerWriteAccess)(params, context),
146
+ skipValidation: true,
147
+ queuedBy: (command) => command.client.user ? 'u:'+command.client.user : 's:'+command.client.session,
148
+ waitForEvents: true,
149
+ async execute(properties, {client, service}, emit) {
150
+ let newObject = {}
151
+ for(const propertyName of writeableProperties) {
152
+ if(properties.hasOwnProperty(propertyName)) {
153
+ newObject[propertyName] = properties[propertyName]
154
+ }
155
+ }
156
+ const data = App.utils.mergeDeep({}, defaults, newObject)
157
+ await App.validation.validate(data, validators, { source: action, action, service, app, client })
158
+ const identifiers = {
159
+ ownerType: 'user_User',
160
+ owner: client.user,
161
+ }
162
+ emit({
163
+ type: eventName,
164
+ identifiers,
165
+ data
166
+ })
167
+ }
168
+ })
169
+ const action = service.actions[actionName]
170
+ const validators = App.validation.getValidators(action, service, action)
171
+ }
172
+
173
+ if(config.ownerUpdateAccess || config.ownerWriteAccess) {
174
+ const eventName = 'ownerOwned' + modelName + 'Updated'
175
+ const actionName = 'updateMy' + modelName
176
+ service.actions[actionName] = new ActionDefinition({
177
+ name: actionName,
178
+ properties: {
179
+ ...originalModelProperties
180
+ },
181
+ access: (params, context) => context.client.user
182
+ && (config.ownerUpdateAccess || config.ownerWriteAccess)(params, context),
183
+ skipValidation: true,
184
+ queuedBy: (command) => command.client.user ? 'u:'+command.client.user : 's:'+command.client.session,
185
+ waitForEvents: true,
186
+ async execute(properties, { client, service }, emit) {
187
+ const owner = client.user ? ['user_User', client.user] : ['session_Session', client.session]
188
+ const id = owner.map(p => JSON.stringify(p)).join(':')
189
+ const entity = await modelRuntime().get(id)
190
+ if(!entity) throw 'not_found'
191
+ let updateObject = {}
192
+ for(const propertyName of writeableProperties) {
193
+ if(properties.hasOwnProperty(propertyName)) {
194
+ updateObject[propertyName] = properties[propertyName]
195
+ }
196
+ }
197
+ const merged = App.utils.mergeDeep({}, entity, updateObject)
198
+ await App.validation.validate(merged, validators, { source: action, action, service, app, client })
199
+ const identifiers = {
200
+ ownerType: 'user_User',
201
+ owner: client.user,
202
+ }
203
+ emit({
204
+ type: eventName,
205
+ identifiers,
206
+ data: properties || {}
207
+ })
208
+ }
209
+ })
210
+ const action = service.actions[actionName]
211
+ const validators = App.validation.getValidators(action, service, action)
212
+ }
213
+
214
+ if(config.ownerResetAccess || config.ownerWriteAccess) {
215
+ const eventName = 'ownerOwned' + modelName + 'Reset'
216
+ const actionName = 'resetMy' + modelName
217
+ service.actions[actionName] = new ActionDefinition({
218
+ name: actionName,
219
+ access: (params, context) => context.client.user
220
+ && (config.ownerResetAccess || config.ownerWriteAccess)(params, context),
221
+ queuedBy: (command) => command.client.user ? 'u:'+command.client.user : 's:'+command.client.session,
222
+ waitForEvents: true,
223
+ async execute(properties, {client, service}, emit) {
224
+ const owner = client.user ? ['user_User', client.user] : ['session_Session', client.session]
225
+ const id = owner.map(p => JSON.stringify(p)).join(':')
226
+ const entity = await modelRuntime().get(id)
227
+ if (!entity) throw 'not_found'
228
+ const identifiers = {
229
+ ownerType: 'user_User',
230
+ owner: client.user,
231
+ }
232
+ emit({
233
+ type: eventName,
234
+ identifiers
235
+ })
236
+ }
237
+ })
238
+ }
239
+
240
+ }
241
+ }
242
+
243
+ })
package/index.js CHANGED
@@ -7,6 +7,8 @@ require('./userProperty.js')
7
7
  require('./userItem.js')
8
8
  require('./sessionOrUserProperty.js')
9
9
  require('./sessionOrUserItem.js')
10
+ require('./contactOrUserProperty.js')
11
+ require('./contactOrUserItem.js')
10
12
 
11
13
  const Session = definition.foreignModel('session', 'Session')
12
14
 
@@ -44,6 +46,10 @@ definition.trigger({
44
46
  async execute({ user, session }, { client, service }, emit) {
45
47
  const userData = await User.get(user)
46
48
  if(!userData) throw 'userNotFound'
49
+ await service.trigger({
50
+ type: 'signedIn',
51
+ session, user
52
+ })
47
53
  emit({
48
54
  type: "signedIn",
49
55
  user, session
@@ -55,6 +61,11 @@ definition.action({
55
61
  name: 'signOut',
56
62
  async execute({ }, { client, service }, emit) {
57
63
  if(!client.user) throw "notSignedIn"
64
+ await service.trigger({
65
+ type: 'signedOut',
66
+ session: client.session,
67
+ user: client.user
68
+ })
58
69
  emit({
59
70
  type: "signedOut",
60
71
  user: client.user,
@@ -78,6 +89,10 @@ definition.trigger({
78
89
  if(!user) {
79
90
  user = app.generateUid()
80
91
  }
92
+ await service.trigger({
93
+ type: 'signedIn',
94
+ session, user
95
+ })
81
96
  emit([{
82
97
  type: "created",
83
98
  user
@@ -98,6 +113,14 @@ definition.action({
98
113
  },
99
114
  async execute({ }, { client, service }, emit) {
100
115
  const user = client.user
116
+ await service.trigger({
117
+ type: 'signedOut',
118
+ session: client.session, user: client.user
119
+ })
120
+ await service.trigger({
121
+ type: 'userDeleted',
122
+ user: client.user
123
+ })
101
124
  await service.trigger({
102
125
  type: 'userDeleted',
103
126
  user
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/user-service",
3
- "version": "0.2.25",
3
+ "version": "0.2.26",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,9 +21,9 @@
21
21
  "url": "https://www.viamage.com/"
22
22
  },
23
23
  "dependencies": {
24
- "@live-change/framework": "0.5.27",
25
- "@live-change/relations-plugin": "^0.5.20",
24
+ "@live-change/framework": "0.6.0",
25
+ "@live-change/relations-plugin": "0.6.0",
26
26
  "pluralize": "8.0.0"
27
27
  },
28
- "gitHead": "4ccbe06b5a1ad1c46a907ac079e31a6d72a8591e"
28
+ "gitHead": "f3d7b9b6c689b9d87df3cb7f64cd75fc72339b7a"
29
29
  }
@@ -30,6 +30,9 @@ definition.processor(function(service, app) {
30
30
  ...config
31
31
  }
32
32
 
33
+ /// TODO: merge on signedIn trigger
34
+ /// TODO: delete on userDeleted trigger
35
+
33
36
  if(config.ownerReadAccess) {
34
37
  const viewName = 'my' + pluralize(modelName)
35
38
  service.views[viewName] = new ViewDefinition({
@@ -50,13 +53,12 @@ definition.processor(function(service, app) {
50
53
  service.views[viewName] = new ViewDefinition({
51
54
  name: viewName,
52
55
  access(params, context) {
53
- if(!context.client.user) return false
54
- return config.userReadAccess ? config.userReadAccess(params, context) : true
56
+ return config.ownerReadAccess(params, context)
55
57
  },
56
58
  properties: App.rangeProperties,
57
59
  daoPath(range, { client, context }) {
58
60
  const owner = client.user ? ['user_User', client.user] : ['session_Session', client.session]
59
- return modelRuntime().sortedIndexRangePath('byOwner' + sortFieldUc, owner, range)
61
+ return modelRuntime().sortedIndexRangePath('byOwner' + sortFieldUc, owner, App.extractRange(range))
60
62
  }
61
63
  })
62
64
  }
@@ -2,6 +2,24 @@ const definition = require("./definition.js")
2
2
  const App = require("@live-change/framework")
3
3
  const { PropertyDefinition, ViewDefinition, IndexDefinition, ActionDefinition, EventDefinition } = App
4
4
  const { User } = require("./model.js")
5
+ const { allCombinations } = require("./combinations.js")
6
+
7
+ const pluralize = require('pluralize')
8
+
9
+ function createIdentifiersProperties(keys) {
10
+ const identifiers = {}
11
+ if(keys) for(const key of keys) {
12
+ identifiers[key] = {
13
+ type: String,
14
+ validation: ['nonEmpty']
15
+ }
16
+ identifiers[key + 'Type'] = {
17
+ type: String,
18
+ validation: ['nonEmpty']
19
+ }
20
+ }
21
+ return identifiers
22
+ }
5
23
 
6
24
  definition.processor(function(service, app) {
7
25
 
@@ -9,8 +27,8 @@ definition.processor(function(service, app) {
9
27
  const model = service.models[modelName]
10
28
 
11
29
  if(model.sessionOrUserProperty) {
12
- console.log("MODEL " + modelName + " IS SESSION OR USER PROPERTY, CONFIG:", model.userProperty)
13
- if (model.properties.owner) throw new Error('owner property already exists!!!')
30
+ console.log("MODEL " + modelName + " IS SESSION OR USER PROPERTY, CONFIG:", model.sessionOrUserProperty)
31
+ if (model.properties.sessionOrUser) throw new Error('sessionOrUser property already exists!!!')
14
32
 
15
33
  const originalModelProperties = { ...model.properties }
16
34
  const modelProperties = Object.keys(model.properties)
@@ -23,26 +41,70 @@ definition.processor(function(service, app) {
23
41
  const config = model.sessionOrUserProperty
24
42
  const writeableProperties = modelProperties || config.writableProperties
25
43
 
44
+ if(model.propertyOf) throw new Error("model " + modelName + " already have owner")
26
45
  if(model.propertyOfAny) throw new Error("model " + modelName + " already have owner")
46
+
47
+ const extendedWith = config.extendedWith
48
+ ? (Array.isArray(config.extendedWith) ? config.extendedWith : [config.extendedWith])
49
+ : []
27
50
  model.propertyOfAny = {
28
- ...config
51
+ ...config,
52
+ to: ['sessionOrUser', ...extendedWith]
29
53
  }
30
54
 
31
- if(config.ownerReadAccess) {
55
+ /// TODO: merge on signedIn trigger
56
+ /// TODO: delete on userDeleted trigger
57
+
58
+
59
+ if(config.ownerReadAccess) { // single item view
32
60
  const viewName = 'my' + modelName
61
+ const identifiers = createIdentifiersProperties(extendedWith)
33
62
  service.views[viewName] = new ViewDefinition({
34
63
  name: viewName,
64
+ properties: {
65
+ ...identifiers
66
+ },
35
67
  access(params, context) {
36
68
  return config.ownerReadAccess ? config.ownerReadAccess(params, context) : true
37
69
  },
38
70
  daoPath(params, { client, context }) {
39
71
  const owner = client.user ? ['user_User', client.user] : ['session_Session', client.session]
72
+ for(const key of extendedWith) {
73
+ owner.push(params[key+'Type'], params[key])
74
+ }
40
75
  const id = owner.map(p => JSON.stringify(p)).join(':')
41
76
  return modelRuntime().path(id)
42
77
  }
43
78
  })
44
79
  }
45
80
 
81
+ if(config.ownerReadAccess && config.extendedWith) {
82
+ const extendedCombinations = [[]].concat(allCombinations(extendedWith).slice(0, -1))
83
+ for(const combination of extendedCombinations) {
84
+ const propsUpperCase = combination.map(prop => prop[0].toUpperCase() + prop.slice(1))
85
+ const indexName = 'by' + (combination).map(prop => prop[0].toUpperCase() + prop.slice(1))
86
+ const viewName = 'my' + propsUpperCase.join('And') + pluralize(modelName)
87
+ const identifiers = createIdentifiersProperties(combination)
88
+ service.views[viewName] = new ViewDefinition({
89
+ name: viewName,
90
+ properties: {
91
+ ...identifiers,
92
+ ...App.rangeProperties,
93
+ },
94
+ access(params, context) {
95
+ return config.ownerReadAccess ? config.ownerReadAccess(params, context) : true
96
+ },
97
+ daoPath(params, {client, context}) {
98
+ const owner = client.user ? ['user_User', client.user] : ['session_Session', client.session]
99
+ for (const key of combination) {
100
+ owner.push(params[key + 'Type'], params[key])
101
+ }
102
+ return modelRuntime().indexRangePath(indexName, owner, App.extractRange(params) )
103
+ }
104
+ })
105
+ }
106
+ }
107
+
46
108
  if(config.ownerViews) {
47
109
  for(const view of config.userViews) {
48
110
  const viewName = view.name || ('my' + (view.prefix || '') + modelName + (view.suffix || ''))
package/userItem.js CHANGED
@@ -30,6 +30,8 @@ definition.processor(function(service, app) {
30
30
  ...config
31
31
  }
32
32
 
33
+ /// TODO: delete on userDeleted trigger
34
+
33
35
  if(config.userReadAccess) {
34
36
  const viewName = 'myUser' + pluralize(modelName)
35
37
  service.views[viewName] = new ViewDefinition({
package/userProperty.js CHANGED
@@ -29,6 +29,8 @@ definition.processor(function(service, app) {
29
29
  ...config
30
30
  }
31
31
 
32
+ /// TODO: delete on userDeleted trigger
33
+
32
34
  if(config.userReadAccess) {
33
35
  const viewName = 'myUser' + modelName
34
36
  service.views[viewName] = new ViewDefinition({