musora-content-services 1.0.105 → 1.0.108

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 (55) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/config.js.html +2 -2
  6. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  7. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  8. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  9. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  14. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  15. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  16. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  24. package/docs/index.html +2 -2
  25. package/docs/module-Config.html +2 -2
  26. package/docs/module-Railcontent-Services.html +2 -2
  27. package/docs/module-Sanity-Services.html +393 -42
  28. package/docs/railcontent.js.html +2 -2
  29. package/docs/sanity.js.html +307 -86
  30. package/docs/scripts/collapse.js +0 -0
  31. package/docs/scripts/commonNav.js +0 -0
  32. package/docs/scripts/linenumber.js +0 -0
  33. package/docs/scripts/nav.js +0 -0
  34. package/docs/scripts/polyfill.js +0 -0
  35. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  36. package/docs/scripts/prettify/lang-css.js +0 -0
  37. package/docs/scripts/prettify/prettify.js +0 -0
  38. package/docs/scripts/search.js +0 -0
  39. package/docs/styles/jsdoc.css +0 -0
  40. package/docs/styles/prettify.css +0 -0
  41. package/jest.config.js +0 -0
  42. package/jsdoc.json +0 -0
  43. package/package.json +1 -1
  44. package/src/contentTypeConfig.js +1331 -12
  45. package/src/filterBuilder.js +122 -0
  46. package/src/index.d.ts +0 -0
  47. package/src/index.js +0 -0
  48. package/src/services/config.js +0 -0
  49. package/src/services/railcontent.js +0 -0
  50. package/src/services/sanity.js +267 -87
  51. package/src/services/userContext.js +0 -0
  52. package/test/localStorageMock.js +0 -0
  53. package/test/log.js +0 -0
  54. package/test/sanityQueryService.test.js +222 -17
  55. package/test/userContext.test.js +0 -0
@@ -9,33 +9,36 @@ const {
9
9
  fetchAllSongs,
10
10
  fetchSongFilterOptions,
11
11
  fetchSongCount,
12
- fetchWorkouts,
13
12
  fetchNewReleases,
14
13
  fetchUpcomingEvents,
15
14
  fetchByRailContentId,
16
15
  fetchByRailContentIds,
17
16
  fetchAll,
18
17
  fetchAllFilterOptions,
19
- fetchMethodNextLesson,
20
- fetchMethodChildrenIds,
21
- fetchNextPreviousLesson,
18
+ fetchFoundation,
19
+ fetchMethods,
20
+ fetchMethod,
22
21
  fetchRelatedLessons,
22
+ fetchAllPacks,
23
23
  fetchPackAll,
24
- fetchPackChildren,
25
24
  fetchLessonContent,
26
- getSortOrder,
27
- fetchParentByRailContentId,
25
+ fetchCourseOverview,
28
26
  fetchChildren,
29
- fetchMethod,
30
- fetchMethods,
31
- fetchFoundation,
32
- fetchAllPacks,
33
- fetchPacksAll,
27
+ fetchParentByRailContentId,
28
+ fetchLiveEvent,
29
+ fetchChallengeOverview,
34
30
  fetchCoachLessons,
35
31
  fetchByReference,
36
- fetchScheduledReleases
32
+ fetchScheduledReleases,
33
+ getSortOrder,
34
+ fetchShowsData,
35
+ fetchMetadata
37
36
  } = require('../src/services/sanity.js');
38
37
 
38
+ const {
39
+ FilterBuilder,
40
+ } = require('../src/filterBuilder.js');
41
+
39
42
  describe('Sanity Queries', function () {
40
43
  beforeEach(() => {
41
44
  const config = {
@@ -73,7 +76,14 @@ describe('Sanity Queries', function () {
73
76
 
74
77
  test('fetchByRailContentId', async () => {
75
78
  const id = 380094;
76
- const response = await fetchByRailContentId(id);
79
+ const response = await fetchByRailContentId(id, "song");
80
+ expect(response.id).toBe(id);
81
+ });
82
+
83
+ test('fetchChallengeOverview', async () => {
84
+ const id = 402197;
85
+ const response = await fetchChallengeOverview(id);
86
+ expect(response.lessons).toBeDefined();
77
87
  expect(response.id).toBe(id);
78
88
  });
79
89
 
@@ -88,12 +98,36 @@ describe('Sanity Queries', function () {
88
98
 
89
99
  });
90
100
 
101
+ test('fetchUpcomingEvents', async () => {
102
+ const response = await fetchUpcomingEvents('drumeo', {});
103
+ expect(response.length).toBeGreaterThan(0);
104
+ });
105
+
106
+ test('fetchUpcomingNewReleases', async () => {
107
+ const response = await fetchNewReleases('drumeo');
108
+ expect(response.length).toBeGreaterThan(0);
109
+ });
110
+
111
+
91
112
  test('fetchLessonContent', async () => {
92
113
  const id = 380094;
93
114
  const response = await fetchLessonContent(id);
94
115
  expect(response.id).toBe(id);
95
116
  });
96
117
 
118
+
119
+ test('fetchCourseOverview', async () => {
120
+ const id = 310414;
121
+ const response = await fetchCourseOverview(id);
122
+ expect(response.id).toBe(id);
123
+ expect(response.type).toBe('course');
124
+ });
125
+
126
+ test('fetchSongCount', async () => {
127
+ const response = await fetchSongCount('drumeo');
128
+ expect(response).toBeGreaterThan(1000);
129
+ });
130
+
97
131
  test('fetchAllSongs', async () => {
98
132
  const response = await fetchAllSongs('drumeo', {});
99
133
  log(response);
@@ -102,6 +136,13 @@ describe('Sanity Queries', function () {
102
136
  expect(response.entity[0].instrumentless).toBeDefined();
103
137
  });
104
138
 
139
+ test('fetchSongFilterOptions', async () => {
140
+ const response = await fetchSongFilterOptions('drumeo', {});
141
+ log(response);
142
+ expect(response.genre).toBeDefined();
143
+ expect(response.difficulty).toBeDefined();
144
+ });
145
+
105
146
  test('fetchAllSongsGroupByArtist', async () => {
106
147
  const response = await fetchAllSongs('drumeo', {groupBy:"artist"});
107
148
  expect(response.entity[0].lessons[0].soundslice).toBeDefined();
@@ -110,6 +151,12 @@ describe('Sanity Queries', function () {
110
151
  }, 100000);
111
152
 
112
153
 
154
+ test('fetchNewReleases', async () => {
155
+ const response = await fetchNewReleases('drumeo');
156
+ log(response);
157
+ expect(response[0].id).toBeDefined();
158
+ });
159
+
113
160
  test('fetchAllWorkouts', async () => {
114
161
  const response = await fetchAll('drumeo', 'workout',{});
115
162
  log(response);
@@ -159,10 +206,10 @@ describe('Sanity Queries', function () {
159
206
 
160
207
  test('fetchRelatedLessons', async () => {
161
208
  const id = 380094;
162
- const document = await fetchByRailContentId(id);
209
+ const document = await fetchByRailContentId(id, 'song');
163
210
  let artist = document.artist.name;
164
211
  const response = await fetchRelatedLessons(id, 'singeo');
165
- let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id);
212
+ let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id, 'song');
166
213
  // match on artist or any genre
167
214
  let isMatch = artist === relatedDoc.artist.name;
168
215
  isMatch = isMatch || document.genre.some((genre) => {
@@ -274,7 +321,7 @@ describe('Sanity Queries', function () {
274
321
  });
275
322
 
276
323
  test('fetchCoachLessons', async () => {
277
- const response = await fetchCoachLessons('drumeo',233797);
324
+ const response = await fetchCoachLessons('drumeo',411493, {});
278
325
  expect(response.entity.length).toBeGreaterThan(0);
279
326
  });
280
327
 
@@ -310,4 +357,162 @@ describe('Sanity Queries', function () {
310
357
  log(response);
311
358
  expect(response.entity[0].web_url_path).toContain('/drumeo/coaches/');
312
359
  });
360
+
361
+ test('fetchShowsData', async () => {
362
+ const response = await fetchShowsData('singeo');
363
+ log(response);
364
+ expect(response.length).toBeGreaterThan(0);
365
+ });
366
+
367
+ test('fetchMetadata', async () => {
368
+ const response = await fetchMetadata('drumeo','song');
369
+ log(response);
370
+ expect(response.tabs.length).toBeGreaterThan(0);
371
+ });
372
+
373
+ });
374
+
375
+ describe('Filter Builder', function () {
376
+
377
+ test('baseConstructor', async () => {
378
+ const filter = 'railcontent_id = 111'
379
+ let builder = new FilterBuilder(filter);
380
+ let finalFilter = builder.buildFilter(filter);
381
+ let clauses = spliceFilterForAnds(finalFilter);
382
+ expect(clauses[0].phrase).toBe(filter);
383
+ expect(clauses[1].field).toBe('published_on');
384
+
385
+ builder = new FilterBuilder();
386
+ finalFilter = builder.buildFilter(filter);
387
+ clauses = spliceFilterForAnds(finalFilter);
388
+ expect(clauses[0].field).toBe('published_on');
389
+ expect(clauses[0].operator).toBe('<=');
390
+ });
391
+
392
+ test('withOnlyFilterAvailableStatuses', async () => {
393
+ const filter = 'railcontent_id = 111'
394
+ const builder = FilterBuilder.withOnlyFilterAvailableStatuses(filter,['published', 'unlisted']);
395
+ const finalFilter = builder.buildFilter();
396
+ const clauses = spliceFilterForAnds(finalFilter);
397
+ expect(clauses[0].phrase).toBe(filter);
398
+ expect(clauses[1].field).toBe('status');
399
+ expect(clauses[1].operator).toBe('in');
400
+ // not sure I like this
401
+ expect(clauses[1].condition).toBe("['published','unlisted']");
402
+ expect(clauses[2].field).toBe('published_on');
403
+ });
404
+
405
+ test('withContentStatusAndFutureScheduledContent', async () => {
406
+ const filter = 'railcontent_id = 111'
407
+ const builder = new FilterBuilder(filter,{
408
+ availableContentStatuses: ['published', 'unlisted', 'scheduled'],
409
+ getFutureScheduledContentsOnly: true});
410
+ const finalFilter = builder.buildFilter();
411
+ const clauses = spliceFilterForAnds(finalFilter);
412
+ expect(clauses[0].phrase).toBe(filter);
413
+ expect(clauses[1].field).toBe('(status'); // extra ( because it's a multi part filter
414
+ expect(clauses[1].operator).toBe('in');
415
+ // getFutureScheduledContentsOnly doesn't make a filter that's splicable, so we match on the more static string
416
+ const expected = "['published','unlisted'] || (status == 'scheduled' && published_on >=";
417
+ console.log(clauses[1].condition);
418
+ console.log(expected)
419
+ const isMatch = finalFilter.includes(expected);
420
+ expect(isMatch).toBeTruthy();
421
+ });
422
+
423
+ test('withUserPermissions', async () => {
424
+ const filter = 'railcontent_id = 111'
425
+ const builder = new FilterBuilder(filter,
426
+ { user: {
427
+ user: {},
428
+ permissions: [91, 92],
429
+ }});
430
+ const finalFilter = builder.buildFilter();
431
+ const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
432
+ const isMatch = finalFilter.includes(expected);
433
+ expect(isMatch).toBeTruthy();
434
+ });
435
+
436
+ test('withUserPermissionsForPlusUser', async () => {
437
+ const filter = 'railcontent_id = 111'
438
+ const builder = new FilterBuilder(filter,
439
+ {
440
+ user: getPlusUser()
441
+ });
442
+ const finalFilter = builder.buildFilter();
443
+ const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
444
+ const isMatch = finalFilter.includes(expected);
445
+ expect(isMatch).toBeTruthy();
446
+ });
447
+
448
+ test('withPermissionBypass', async () => {
449
+ const filter = 'railcontent_id = 111'
450
+ const builder = new FilterBuilder(filter,
451
+ {
452
+ user: getPlusUser(),
453
+ bypassPermissions:true
454
+ });
455
+ const finalFilter = builder.buildFilter();
456
+ const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
457
+ const isMatch = finalFilter.includes(expected);
458
+ expect(isMatch).toBeFalsy();
459
+ const clauses = spliceFilterForAnds(finalFilter);
460
+ expect(clauses[0].field).toBe('railcontent_id');
461
+ expect(clauses[1].field).toBe('published_on');
462
+ });
463
+
464
+
465
+ test('withPublishOnRestrictions', async () => {
466
+ // testing dates is a pain more frustration than I'm willing to deal with, so I'm just testing operators.
467
+
468
+ const filter = 'railcontent_id = 111'
469
+ let builder = new FilterBuilder(filter, {
470
+ user: {},
471
+ pullFutureContent: true,
472
+ });
473
+
474
+ let finalFilter = builder.buildFilter();
475
+ let clauses = spliceFilterForAnds(finalFilter);
476
+ expect(clauses[0].phrase).toBe(filter);
477
+
478
+ expect(clauses[1].field).toBe('published_on');
479
+ expect(clauses[1].operator).toBe('<=');
480
+ const restrictionDate = new Date(clauses[1].condition)
481
+ const now = new Date();
482
+ expect(now.getTime()).toBeLessThan(restrictionDate.getTime());
483
+
484
+ builder = new FilterBuilder(filter,
485
+ {
486
+ user: {},
487
+ getFutureContentOnly: true,
488
+ });
489
+ finalFilter = builder.buildFilter();
490
+ clauses = spliceFilterForAnds(finalFilter);
491
+ expect(clauses[0].phrase).toBe(filter);
492
+ expect(clauses[1].field).toBe('published_on');
493
+ expect(clauses[1].operator).toBe('>=');
494
+ });
495
+
496
+ function getPlusUser() {
497
+ return {
498
+ permissions: [91,92],
499
+ }
500
+ }
501
+
502
+ function spliceFilterForAnds(filter) {
503
+ // this will not correctly split complex filters with && and || conditions.
504
+ let phrases = filter.split(' && ');
505
+ let clauses= [];
506
+ phrases.forEach((phrase) => {
507
+ let field = phrase.substring(0, phrase.indexOf(' '));
508
+ //if(field.charAt(0) === '(' ) field = field.substring(1);
509
+ const temp = phrase.substring(phrase.indexOf(' ') + 1);
510
+ const operator = temp.substring(0, temp.indexOf(' '));
511
+ let condition = temp.substring(temp.indexOf(' ') + 1);
512
+ //if(condition.charAt(condition.length) === ')') condition = condition.slice(-1);
513
+ clauses.push({phrase, field, operator, condition});
514
+ });
515
+ return clauses;
516
+ }
517
+
313
518
  });
File without changes