@webresto/graphql 1.3.7 → 1.3.8

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 (142) hide show
  1. package/.gitattributes +2 -0
  2. package/.gitlab-ci.yml +18 -0
  3. package/.vscode/extensions.json +5 -0
  4. package/docs/actions.md +25 -0
  5. package/docs/authorization.md +215 -0
  6. package/docs/captcha.md +71 -0
  7. package/docs/device-id.md +30 -0
  8. package/docs/messages.md +10 -0
  9. package/docs/user.md +54 -0
  10. package/index.d.ts +0 -1
  11. package/index.js +6 -2
  12. package/index.ts +2 -2
  13. package/lib/afterHook.js +8 -0
  14. package/lib/afterHook.ts +9 -0
  15. package/lib/bindTranslations.d.ts +1 -0
  16. package/lib/bindTranslations.js +40 -0
  17. package/lib/bindTranslations.ts +39 -0
  18. package/lib/defaults.d.ts +1 -0
  19. package/lib/defaults.js +49 -10
  20. package/lib/defaults.ts +55 -0
  21. package/lib/eventHelper.d.ts +14 -5
  22. package/lib/eventHelper.js +28 -9
  23. package/lib/eventHelper.ts +41 -8
  24. package/lib/getRecomended.d.ts +1 -0
  25. package/lib/getRecomended.js +29 -0
  26. package/lib/getRecomended.ts +31 -0
  27. package/lib/graphqlHelper.d.ts +3 -4
  28. package/lib/graphqlHelper.js +184 -72
  29. package/lib/graphqlHelper.ts +329 -185
  30. package/lib/jwt.d.ts +10 -0
  31. package/lib/jwt.js +43 -0
  32. package/lib/jwt.ts +61 -0
  33. package/package.json +13 -6
  34. package/src/additionalResolvers.d.ts +72 -9
  35. package/src/additionalResolvers.js +93 -24
  36. package/src/additionalResolvers.ts +105 -34
  37. package/src/graphql.d.ts +5 -3
  38. package/src/graphql.js +170 -37
  39. package/src/graphql.ts +210 -60
  40. package/src/resolvers/bonusProgram.d.ts +32 -0
  41. package/src/resolvers/bonusProgram.js +65 -0
  42. package/src/resolvers/bonusProgram.ts +79 -0
  43. package/src/resolvers/captcha.d.ts +11 -0
  44. package/src/resolvers/captcha.js +19 -0
  45. package/src/resolvers/captcha.ts +16 -0
  46. package/src/resolvers/checkout.d.ts +35 -16
  47. package/src/resolvers/checkout.js +171 -94
  48. package/src/resolvers/checkout.ts +214 -104
  49. package/src/resolvers/dishAndModifier.js +8 -4
  50. package/src/resolvers/dishAndModifier.ts +4 -0
  51. package/src/resolvers/error.d.ts +9 -0
  52. package/src/resolvers/error.js +21 -0
  53. package/src/resolvers/error.ts +21 -0
  54. package/src/resolvers/menu.d.ts +9 -0
  55. package/src/resolvers/menu.js +12 -0
  56. package/src/resolvers/menu.ts +10 -0
  57. package/src/resolvers/order.d.ts +527 -0
  58. package/src/resolvers/order.js +349 -0
  59. package/src/resolvers/order.ts +435 -0
  60. package/src/resolvers/paymentMethod.js +7 -3
  61. package/src/resolvers/paymentMethod.ts +9 -5
  62. package/src/resolvers/pickupPoint.d.ts +1 -0
  63. package/src/resolvers/pickupPoint.js +24 -0
  64. package/src/resolvers/pickupPoint.ts +23 -0
  65. package/src/resolvers/recomended.d.ts +13 -0
  66. package/src/resolvers/recomended.js +80 -0
  67. package/src/resolvers/recomended.ts +86 -0
  68. package/src/resolvers/restrictions.d.ts +37 -1
  69. package/src/resolvers/restrictions.js +100 -15
  70. package/src/resolvers/restrictions.ts +106 -14
  71. package/src/resolvers/streets.d.ts +1 -1
  72. package/src/resolvers/streets.js +1 -4
  73. package/src/resolvers/streets.ts +1 -3
  74. package/src/resolvers/subscriptions.d.ts +4 -4
  75. package/src/resolvers/subscriptions.js +49 -12
  76. package/src/resolvers/subscriptions.ts +59 -14
  77. package/src/resolvers/telemetry.d.ts +14 -0
  78. package/src/resolvers/telemetry.js +25 -0
  79. package/src/resolvers/telemetry.ts +24 -0
  80. package/src/resolvers/user.d.ts +82 -0
  81. package/src/resolvers/user.js +416 -0
  82. package/src/resolvers/user.ts +621 -0
  83. package/src/resolvers/userLocation.d.ts +53 -0
  84. package/src/resolvers/userLocation.js +74 -0
  85. package/src/resolvers/userLocation.ts +125 -0
  86. package/src/resolvers/userOTPrequest.d.ts +21 -0
  87. package/src/resolvers/userOTPrequest.js +57 -0
  88. package/src/resolvers/userOTPrequest.ts +75 -0
  89. package/test/e2e_helper.js +157 -0
  90. package/test/e2e_helper.ts +212 -0
  91. package/test/fixture/config/i18n.js +7 -20
  92. package/test/fixture/config/locales/de.json +1 -0
  93. package/test/fixture/config/locales/en.json +10 -0
  94. package/test/fixture/config/locales/es.json +3 -0
  95. package/test/fixture/config/locales/fr.json +1 -0
  96. package/test/fixture/config/log.js +1 -1
  97. package/test/fixture/package.json +5 -6
  98. package/test/fixture/patches/rttc+10.0.1.patch +17 -0
  99. package/test/integration/captcha.test.js +20 -0
  100. package/test/integration/captcha.test.ts +25 -0
  101. package/test/integration/dish.test.js +35 -0
  102. package/test/integration/dish.test.ts +43 -0
  103. package/test/integration/graphql.test.js +5 -2
  104. package/test/integration/graphql.test.ts +2 -4
  105. package/test/integration/images.test.js +35 -0
  106. package/test/integration/images.test.ts +40 -0
  107. package/test/integration/locale.test.js +26 -0
  108. package/test/integration/locale.test.ts +32 -0
  109. package/test/integration/order.test.js +56 -43
  110. package/test/integration/order.test.ts +59 -59
  111. package/test/integration/subscriptions.test.js +136 -0
  112. package/test/integration/subscriptions.test.ts +162 -0
  113. package/test/integration/user.test.js +249 -0
  114. package/test/integration/user.test.ts +299 -0
  115. package/test/unit/first.test.js +4 -2
  116. package/test/unit/first.test.ts +1 -1
  117. package/test/unit/get-recomended.test.js +56 -0
  118. package/test/unit/get-recomended.test.ts +63 -0
  119. package/translations/de.json +2 -0
  120. package/translations/en.json +3 -0
  121. package/translations/es.json +3 -0
  122. package/translations/fr.json +2 -0
  123. package/translations/ru.json +36 -0
  124. package/tsconfig.json +20 -5
  125. package/types/global.d.ts +30 -0
  126. package/types/global.js +2 -0
  127. package/types/global.ts +31 -0
  128. package/types/primitives.d.ts +19 -0
  129. package/types/references.d.ts +1 -0
  130. package/types/restoGraphQLConfig.d.ts +13 -0
  131. package/lib/afterHook.ts___graphql-transport-ws +0 -138
  132. package/lib/afterHook.ts___graphql-ws +0 -133
  133. package/lib/errorWrapper.d.ts +0 -4
  134. package/lib/errorWrapper.js +0 -13
  135. package/lib/errorWrapper.ts +0 -12
  136. package/notes.md +0 -1976
  137. package/src/resolvers/cart.d.ts +0 -343
  138. package/src/resolvers/cart.js +0 -196
  139. package/src/resolvers/cart.ts +0 -278
  140. package/test/fixture/config/connections.js +0 -9
  141. package/test/integration/sails_not_crash.test.js +0 -3
  142. package/test/integration/sails_not_crash.test.ts +0 -3
@@ -1,23 +1,18 @@
1
- /// <reference path="../../core/libs/globalTypes.ts"/>
2
-
3
1
  import _ = require("lodash");
4
- import { WorkTimeValidator} from '@webresto/worktime'
5
- import getEmitter from "@webresto/core/libs/getEmitter";
2
+ import { WorkTimeValidator } from '@webresto/worktime'
3
+
6
4
  import * as WLCriteria from 'waterline-criteria';
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
-
11
- const scalarTypes = {
12
- string: "String",
13
- text: "String",
14
- date: "String",
15
- datetime: "String",
16
- integer: "Int",
17
- float: "Float",
18
- boolean: "Boolean",
19
- // "json": "Json",
20
- // "array": "Array",
5
+ import { JWTAuth } from "./jwt";
6
+
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+
10
+ const scalarTypes = {
11
+ string: "String",
12
+ number: "Float",
13
+ boolean: "Boolean",
14
+ // json: "Json",
15
+ // "array": "Array",
21
16
  }
22
17
 
23
18
  /*
@@ -75,30 +70,31 @@ const models: Set<string> = new Set();
75
70
  * @returns void
76
71
  */
77
72
 
78
- function addModel (modelName: string) {
79
- modelName = firstLetterToUpperCase(modelName);
80
- if (blackList.includes(modelName)) {
81
- // schemaScalars.add(modelName);
82
- return;
83
- }
84
- models.add(modelName.toLowerCase());
73
+ function addModel(modelName: string) {
74
+ modelName = firstLetterToUpperCase(modelName);
75
+ if (blackList.includes(modelName)) {
76
+ // schemaScalars.add(modelName);
77
+ return;
78
+ }
79
+ models.add(modelName.toLowerCase());
85
80
  }
86
- function addType (typeString: String) {
87
- schemaTypes.push(typeString);
81
+
82
+ function addType(type: string) {
83
+ schemaTypes.push(type);
88
84
  }
89
85
  /**
90
86
  * Мержит новый резолвер с объектом резолверов. Новый резолвер заменит старый при совпадении имен
91
87
  *
92
88
  * @param resolvers
93
89
  * resolverExample = {
94
- * def: "user(id: String)",
90
+ * def: "user(id: string)",
95
91
  * fn: function (parent, args, context) {
96
92
  * return User.find({id: args.id})
97
93
  * }
98
94
  * }
99
95
  */
100
- function addResolvers (resolvers: Object) {
101
- _.merge(schemaResolvers, resolvers);
96
+ function addResolvers(resolvers: Object) {
97
+ _.merge(schemaResolvers, resolvers);
102
98
  }
103
99
 
104
100
  /**
@@ -107,7 +103,7 @@ function addResolvers (resolvers: Object) {
107
103
  function addAllSailsModels() {
108
104
  Object.keys(sails.models).forEach((key) => {
109
105
  if (key.includes("__")) return;
110
- if (sails.models[key].graphql && sails.models[key].graphql.public === false){
106
+ if (sails.models[key].graphql && sails.models[key].graphql.public === false) {
111
107
  addToBlackList([key]);
112
108
  return;
113
109
  }
@@ -125,12 +121,12 @@ function addAllSailsModels() {
125
121
  * @param list array<string>
126
122
  */
127
123
  function addToBlackList(list: Array<string>) {
128
- blackList.push(...list);
124
+ blackList.push(...list);
129
125
  }
130
126
 
131
127
  /**
132
128
  * Добавляет в указаную модель новое поле
133
- * Пример: addCustomField("Order", "customField: String")
129
+ * Пример: addCustomField("Order", "customField: string")
134
130
  *
135
131
  * @param model string
136
132
  * @param field string
@@ -148,7 +144,7 @@ function addCustomField(model, field) {
148
144
  * @param field string
149
145
  */
150
146
  function addToReplaceList(model, field) {
151
- replaceList[model] = field;
147
+ replaceList[model] = field;
152
148
  }
153
149
 
154
150
  /**
@@ -174,7 +170,7 @@ function addDirResolvers(dir) {
174
170
  *
175
171
  * @returns {schemaTypes, schemaResolvers}
176
172
  */
177
- function getSchema () {
173
+ function getSchema() {
178
174
  Object.keys(whiteList).forEach(modelname => {
179
175
  if (sails.models[modelname]?.graphql?.public !== false) {
180
176
  addModelResolver(modelname);
@@ -182,7 +178,7 @@ function getSchema () {
182
178
  });
183
179
 
184
180
  addResolvers(modelsResolvers);
185
- return createSchema({types: schemaTypes, resolvers: schemaResolvers});
181
+ return createSchema({ types: schemaTypes, resolvers: schemaResolvers });
186
182
  }
187
183
 
188
184
  function firstLetterToUpperCase(string) {
@@ -213,26 +209,37 @@ function createType(model) {
213
209
 
214
210
  let scalarType;
215
211
  if (attributes[prop].type) {
216
- if (scalarTypes[attributes[prop].type.toLowerCase()]) {
217
- scalarType = scalarTypes[attributes[prop].type.toLowerCase()];
212
+
213
+ // TODO: make method add AddModelFieldType(path, type) for pass custom type for specific model
214
+ if (modelName.toLowerCase() === "user" && prop === "phone") {
215
+ scalarType = "Phone"
218
216
  } else {
219
- scalarType = firstLetterToUpperCase(attributes[prop].type);
220
- schemaScalars.add(scalarType);
217
+ if (scalarTypes[attributes[prop].type.toLowerCase()]) {
218
+ scalarType = scalarTypes[attributes[prop].type.toLowerCase()];
219
+ } else {
220
+ scalarType = firstLetterToUpperCase(attributes[prop].type);
221
+ schemaScalars.add(scalarType);
222
+ }
221
223
  }
222
224
  type += ' ' + prop + ': ' + scalarType + '\n';
223
225
  }
224
-
226
+
225
227
  // MODEL SCHEMA GENERATION
226
228
  if (attributes[prop].model) {
227
229
  let relationModel = sails.models[attributes[prop].model.toLowerCase()]
228
- scalarType = scalarTypes[relationModel.attributes[relationModel.primaryKey].type]
230
+ scalarType = scalarTypes[relationModel.attributes[relationModel.primaryKey].type.toLowerCase()]
229
231
  const name = sails.models[attributes[prop].model.toLowerCase()].globalId;
230
232
  type += ` ${prop}: ${name}\n`;
233
+
234
+ // Virtual Id field
235
+ type += ` ${prop}Id: ${scalarType}\n`;
236
+
231
237
  }
232
238
 
233
239
  // COLLECTION SCHEMA GENERATION
234
240
  if (attributes[prop].collection) {
235
- scalarType = scalarTypes[attributes[sails.models[attributes[prop].collection.toLowerCase()].primaryKey].type.toLowerCase()]
241
+ let collectionModel = sails.models[attributes[prop].collection.toLowerCase()];
242
+ scalarType = scalarTypes[collectionModel.attributes[collectionModel.primaryKey].type.toLowerCase()];
236
243
  const name = sails.models[attributes[prop].collection.toLowerCase()].globalId;
237
244
  type += ` ${prop}: [${name}]\n`;
238
245
  }
@@ -241,7 +248,7 @@ function createType(model) {
241
248
  type += ` ${customFields[modelName]}\n`;
242
249
  }
243
250
  if (!attributes.customData) {
244
- type += '""" autogenerated """ customData: Json';
251
+ type += `""" [autogenerated] ${isAuthRequired(modelName) ? '\n[auth required]' : ''}""" customData: Json`;
245
252
  }
246
253
  type += '}\n';
247
254
  return type;
@@ -308,10 +315,9 @@ function createSchema(typeDefsObj) {
308
315
  const whiteList = {
309
316
  // group: ['subscription', 'query'] // order - modelname , 'subscription' - resolver type
310
317
  }
311
- const userAuth = typeof sails.config.restographql?.authService === 'function' ? sails.config.restographql.authService : null;
312
318
 
313
- let modelsResolvers: {Query?: Object, Subscription?: Object} = { Query: {}};
314
- const { withFilter } = require("apollo-server");
319
+ let modelsResolvers: { Query?: Object, Subscription?: Object } = { Query: {} };
320
+ import { withFilter } from "apollo-server";
315
321
 
316
322
  /**
317
323
  * Патчит waterline criteria во время автогенерации
@@ -322,17 +328,17 @@ const { withFilter } = require("apollo-server");
322
328
  */
323
329
  function sanitizeCriteria(modelname, criteria) {
324
330
 
325
- if (sails.models[modelname].attributes.enable){
331
+ if (sails.models[modelname].attributes.enable) {
326
332
  criteria.enable = true;
327
333
  }
328
334
 
329
- if (sails.models[modelname].attributes.isDeleted){
335
+ if (sails.models[modelname].attributes.isDeleted) {
330
336
  criteria.isDeleted = false;
331
337
  }
332
338
 
333
339
  switch (modelname) {
334
340
  case 'dish':
335
- criteria.balance = {'!=': 0};
341
+ criteria.balance = { '!=': 0 };
336
342
  criteria.isDeleted = false;
337
343
  break;
338
344
  case 'group':
@@ -376,52 +382,81 @@ function addModelResolver(modelname) {
376
382
  models.add(modelname); // make schema Type for Model
377
383
  const methodName = firstLetterToLowerCase(modelName)
378
384
  let resolverQuery = {
379
- def: `""" autogenerated """ ${methodName}(criteria: Json): [${modelName}]`,
385
+ def: `""" [autogenerated] ${isAuthRequired(modelname) ? '\n[auth required]' : ''}""" ${methodName}(criteria: Json, skip: Int, limit: Int, sort: String): [${modelName}]`,
380
386
  fn: async function (parent, args, context) {
381
387
 
382
388
  let criteria = args.criteria || {};
383
389
  criteria = sanitizeCriteria(modelname, criteria);
384
390
 
385
391
  // If model has User field need auth
386
- if (sails.models[modelname].attributes.user) {
387
- if (userAuth) {
388
- let user = await userAuth(
389
- context.connectionParams.authorization
390
- );
391
- if (user.id) {
392
- criteria.user = user.id;
393
- } else return null;
392
+ if (isAuthRequired(modelName)) {
393
+ let auth = await JWTAuth.verify(
394
+ context.connectionParams.authorization
395
+ );
396
+
397
+ if (auth.userId && UserDevice.checkSession(auth.sessionId, auth.userId, { lastIP: "IP", userAgent: context.connectionParams["user-agent"] })) {
398
+ if (modelName.toLowerCase() === "user") {
399
+ criteria.id = auth.userId
400
+ } else {
401
+ criteria.user = auth.userId
402
+ }
394
403
  } else {
395
- return null;
404
+ throw 'Authorization failed'
396
405
  }
397
406
  }
398
407
 
399
- let query: any = { where: criteria};
408
+
409
+ let query: any;
410
+ if (criteria.where === undefined) {
411
+ query = { where: criteria }
412
+ } else {
413
+ query = criteria
414
+ }
415
+
400
416
  //sorting
401
- if (sails.models[modelname].attributes.order) {
402
- query.sort = 'order ASC'
417
+ if (sails.models[modelname].attributes.sortOrder) {
418
+ query.sort = 'sortOrder ASC'
403
419
  }
404
420
 
405
- let result = await sails.models[modelname].find(query);
406
421
 
407
- getEmitter().emit(`graphql-query-${modelname}`, result);
422
+ let ORMrequest = sails.models[modelname].find(query);
423
+
424
+ if (args.skip) {
425
+ ORMrequest.skip(args.skip)
426
+ }
427
+
428
+ if (args.limit) {
429
+ ORMrequest.limit(args.limit)
430
+ }
431
+
432
+ if (args.sort) {
433
+ ORMrequest.sort(args.sort)
434
+ } else {
435
+ if (sails.models[modelname].attributes.sortOrder) {
436
+ ORMrequest.sort('sortOrder ASC')
437
+ }
438
+ }
408
439
 
409
- //workTime filter
440
+ let result = await ORMrequest
410
441
 
411
- if (sails.models[modelname].attributes.workTime) {
442
+ emitter.emit(`graphql-query-${modelname}`, result);
443
+
444
+ //worktime filter
445
+
446
+ if (sails.models[modelname].attributes.worktime) {
412
447
  result = result.filter(record => {
413
- if (!record.workTime) return true;
448
+ if (!record.worktime) return true;
414
449
  try {
415
- return (WorkTimeValidator.isWorkNow({workTime: record.workTime})).workNow
450
+ return (WorkTimeValidator.isWorkNow({ worktime: record.worktime })).workNow
416
451
  } catch (error) {
417
- sails.log.error("Graphql > helper > error: ",error)
452
+ sails.log.error("Graphql > helper > error: ", error)
418
453
  }
419
454
  })
420
455
  }
421
456
 
422
457
  result.forEach(item => {
423
458
 
424
- getEmitter().emit(
459
+ emitter.emit(
425
460
  `http-api:before-send-${modelname.toLowerCase()}`,
426
461
  item
427
462
  );
@@ -431,105 +466,206 @@ function addModelResolver(modelname) {
431
466
  },
432
467
  };
433
468
  modelsResolvers.Query[methodName] = resolverQuery;
469
+
470
+
471
+ let resolverQueryCount = {
472
+ def: `""" [autogenerated] ${isAuthRequired(modelname) ? '\n[auth required]' : ''}""" ${methodName}Count(criteria: Json): Int`,
473
+ fn: async function (parent, args, context) {
474
+
475
+ let criteria = args.criteria || {};
476
+ criteria = sanitizeCriteria(modelname, criteria);
477
+
478
+ // If model has User field need auth
479
+ if (isAuthRequired(modelName)) {
480
+ let auth = await JWTAuth.verify(
481
+ context.connectionParams.authorization
482
+ );
483
+
484
+ if (auth.userId && UserDevice.checkSession(auth.sessionId, auth.userId, { lastIP: "IP", userAgent: context.connectionParams["user-agent"] })) {
485
+ if (modelName.toLowerCase() === "user") {
486
+ criteria.id = auth.userId
487
+ } else {
488
+ criteria.user = auth.userId
489
+ }
490
+ } else {
491
+ throw 'Authorization failed'
492
+ }
493
+ }
494
+
495
+
496
+ let query: any;
497
+ if (criteria.where === undefined) {
498
+ query = { where: criteria }
499
+ } else {
500
+ query = criteria
501
+ }
502
+
503
+
504
+
505
+ let ORMrequest = sails.models[modelname].find(query);
506
+
507
+ let result = await ORMrequest
508
+
509
+ //worktime filter
510
+ if (sails.models[modelname].attributes.worktime) {
511
+ result = result.filter(record => {
512
+ if (!record.worktime) return true;
513
+ try {
514
+ return (WorkTimeValidator.isWorkNow({ worktime: record.worktime })).workNow
515
+ } catch (error) {
516
+ sails.log.error("Graphql > helper > error: ", error)
517
+ }
518
+ })
519
+ }
520
+
521
+ return result.length;
522
+ },
523
+ };
524
+
525
+ modelsResolvers.Query[`${methodName}Count`] = resolverQueryCount;
526
+
434
527
  }
435
- // Model fields resolvers
436
- let resolvers = {};
437
- // iterate separate resolvers in model (type])
438
- Object.keys(sails.models[modelname].attributes).forEach((key) => {
439
- if (key.includes("__")) return;
440
- if (blackList.includes(`${modelName}.${key}`) || blackList.includes(`${key}`)) return;
441
- if (typeof sails.models[modelname].attributes[key] === 'function') return;
442
-
443
- if (sails.models[modelname].attributes[key].graphql) {
444
- if (sails.models[modelname].attributes[key].graphql.public === false)
445
- return;
446
- }
528
+ // Model fields resolvers
529
+ let resolvers = {};
530
+ // iterate separate resolvers in model (type])
531
+ Object.keys(sails.models[modelname].attributes).forEach((key) => {
532
+ if (key.includes("__")) return;
533
+ if (blackList.includes(`${modelName}.${key}`) || blackList.includes(`${key}`)) return;
534
+ if (typeof sails.models[modelname].attributes[key] === 'function') return;
535
+
536
+ if (sails.models[modelname].attributes[key].graphql) {
537
+ if (sails.models[modelname].attributes[key].graphql.public === false)
538
+ return;
539
+ }
447
540
 
448
- let modelAttribute = sails.models[modelname].attributes[key];
541
+ let modelAttribute = sails.models[modelname].attributes[key];
449
542
 
450
- if (modelAttribute.collection || modelAttribute.model) {
451
- let modelRelationType = modelAttribute.collection
452
- ? "collection"
453
- : "model";
543
+ if (modelAttribute.collection || modelAttribute.model) {
544
+ let modelRelationType = modelAttribute.collection
545
+ ? "collection"
546
+ : "model";
454
547
 
455
- let relationKey =
456
- modelAttribute.via !== undefined
457
- ? modelAttribute.via
458
- : "id";
548
+ let relationKey =
549
+ modelAttribute.via !== undefined
550
+ ? modelAttribute.via
551
+ : "id";
459
552
 
460
- let criteria = {};
461
- criteria = sanitizeCriteria(modelAttribute[modelRelationType], criteria);
553
+ let criteria = {};
554
+ criteria = sanitizeCriteria(modelAttribute[modelRelationType], criteria);
462
555
 
463
- switch (modelRelationType) {
464
- case "model":
465
- resolvers[key] = async (parent, args, context) => {
466
- criteria[relationKey] = parent[key];
467
- let result = await sails.models[modelAttribute[modelRelationType]].findOne(criteria);
556
+ switch (modelRelationType) {
557
+ case "model":
558
+ resolvers[key] = async (parent, args, context) => {
559
+ criteria[relationKey] = parent[key];
468
560
 
469
- // TODO: this need only for support legacy patching (discount)
470
- getEmitter().emit(
471
- `http-api:before-send-${modelAttribute.model.toLowerCase()}`,
472
- result
561
+ // Check access rights
562
+ if (isAuthRequired(modelAttribute[modelRelationType])) {
563
+ let auth = await JWTAuth.verify(
564
+ context.connectionParams.authorization
473
565
  );
474
566
 
475
- // celan if not work time
476
- if (result && result.workTime && !WorkTimeValidator.isWorkNow({workTime: result.workTime}).workNow) {
477
- result = null;
567
+ if (auth.userId && UserDevice.checkSession(auth.sessionId, auth.userId, { lastIP: "IP", userAgent: context.connectionParams["user-agent"] })) {
568
+ if (modelName.toLowerCase() === "user") {
569
+ criteria["id"] = auth.userId
570
+ } else {
571
+ criteria["user"] = auth.userId
572
+ }
573
+ } else {
574
+ throw 'Authorization failed'
478
575
  }
479
- };
480
-
481
- return;
482
- case "collection":
483
- resolvers[key] = async (parent, args, context) => {
576
+ }
484
577
 
578
+ let result = await sails.models[modelAttribute[modelRelationType]].findOne(criteria);
485
579
 
486
- let subcriteria: any = {};
580
+ // TODO: this need only for support legacy patching (discount)
581
+ emitter.emit(
582
+ `http-api:before-send-${modelAttribute.model.toLowerCase()}`,
583
+ result
584
+ );
487
585
 
488
- let subquery: any = { where: criteria};
489
- //sorting
490
- if (sails.models[modelname].attributes.order) {
491
- subquery.sort = 'order ASC'
492
- }
586
+ // celan if not work time
587
+ if (result && result.worktime && !WorkTimeValidator.isWorkNow({ worktime: result.worktime }).workNow) {
588
+ result = null;
589
+ }
590
+ return result;
591
+ };
493
592
 
494
- let result = (await sails.models[modelname].findOne({id: parent.id}).populate(key, subquery));
495
- result = result ? result[key] : null;
496
-
497
- // TODO: this need only for support legacy patching (discount)
498
- if (result && result.length){
499
- result.forEach(item => {
500
- getEmitter().emit(
501
- `http-api:before-send-${modelAttribute.collection.toLowerCase()}`,
502
- item
503
- );
504
- });
505
- }
593
+ // add virtual ids
594
+ resolvers[`${key}Id`] = async (parent, args, context) => {
595
+ return parent && parent[key];
596
+ };
597
+
598
+ return;
599
+ case "collection":
600
+ resolvers[key] = async (parent, args, context) => {
601
+ let parentPrimaryKey = sails.models[modelname].primaryKey
602
+ let criteria = {}
603
+ criteria[relationKey] = parent[parentPrimaryKey];
604
+
605
+ // Check access rights
606
+ if (isAuthRequired(modelAttribute[modelRelationType])) {
607
+ let auth = await JWTAuth.verify(
608
+ context.connectionParams.authorization
609
+ );
506
610
 
507
- if (sails.models[modelname].attributes.workTime && Array.isArray(result)) {
508
- result = result.filter(record => {
509
- if (!record.workTime) return true
510
- try {
511
- return (WorkTimeValidator.isWorkNow({workTime: record.workTime})).workNow
512
- } catch (error) {
513
- sails.log.error("Graphql > helper > error: ",error)
514
- }
515
- });
611
+ if (auth.userId && UserDevice.checkSession(auth.sessionId, auth.userId, { lastIP: "IP", userAgent: context.connectionParams["user-agent"] })) {
612
+ if (modelName.toLowerCase() === "user") {
613
+ criteria["id"] = auth.userId
614
+ } else {
615
+ criteria["user"] = auth.userId
616
+ }
617
+ } else {
618
+ throw 'Authorization failed'
516
619
  }
517
- return result;
518
- };
620
+ }
519
621
 
520
- return;
521
- default:
522
- // empty
523
- break;
524
- }
622
+ let result: any = null;
623
+
624
+
625
+ result = (await sails.models[modelname].findOne({ id: parent.id }).populate(key))[key];
626
+ if (result && sails.models[modelAttribute[modelRelationType]].attributes.sortOrder) {
627
+ result.sort((a, b) => a.sortOrder - b.sortOrder);
628
+ }
629
+
630
+ if (!result) result = []
631
+
632
+ // TODO: this need only for support legacy patching (discount)
633
+ if (result && result.length) {
634
+ result.forEach(item => {
635
+ emitter.emit(
636
+ `http-api:before-send-${modelAttribute.collection.toLowerCase()}`,
637
+ item
638
+ );
639
+ });
640
+ }
641
+
642
+ if (sails.models[modelAttribute[modelRelationType]].attributes.worktime && Array.isArray(result) && result.length > 0) {
643
+ result = result.filter(record => {
644
+ if (!record.worktime) return true
645
+ try {
646
+ return (WorkTimeValidator.isWorkNow({ worktime: record.worktime })).workNow
647
+ } catch (error) {
648
+ sails.log.error("Graphql > helper > error: ", error)
649
+ }
650
+ });
651
+ }
652
+
653
+ return result;
654
+ };
655
+
656
+ return;
657
+ default:
658
+ // empty
659
+ break;
525
660
  }
661
+ }
526
662
 
527
- resolvers[key] = async (parent, args, context) => {
528
- return parent && parent[key];
529
- };
530
- });
663
+ resolvers[key] = async (parent, args, context) => {
664
+ return parent && parent[key];
665
+ };
666
+ });
531
667
 
532
- modelsResolvers[modelName] = resolvers;
668
+ modelsResolvers[modelName] = resolvers;
533
669
 
534
670
 
535
671
  // Subscription resolver
@@ -537,7 +673,7 @@ function addModelResolver(modelname) {
537
673
  models.add(modelname);
538
674
  const methodName = `${firstLetterToLowerCase(modelName)}`;
539
675
  let subscription = {
540
- def: `""" Generated """ ${methodName}(criteria: Json): ${modelName}`,
676
+ def: `""" [autogenerated] ${isAuthRequired(modelname) ? '\n[auth required]' : ''} """ ${methodName}(criteria: Json): ${modelName} `,
541
677
  fn: {
542
678
  subscribe: withFilter(
543
679
  (rootValue, args, context, info) =>
@@ -545,38 +681,42 @@ function addModelResolver(modelname) {
545
681
  async (payload, args, context, info) => {
546
682
 
547
683
  // For User models
548
- if (sails.models[modelname].attributes.user) {
549
- if (userAuth) {
550
- let user = await userAuth(
551
- context.connectionParams.authorization
552
- );
553
- if (user.id === payload.user){
554
- if (args.criteria) {
555
- checkCriteria(payload, args.criteria)
556
- } else {
557
- return true;
558
- }
559
- };
684
+ if (sails.models[modelname].attributes.user || modelname === 'user') {
685
+
686
+ let auth = await JWTAuth.verify(
687
+ context.connectionParams.authorization
688
+ );
689
+
690
+ if (!args.criteria) {
691
+ args.criteria = {}
692
+ }
693
+
694
+ if (auth.userId) {
695
+ if (modelName.toLowerCase() === "user") {
696
+ args.criteria.id = auth.userId
697
+ } else {
698
+ args.criteria.user = auth.userId
699
+ }
560
700
  } else {
561
- return false;
701
+ throw 'Authorization failed'
562
702
  }
563
703
  }
564
704
 
565
705
  return checkCriteria(payload, args.criteria)
566
-
706
+
567
707
  // Filter by waterline criteria
568
- function checkCriteria(payload: any, criteria: any): boolean{
708
+ function checkCriteria(payload: any, criteria: any): boolean {
569
709
 
570
710
  // For id's array
571
- if (Array.isArray(criteria) || typeof criteria === "string"){
572
- return (WLCriteria(payload, { where: { id: criteria }}).results).length > 0
711
+ if (Array.isArray(criteria) || typeof criteria === "string") {
712
+ return (WLCriteria(payload, { where: { id: criteria } }).results).length > 0
573
713
  }
574
714
 
575
715
  // Where cause
576
- if ( typeof criteria === 'object' && !Array.isArray(criteria) && criteria !== null ) {
716
+ if (typeof criteria === 'object' && !Array.isArray(criteria) && criteria !== null) {
577
717
  return (WLCriteria(payload, { where: criteria }).results).length > 0
578
718
  }
579
-
719
+
580
720
  return false
581
721
  }
582
722
 
@@ -604,23 +744,23 @@ function modelPublishExtend(modelname) {
604
744
  let modelName = sails.models[modelname].globalId;
605
745
 
606
746
  let afterCreate = sails.models[modelname].afterCreate;
607
- sails.models[modelname].afterCreate = async function (values, cb ) {
608
- await sails.models[modelname].publish(values.id);
609
- if (afterCreate) {
610
- afterCreate(values, cb);
611
- } else {
612
- cb();
613
- }
747
+ sails.models[modelname].afterCreate = async function (values, cb) {
748
+ await sails.models[modelname].publish(values.id);
749
+ if (afterCreate) {
750
+ afterCreate(values, cb);
751
+ } else {
752
+ cb();
753
+ }
614
754
  };
615
755
 
616
756
  let afterUpdate = sails.models[modelname].afterUpdate;
617
- sails.models[modelname].afterUpdate = async function (values, cb ) {
618
- await sails.models[modelname].publish(values.id);
619
- if (afterUpdate) {
620
- afterUpdate(values, cb);
621
- } else {
622
- cb();
623
- }
757
+ sails.models[modelname].afterUpdate = async function (values, cb) {
758
+ await sails.models[modelname].publish(values.id);
759
+ if (afterUpdate) {
760
+ afterUpdate(values, cb);
761
+ } else {
762
+ cb();
763
+ }
624
764
  };
625
765
 
626
766
  let modelPublishExtendObj = {
@@ -628,7 +768,7 @@ function modelPublishExtend(modelname) {
628
768
  let data = await sails.models[modelname].findOne(id);
629
769
  // `http-api:request-${modelAttribute.collection.toLowerCase()}model-list`,
630
770
 
631
- getEmitter().emit(`http-api:before-send-${modelname.toLowerCase()}`, data);
771
+ emitter.emit(`http-api:before-send-${modelname.toLowerCase()}`, data);
632
772
  sails.graphql.pubsub.publish(modelName, data);
633
773
  },
634
774
  };
@@ -636,6 +776,10 @@ function modelPublishExtend(modelname) {
636
776
  _.merge(sails.models[modelname], modelPublishExtendObj);
637
777
  }
638
778
 
779
+ function isAuthRequired(modelname: string): Boolean {
780
+ modelname = modelname.toLowerCase();
781
+ return sails.models[modelname].attributes.user !== undefined || modelname === 'user';
782
+ }
639
783
 
640
784
  export default {
641
785
  addModel,