@qikdev/sdk 0.1.169 → 0.1.180

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 (71) hide show
  1. package/.gitlab-ci.yml +24 -0
  2. package/dist/main.js +1 -1
  3. package/jsdoc.conf +10 -0
  4. package/package.json +5 -24
  5. package/public/docs/access.html +3826 -0
  6. package/public/docs/api.html +1356 -0
  7. package/public/docs/auth.html +2180 -0
  8. package/public/docs/cache.html +351 -0
  9. package/public/docs/content.html +2560 -0
  10. package/public/docs/files.html +779 -0
  11. package/public/docs/filter.html +1355 -0
  12. package/public/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  13. package/public/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  14. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  15. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  16. package/public/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  17. package/public/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  18. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  19. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  20. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  21. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  22. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  23. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  24. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  25. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  26. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  27. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  28. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  29. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  30. package/public/docs/index.html +96 -0
  31. package/public/docs/qik.access.js.html +790 -0
  32. package/public/docs/qik.api.js.html +511 -0
  33. package/public/docs/qik.auth.js.html +1006 -0
  34. package/public/docs/qik.cache.js.html +131 -0
  35. package/public/docs/qik.content.js.html +918 -0
  36. package/public/docs/qik.core.js.html +301 -0
  37. package/public/docs/qik.files.js.html +219 -0
  38. package/public/docs/qik.filter.js.html +611 -0
  39. package/public/docs/qik.socket.js.html +416 -0
  40. package/public/docs/qik.system.js.html +117 -0
  41. package/public/docs/qik.utils.js.html +1467 -0
  42. package/public/docs/scripts/collapse.js +20 -0
  43. package/public/docs/scripts/linenumber.js +25 -0
  44. package/public/docs/scripts/nav.js +12 -0
  45. package/public/docs/scripts/polyfill.js +4 -0
  46. package/public/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  47. package/public/docs/scripts/prettify/lang-css.js +2 -0
  48. package/public/docs/scripts/prettify/prettify.js +28 -0
  49. package/public/docs/scripts/search.js +83 -0
  50. package/public/docs/socket.html +810 -0
  51. package/public/docs/styles/jsdoc.css +765 -0
  52. package/public/docs/styles/prettify.css +79 -0
  53. package/public/docs/system.html +197 -0
  54. package/src/api/qik.access.js +790 -0
  55. package/src/api/qik.api.js +431 -0
  56. package/src/api/qik.auth.js +938 -0
  57. package/src/api/qik.cache.js +63 -0
  58. package/src/api/qik.content.js +858 -0
  59. package/src/api/qik.core.js +246 -0
  60. package/src/api/qik.files.js +150 -0
  61. package/src/api/qik.filter.js +543 -0
  62. package/src/api/qik.geo.js +895 -0
  63. package/src/api/qik.socket.js +348 -0
  64. package/src/api/qik.system.js +49 -0
  65. package/src/api/qik.utils.js +1410 -0
  66. package/src/index.js +20 -0
  67. package/src/version.js +1 -0
  68. package/test/index.spec.js +41 -0
  69. package/test/mocha.opts +0 -0
  70. package/dist/sdk.js +0 -2
  71. package/dist/sdk.js.LICENSE.txt +0 -8
@@ -0,0 +1,858 @@
1
+ import axios from 'axios';
2
+ import _ from 'lodash';
3
+
4
+ ///////////////////////////////////////////////////
5
+
6
+ /**
7
+ * Creates a new QikContent instance.
8
+ * This module provides a number of helper functions for creating and modifying content via the REST API
9
+ * @alias content
10
+ * @constructor
11
+ * @hideconstructor
12
+ * @param {QikCore} qik A reference to the parent instance of the QikCore module. This module is usually created by a QikCore instance that passes itself in as the first argument.
13
+ */
14
+ export default function(qik) {
15
+
16
+ if (!qik.api) {
17
+ throw new Error(`Can't Instantiate QikContent before QikAPI exists`);
18
+ }
19
+
20
+ ///////////////////////////////////////////////////
21
+
22
+ var service = {
23
+ debug: false,
24
+ loadingGlossary:false,
25
+ }
26
+
27
+
28
+ ///////////////////////////////////////////////////////////////////////////////
29
+
30
+ const variables = {}
31
+ let inflightVariablesRequest;
32
+
33
+
34
+ /**
35
+ *
36
+ * Retrieves all global variables for the current user. This is often used when running custom code in an action.
37
+ * @alias content.variables
38
+ * @param {Array} keys Provide specific keys of variables you want to retrieve
39
+ * @param {Object} options Additional options when making the request
40
+ * @param {Boolean} options.reload Force variables to reload and not be cached. If false will retrieve any variables that are already known from the in memory cache.
41
+ * @example
42
+ *
43
+ * const { OAUTH_CLIENT_ID, OAUTH_KEY } = await sdk.content.variables();
44
+ */
45
+
46
+ service.variables = async function(keys, options) {
47
+ options = options || {};
48
+ keys = keys || [];
49
+
50
+ var reload = options.refresh || options.reload || !variables.data;
51
+ if (reload) {
52
+ if(!inflightVariablesRequest) {
53
+ inflightVariablesRequest = qik.api.post(`/variables`, {keys});
54
+ inflightVariablesRequest.then(resolveRequest, resolveRequest);
55
+ function resolveRequest() {
56
+ inflightVariablesRequest = null;
57
+ }
58
+ }
59
+
60
+ const { data } = await inflightVariablesRequest
61
+ variables.data = data;
62
+ qik.dispatch('variables', data)
63
+ }
64
+
65
+ return variables.data;
66
+ }
67
+
68
+ ///////////////////////////////////////////////////
69
+
70
+ const glossaryCache = qik.cache.get('user:glossary');
71
+
72
+ let inflightGlossaryRequest;
73
+
74
+ /**
75
+ *
76
+ * Retrieves the glossary of all content types visible to the requesting user.
77
+ By default this will include all fields, validation, expressions and other configuration
78
+ * @alias content.glossary
79
+ * @param {Object} options Additional options
80
+ * @param {Boolean} options.hash Whether to return the data as a keyed object
81
+ allowing for fast selection of specific content types, by default will return as an array
82
+ * @param {Boolean} options.reload Force glossary to reload and not be cached.
83
+ If false will retrieve content type data from the in memory cache
84
+ * @example
85
+ *
86
+ * const { article, profile } = await sdk.content.glossary({hash:true});
87
+ */
88
+ service.glossary = async function(options) {
89
+ options = options || {};
90
+
91
+
92
+ // Check if we already have the glossary cached
93
+ let cached = glossaryCache.get('glossary');
94
+ var reload = options.refresh || options.reload || !cached;
95
+
96
+ // If we are forcing a reload
97
+ if (reload) {
98
+ if(!inflightGlossaryRequest) {
99
+
100
+ service.loadingGlossary = true;
101
+
102
+ inflightGlossaryRequest = qik.api.get(`/glossary`, {cache:false});
103
+ inflightGlossaryRequest.then(resolveRequest, resolveRequest);
104
+ function resolveRequest() {
105
+ inflightGlossaryRequest = null;
106
+ service.loadingGlossary = false;
107
+ }
108
+ }
109
+
110
+ // Now we have the glossary
111
+ const { data } = await inflightGlossaryRequest
112
+
113
+ // Cache it for later
114
+ glossaryCache.set('glossary', data);
115
+ cached = data;
116
+ qik.dispatch('glossary', data)
117
+ }
118
+
119
+
120
+ if (options.hash) {
121
+ var result = qik.utils.hash(cached, 'key');
122
+ return result;
123
+ }
124
+
125
+ if (options.hex) {
126
+ var result = qik.utils.hash(cached, 'hex');
127
+ return result;
128
+ }
129
+
130
+ return cached;
131
+ }
132
+
133
+
134
+
135
+ ///////////////////////////////////////////////////
136
+
137
+
138
+
139
+ const scopeGlossary = {}
140
+
141
+ let inflightScopeGlossaryRequest;
142
+
143
+ /**
144
+ *
145
+ * Retrieves the scope glossary of all scopes the user can know about. This helps to convert a scope id into a human readable title.
146
+ * @alias content.scopeGlossary
147
+ * @param {Object} options Additional options
148
+ * @param {Boolean} options.hash Whether to return the data as a keyed object with each scopes _id as the key
149
+ allowing for fast selection of specific scopes, by default will return a structured tree
150
+ * @param {Boolean} options.reload Force the glossary to reload and not be cached.
151
+ If false will retrieve content type data from the in memory cache
152
+ * @example
153
+ *
154
+ * const scopes = await sdk.content.scopeGlossary();
155
+ */
156
+
157
+ service.scopeGlossary = async function(options) {
158
+ options = options || {};
159
+
160
+ var reload = options.refresh || options.reload || !scopeGlossary.data;
161
+
162
+
163
+ if (reload) {
164
+
165
+ if(!inflightScopeGlossaryRequest) {
166
+ inflightScopeGlossaryRequest = qik.api.get(`/scope/glossary`, {cache:false});
167
+ inflightScopeGlossaryRequest.then(resolveRequest, resolveRequest);
168
+ function resolveRequest() {
169
+ inflightScopeGlossaryRequest = null;
170
+ }
171
+ }
172
+
173
+ const { data } = await inflightScopeGlossaryRequest
174
+ scopeGlossary.data = data;
175
+ }
176
+
177
+ if (options.hash) {
178
+ var result = qik.utils.hash(scopeGlossary.data, '_id');
179
+ return result;
180
+ }
181
+
182
+ return scopeGlossary.data;
183
+ }
184
+
185
+
186
+
187
+
188
+ ///////////////////////////////////////////////////
189
+
190
+ /**
191
+ *
192
+ * Retrieves all available filter comparators for each data type
193
+ * @alias content.comparators
194
+ * @param {Object} options Additional options
195
+ * @param {Boolean} options.reload Ignore any locally cached data
196
+ * @example
197
+ * const {hash, available, types} = await sdk.content.comparators();
198
+ * console.log(available) // {boolean:[{title:'Is equal to', operator:'equal'...}]}
199
+ * console.log(hash) // {equal:[{title:'Is equal to', operator:'equal'...}]}
200
+ */
201
+
202
+
203
+ const comparators = {}
204
+
205
+ service.comparators = async function(options) {
206
+ options = options || {};
207
+
208
+ var reload = options.reload || options.refresh || !comparators.data;
209
+
210
+ if (reload) {
211
+ const { data } = await qik.api.get(`/system/comparators`);
212
+
213
+
214
+ /////////////////////////////
215
+
216
+ data.available = {};
217
+
218
+ Object.entries(data.types).forEach(([key, value]) => {
219
+ data.available[key] = value.map(function(comparatorKey) {
220
+ return data.hash[comparatorKey];
221
+ })
222
+ });
223
+
224
+
225
+ /////////////////////////////
226
+
227
+ comparators.data = data;
228
+ }
229
+
230
+
231
+
232
+ // if (options.hash) {
233
+ // var result = qik.utils.hash(comparators.data, 'key');
234
+ // return result;
235
+ // }
236
+
237
+ return comparators.data;
238
+ }
239
+
240
+ ///////////////////////////////////////////////////
241
+
242
+
243
+ function getLimits(fieldDefinition) {
244
+
245
+ var { minimum, maximum } = fieldDefinition;
246
+ minimum = qik.utils.parseInt(minimum);
247
+ minimum = Math.max(minimum, 0);
248
+
249
+ maximum = qik.utils.parseInt(maximum);
250
+ maximum = Math.max(maximum, 0); // cant be less than 0
251
+ if (maximum == 0) {
252
+ //Unlimited maximum
253
+ } else {
254
+ maximum = Math.max(maximum, minimum); // cant be less than the minimum
255
+ }
256
+ return { minimum, maximum };
257
+ }
258
+
259
+
260
+
261
+
262
+ service.meetsValidationRequirements = function(input, fieldType, validationCriteria) {
263
+
264
+ if (validationCriteria.minLength) {
265
+ var stringLength = String(input).length;
266
+ if (stringLength < validationCriteria.minLength) {
267
+ return `Must be at least ${validationCriteria.minLength} characters`;
268
+
269
+ }
270
+ }
271
+
272
+ if (validationCriteria.maxLength) {
273
+ var stringLength = String(input).length;
274
+ if (stringLength > validationCriteria.maxLength) {
275
+ return `Can be no more than ${validationCriteria.maxLength} characters`;
276
+
277
+ }
278
+ }
279
+
280
+ if (validationCriteria.minValue) {
281
+ if(input !== undefined) {
282
+
283
+
284
+ var number = Number(input);
285
+ if (number < validationCriteria.minValue) {
286
+ return `Must be at least ${validationCriteria.minValue}`;
287
+
288
+ }
289
+ }
290
+ }
291
+
292
+ if (validationCriteria.maxValue) {
293
+ if(input !== undefined) {
294
+
295
+
296
+ var number = Number(input);
297
+ if (number > validationCriteria.maxValue) {
298
+ return `Can be no greater than ${validationCriteria.maxValue}`;
299
+
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Checks if a certain input validates against a field definition
307
+ * @alias content.validateField
308
+ * @param {Any} input The input to validate
309
+ * @param {Object} fieldDefinition The field to validate against
310
+ * @param {Object} options Additional options when calling the function
311
+ * @example
312
+ * const validationResult = await sdk.content.validateField('Johnny Bobbins', {title:'Name', key:'firstName', type:'string', minimum:1, maximum:1, ...});
313
+ * console.log(validationResult)
314
+ * // Results in { valid:true }
315
+ *
316
+ * const validationResult = await sdk.content.validateField('Johnny Bobbins', {title:'Number', key:'number', type:'integer', minimum:1, maximum:1, ...});
317
+ * console.log(validationResult)
318
+ * // Results in { valid:false, status:400, message:'Invalid number input for field' }
319
+ */
320
+
321
+ service.validateField = function(input, fieldDefinition, options) {
322
+ options = options || {}
323
+
324
+ var fieldType = fieldDefinition.type || 'string';
325
+ var { minimum, maximum } = getLimits(fieldDefinition);
326
+
327
+ var isObject = (fieldDefinition.type == 'group' && fieldDefinition.asObject);
328
+ var singleValue = isObject ? minimum === maximum && maximum === 1 : maximum === 1;
329
+ var multiValue = !singleValue;
330
+
331
+ //////////////////
332
+
333
+ var isNumeric;
334
+ switch (fieldType) {
335
+ case 'integer':
336
+ case 'decimal':
337
+ case 'number':
338
+ case 'float':
339
+ isNumeric = true;
340
+ break;
341
+ }
342
+
343
+ //////////////////
344
+
345
+ var inputWasProvided = qik.utils.exists(input);
346
+
347
+ //If an answer is required
348
+ if (minimum) {
349
+ //but none was provided
350
+ if (!inputWasProvided) {
351
+ //Throw an error
352
+ return {
353
+ valid: false,
354
+ message: `${fieldDefinition.title} is a required field`,
355
+ status: 400,
356
+ }
357
+ }
358
+ } else {
359
+ //No answer is needed and none was provided
360
+ if (!inputWasProvided) {
361
+ return {
362
+ valid: true,
363
+ }
364
+ }
365
+ }
366
+
367
+ //////////////////
368
+
369
+
370
+ //If we are requiring multiple values
371
+ if (multiValue) {
372
+
373
+ //But the input is not an array
374
+ if (!Array.isArray(input)) {
375
+
376
+ if (minimum) {
377
+ return {
378
+ valid: false,
379
+ message: `${fieldDefinition.title} requires at least ${minimum} values`,
380
+ status: 400,
381
+ }
382
+ } else {
383
+
384
+ console.log('NOT PROVIDED AS ARRAY', fieldDefinition.title, input)
385
+ return {
386
+ valid: false,
387
+ message: `${fieldDefinition.title} must be provided as an array`,
388
+ status: 400,
389
+ }
390
+ }
391
+ }
392
+
393
+
394
+
395
+ ////////////////////////////
396
+
397
+ var compacted = input;
398
+
399
+ compacted = compacted.filter(function(v) {
400
+ //Check if we care about this value
401
+ var empty = v === undefined || v === null || v === '';
402
+ return !empty;
403
+ })
404
+
405
+
406
+ // console.log('COMPACTED', input.length, compacted.length);
407
+
408
+ ////////////////////////////
409
+
410
+ //We need an exact number of answers
411
+ if (minimum == maximum) {
412
+
413
+ //But we don't have the number of answers needed
414
+ if (minimum && (compacted.length != minimum)) {
415
+ return {
416
+ valid: false,
417
+ message: `${fieldDefinition.title} requires exactly ${maximum} values`,
418
+ status: 400,
419
+ }
420
+ }
421
+ }
422
+
423
+ //We have too many answers
424
+ if (maximum && (compacted.length > maximum)) {
425
+
426
+ return {
427
+ valid: false,
428
+ message: `${fieldDefinition.title} requires less than ${maximum+1} values`,
429
+ status: 400,
430
+ }
431
+ }
432
+
433
+ //We don't have enough answers
434
+ if (compacted.length < minimum) {
435
+
436
+ // console.log(fieldDefinition.title, 'INPUT', input.length, minimum, input, compacted)
437
+
438
+ return {
439
+ valid: false,
440
+ message: `${fieldDefinition.title} requires at least ${minimum} values`,
441
+ status: 400,
442
+ }
443
+ }
444
+
445
+ ////////////////////////////
446
+
447
+ var foundBadEntry;
448
+
449
+ //Find any bad values
450
+ var badEntry = compacted.find(function(val) {
451
+ var valueFieldType = fieldType;
452
+
453
+ if (fieldDefinition.type === 'group') {
454
+ valueFieldType = 'object';
455
+ }
456
+
457
+ if (fieldDefinition.type === 'reference' && fieldDefinition.widget === 'form') {
458
+ valueFieldType = 'object';
459
+ }
460
+
461
+ var isValid = qik.utils.isValidValue(val, valueFieldType, options.strict);
462
+
463
+ ////////////////////////////
464
+
465
+ if (!isValid) {
466
+ foundBadEntry = true;
467
+ return true;
468
+ }
469
+
470
+ ////////////////////////////
471
+
472
+ //Is there additional validation requirements
473
+ if (fieldDefinition.validation) {
474
+ var additionalValidationErrors = service.meetsValidationRequirements(val, fieldType, fieldDefinition.validation)
475
+ if (additionalValidationErrors) {
476
+ foundBadEntry = true;
477
+ return true;
478
+ }
479
+ }
480
+ })
481
+
482
+ if (foundBadEntry) {
483
+ let badValueMessage = `Invalid input for ${fieldDefinition.title}`;
484
+ return {
485
+ valid: false,
486
+ message: badValueMessage,
487
+ status: 400,
488
+ }
489
+ }
490
+
491
+ } else {
492
+
493
+ var dataType = fieldType;
494
+ var widgetType = fieldDefinition.widget;
495
+ if (dataType === 'group') {
496
+ dataType = 'object';
497
+ }
498
+
499
+ if (dataType === 'reference' && widgetType === 'form') {
500
+ dataType = 'object';
501
+ }
502
+
503
+
504
+ //////////////////
505
+
506
+ var cleanedValue = service.getCleanedValue(input, dataType, options);
507
+
508
+
509
+ //////////////////
510
+
511
+ var isValidValue = qik.utils.isValidValue(cleanedValue, dataType, options.strict);
512
+
513
+ //////////////////
514
+
515
+ //Invalid input
516
+ if (!isValidValue) {
517
+ return {
518
+ valid: false,
519
+ message: `Single value '${input}' is not a valid ${dataType} for ${fieldDefinition.title}`,
520
+ criteria: {
521
+ isValidValue,
522
+ cleanedValue,
523
+ fieldType,
524
+ options,
525
+ },
526
+ status: 400,
527
+ }
528
+ }
529
+
530
+ //Is there additional validation requirements
531
+ let hasAdditionalValidation = false;
532
+
533
+ const validation = {}
534
+ if(String(fieldDefinition.minValue)) { validation.minValue = parseInt(fieldDefinition.minValue); hasAdditionalValidation = true }
535
+ if(String(fieldDefinition.maxValue)) { validation.maxValue = parseInt(fieldDefinition.maxValue); hasAdditionalValidation = true }
536
+ if(String(fieldDefinition.minLength)) { validation.minLength = parseInt(fieldDefinition.minLength); hasAdditionalValidation = true }
537
+ if(String(fieldDefinition.maxLength)) { validation.maxLength = parseInt(fieldDefinition.maxLength); hasAdditionalValidation = true }
538
+
539
+
540
+ if (hasAdditionalValidation) {
541
+ const validationCriteria = Object.assign({}, validation, fieldDefinition.validation || {});
542
+ var additionalValidationError = service.meetsValidationRequirements(input, fieldType, validationCriteria)
543
+ if (additionalValidationError) {
544
+ return {
545
+ valid: false,
546
+ message: additionalValidationError,
547
+ status: 400,
548
+ };
549
+ }
550
+ }
551
+ }
552
+
553
+ //////////////////
554
+
555
+ return {
556
+ valid: true,
557
+ }
558
+
559
+ }
560
+
561
+ service.getCleanedValue = function(input, dataType, options) {
562
+ switch (dataType) {
563
+ case 'number':
564
+ case 'float':
565
+ case 'decimal':
566
+ if (!qik.utils.exists(input)) {
567
+ return undefined;
568
+ } else {
569
+ return Number(input);
570
+ }
571
+ break;
572
+ case 'integer':
573
+ if (!qik.utils.exists(input)) {
574
+ return undefined;
575
+ } else {
576
+ return parseInt(input);
577
+ }
578
+ break;
579
+ case 'boolean':
580
+ if (!qik.utils.exists(input)) {
581
+ return undefined;
582
+ }
583
+ return qik.utils.parseBoolean(input);
584
+ break;
585
+ case 'email':
586
+ return options.strict ? input : String(input).toLowerCase();
587
+ break;
588
+ case 'reference':
589
+ return options.strict ? input : qik.utils.id(input);
590
+ break;
591
+ default:
592
+ return options.strict ? input : qik.utils.cleanValue(input, dataType, options);
593
+ break
594
+ }
595
+
596
+ return input;
597
+ }
598
+
599
+ ///////////////////////////////////////////////////
600
+
601
+ /**
602
+ *
603
+ * Retrieves a list of records matching the provided criteria
604
+ * @alias content.list
605
+ * @param {String} type The type or definition of records we want to retrieve
606
+ * @param {Object} options The options for our query
607
+ * @param {String} options.search Freeform text keywords
608
+ * @param {Object} options.sort How to sort the results
609
+ * @param {String} options.sort.key Which key to sort on
610
+ * @param {String} options.sort.direction Which direction to sort on
611
+ * @param {Object} options.sort.type What type of data is being sorted
612
+ * @param {Object} options.page Page configuration
613
+ * @param {Number} options.page.size Page size
614
+ * @param {Number} options.page.index Page index
615
+ * @param {Object} options.filter How to filter the results
616
+ * @example
617
+ *
618
+ *
619
+ * sdk.content.list('profile', {
620
+ * search:'Jim',
621
+ * page:{
622
+ * size:50,
623
+ * index:2,
624
+ * },
625
+ * sort:{
626
+ * key:'age',
627
+ * direction:'asc',
628
+ * type:'integer',
629
+ * },
630
+ * filter:{
631
+ * operator:'and',
632
+ * filters:[{
633
+ * key:'age',
634
+ * comparator:'>',
635
+ * value:5,
636
+ * }],
637
+ * },
638
+ * })
639
+ */
640
+
641
+ service.list = async function(type, options, advanced) {
642
+
643
+
644
+
645
+
646
+ if (!advanced) {
647
+ advanced = {};
648
+ }
649
+
650
+ const remoteURL = advanced.remoteURL || `/content/${type}/list`;
651
+
652
+ if (advanced.cancellable) {
653
+
654
+ if (!advanced.config) {
655
+ advanced.config = {}
656
+ }
657
+
658
+ //Create a cancel token
659
+ const CancelToken = qik.api.CancelToken;
660
+ const source = CancelToken.source();
661
+ advanced.config.cancelToken = source.token;
662
+
663
+
664
+ const promise = qik.api.post(remoteURL, options, advanced.config);
665
+ return {
666
+ promise,
667
+ cancel(message) {
668
+ source.cancel(message || 'Operation canceled by the user.');
669
+ },
670
+ }
671
+
672
+ } else {
673
+ const { data } = await qik.api.post(remoteURL, options, advanced.config);
674
+ return data;
675
+ }
676
+
677
+
678
+
679
+
680
+
681
+ }
682
+
683
+ ///////////////////////////////////////////////////
684
+
685
+ /**
686
+ *
687
+ * Create an item
688
+ * @alias content.create
689
+ * @param {String} type The type or definition of the record we want to create
690
+ * @param {Object} input The data for our new record
691
+ * @example
692
+ *
693
+ *
694
+ * const result = await sdk.content.create('profile', {
695
+ * firstName:'Mickey',
696
+ * lastName:'Mouse',
697
+ * gender:'male',
698
+ * meta:{
699
+ * scopes:['61eca4746971e75c1fc670cf'],
700
+ * }
701
+ * })
702
+ */
703
+
704
+ service.create = async function(type, input) {
705
+
706
+ const dataModel = {...input};
707
+
708
+ // Sanitize down to just ids before we send
709
+ if(dataModel.meta?.scopes) {
710
+ dataModel.meta.scopes = qik.utils.ids(dataModel.meta.scopes);
711
+ }
712
+
713
+
714
+ const { data } = await qik.api.post(`/content/${type}/create`, dataModel);
715
+ return data;
716
+ }
717
+
718
+ /**
719
+ *
720
+ * Update an item, Only fields the user has permission to view will be returned
721
+ * @alias content.update
722
+ * @param {String} id The id of the record we want to update
723
+ * @param {Object} input The data to update
724
+ * @example
725
+ *
726
+ * const result = await sdk.content.update('61eca4746971e75c1fc670cd', {
727
+ * firstName:'Minnie',
728
+ * lastName:'Mouse',
729
+ * gender:'female',
730
+ * meta:{
731
+ * scopes:['61eca4746971e75c1fc670cd'],
732
+ * }
733
+ * })
734
+ */
735
+ service.update = async function(id, input) {
736
+ id = qik.utils.id(id);
737
+
738
+ const dataModel = {...input};
739
+
740
+ // Sanitize down to just ids before we send
741
+ if(dataModel.meta?.scopes) {
742
+ dataModel.meta.scopes = qik.utils.ids(dataModel.meta.scopes);
743
+ }
744
+
745
+
746
+ const { data } = await qik.api.put(`/content/${id}`, dataModel);
747
+ return data;
748
+ }
749
+
750
+ /**
751
+ *
752
+ * Partially update and patch an item, Only fields the user has permission to edit will be updated
753
+ * @alias content.patch
754
+ * @param {String} id The id of the record we want to update
755
+ * @param {Object} input The data to update, this will be merged with existing data
756
+ * @example
757
+ *
758
+ * const result = await sdk.content.patch('61eca4746971e75c1fc670cd', {
759
+ * firstName:'Mickey',
760
+ * gender:'male',
761
+ * })
762
+ */
763
+ service.patch = async function(id, input) {
764
+ id = qik.utils.id(id);
765
+
766
+ const dataModel = {...input};
767
+
768
+ // Sanitize down to just ids before we send
769
+ if(dataModel.meta?.scopes) {
770
+ dataModel.meta.scopes = qik.utils.ids(dataModel.meta.scopes);
771
+ }
772
+
773
+
774
+ const { data } = await qik.api.patch(`/content/${id}`, dataModel);
775
+ return data;
776
+ }
777
+
778
+ /**
779
+ *
780
+ * Get an item from the database, Only fields the user has permission to view will be returned
781
+ * @alias content.get
782
+ * @param {String} id The id of the record we want to update
783
+ * @example
784
+ *
785
+ * const result = await sdk.content.get('61eca4746971e75c1fc670cd')
786
+ */
787
+ service.get = async function(id, params) {
788
+ id = qik.utils.id(id);
789
+ params = params || {}
790
+
791
+ const { data } = await qik.api.get(`/content/${id}`, params);
792
+ return data;
793
+ }
794
+
795
+ service.getFromID = async function(id) {
796
+ return service.get(id);
797
+ }
798
+
799
+ /**
800
+ *
801
+ * Delete an item from the database
802
+ * @alias content.delete
803
+ * @param {String} id The id of the record we want to delete
804
+ * @example
805
+ * const result = await sdk.content.delete('61eca4746971e75c1fc670cd')
806
+ */
807
+ service.delete = async function(id, input) {
808
+ id = qik.utils.id(id);
809
+ const { data } = await qik.api.delete(`/content/${id}`, input);
810
+ return data;
811
+ }
812
+
813
+ /**
814
+ *
815
+ * Restore a deleted item from the database
816
+ * @alias content.restore
817
+ * @param {String} id The id of the record we want to restore
818
+ * @example
819
+ * const result = await sdk.content.restore('61eca4746971e75c1fc670cd')
820
+ */
821
+ service.restore = async function(id, input) {
822
+ id = qik.utils.id(id);
823
+ const { data } = await qik.api.get(`/content/${id}/restore`, input);
824
+ return data;
825
+ }
826
+
827
+
828
+ /**
829
+ *
830
+ * Retrieve an item from the database by providing it's 'slug'
831
+ * @alias content.getFromSlug
832
+ * @param {String} slug The slug id of the record we want to retrieve
833
+ * it must be provided as either `(type):(slug)`` or `(definition):(slug)`
834
+ * (if unsure use the `meta.abs` absolute slug property of the item you are wanting to retrieve).
835
+ * @example
836
+ * const result = await sdk.content.getFromSlug('article:how-to-get-started')
837
+ * const result = await sdk.content.getFromSlug('car:toyota-landcruiser')
838
+ * const result = await sdk.content.getFromSlug('article:toyota-landcruiser')
839
+ */
840
+ service.getFromSlug = async function(slug) {
841
+ const { data } = await qik.api.get(`/content/slug/${slug}`);
842
+ return data;
843
+ }
844
+
845
+ // service.getFromSlug = async function(type, slug) {
846
+ // const { data } = await qik.api.get(`/content/${type}/slug/${slug}`);
847
+ // return data;
848
+ // }
849
+
850
+ // service.getFromExternalID = async function(type, externalID) {
851
+ // const { data } = await qik.api.get(`/content/${type}/external/${externalID}`);
852
+ // return data;
853
+ // }
854
+
855
+
856
+ return service;
857
+
858
+ }