@live-change/user-service 0.2.24 → 0.2.27

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