musora-content-services 1.0.104 → 1.0.107
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.
- package/CHANGELOG.md +6 -0
- package/docs/config.js.html +1 -1
- package/docs/index.html +46 -8
- package/docs/module-Config.html +1 -1
- package/docs/module-Railcontent-Services.html +1 -1
- package/docs/module-Sanity-Services.html +26 -26
- package/docs/railcontent.js.html +13 -13
- package/docs/sanity.js.html +7 -3
- package/package.json +1 -1
- package/src/contentTypeConfig.js +21 -13
- package/src/filterBuilder.js +122 -0
- package/src/services/railcontent.js +12 -12
- package/src/services/sanity.js +205 -86
- package/test/log.js +5 -0
- package/test/sanityQueryService.test.js +240 -33
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {initializeService} from '../src/services/config.js';
|
|
2
|
+
import {log} from './log.js';
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
fetchSongById,
|
|
@@ -8,33 +9,34 @@ const {
|
|
|
8
9
|
fetchAllSongs,
|
|
9
10
|
fetchSongFilterOptions,
|
|
10
11
|
fetchSongCount,
|
|
11
|
-
fetchWorkouts,
|
|
12
12
|
fetchNewReleases,
|
|
13
13
|
fetchUpcomingEvents,
|
|
14
14
|
fetchByRailContentId,
|
|
15
15
|
fetchByRailContentIds,
|
|
16
16
|
fetchAll,
|
|
17
17
|
fetchAllFilterOptions,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
fetchFoundation,
|
|
19
|
+
fetchMethods,
|
|
20
|
+
fetchMethod,
|
|
21
21
|
fetchRelatedLessons,
|
|
22
|
+
fetchAllPacks,
|
|
22
23
|
fetchPackAll,
|
|
23
|
-
fetchPackChildren,
|
|
24
24
|
fetchLessonContent,
|
|
25
|
-
|
|
26
|
-
fetchParentByRailContentId,
|
|
25
|
+
fetchCourseOverview,
|
|
27
26
|
fetchChildren,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
fetchAllPacks,
|
|
32
|
-
fetchPacksAll,
|
|
27
|
+
fetchParentByRailContentId,
|
|
28
|
+
fetchLiveEvent,
|
|
29
|
+
fetchChallengeOverview,
|
|
33
30
|
fetchCoachLessons,
|
|
34
31
|
fetchByReference,
|
|
35
|
-
fetchScheduledReleases
|
|
32
|
+
fetchScheduledReleases,
|
|
33
|
+
getSortOrder,
|
|
36
34
|
} = require('../src/services/sanity.js');
|
|
37
35
|
|
|
36
|
+
const {
|
|
37
|
+
FilterBuilder,
|
|
38
|
+
} = require('../src/filterBuilder.js');
|
|
39
|
+
|
|
38
40
|
describe('Sanity Queries', function () {
|
|
39
41
|
beforeEach(() => {
|
|
40
42
|
const config = {
|
|
@@ -66,13 +68,20 @@ describe('Sanity Queries', function () {
|
|
|
66
68
|
|
|
67
69
|
test('fetchSongArtistCount', async () => {
|
|
68
70
|
const response = await fetchSongArtistCount('drumeo');
|
|
69
|
-
|
|
71
|
+
log(response);
|
|
70
72
|
expect(response).toBeGreaterThan(1000);
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
test('fetchByRailContentId', async () => {
|
|
74
76
|
const id = 380094;
|
|
75
|
-
const response = await fetchByRailContentId(id);
|
|
77
|
+
const response = await fetchByRailContentId(id, "song");
|
|
78
|
+
expect(response.id).toBe(id);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('fetchChallengeOverview', async () => {
|
|
82
|
+
const id = 402197;
|
|
83
|
+
const response = await fetchChallengeOverview(id);
|
|
84
|
+
expect(response.lessons).toBeDefined();
|
|
76
85
|
expect(response.id).toBe(id);
|
|
77
86
|
});
|
|
78
87
|
|
|
@@ -87,20 +96,51 @@ describe('Sanity Queries', function () {
|
|
|
87
96
|
|
|
88
97
|
});
|
|
89
98
|
|
|
99
|
+
test('fetchUpcomingEvents', async () => {
|
|
100
|
+
const response = await fetchUpcomingEvents('drumeo', {});
|
|
101
|
+
expect(response.length).toBeGreaterThan(0);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('fetchUpcomingNewReleases', async () => {
|
|
105
|
+
const response = await fetchNewReleases('drumeo');
|
|
106
|
+
expect(response.length).toBeGreaterThan(0);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
|
|
90
110
|
test('fetchLessonContent', async () => {
|
|
91
111
|
const id = 380094;
|
|
92
112
|
const response = await fetchLessonContent(id);
|
|
93
113
|
expect(response.id).toBe(id);
|
|
94
114
|
});
|
|
95
115
|
|
|
116
|
+
|
|
117
|
+
test('fetchCourseOverview', async () => {
|
|
118
|
+
const id = 310414;
|
|
119
|
+
const response = await fetchCourseOverview(id);
|
|
120
|
+
expect(response.id).toBe(id);
|
|
121
|
+
expect(response.type).toBe('course');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('fetchSongCount', async () => {
|
|
125
|
+
const response = await fetchSongCount('drumeo');
|
|
126
|
+
expect(response).toBeGreaterThan(1000);
|
|
127
|
+
});
|
|
128
|
+
|
|
96
129
|
test('fetchAllSongs', async () => {
|
|
97
130
|
const response = await fetchAllSongs('drumeo', {});
|
|
98
|
-
|
|
131
|
+
log(response);
|
|
99
132
|
expect(response.entity[0].soundslice).toBeDefined();
|
|
100
133
|
expect(response.entity[0].artist_name).toBeDefined();
|
|
101
134
|
expect(response.entity[0].instrumentless).toBeDefined();
|
|
102
135
|
});
|
|
103
136
|
|
|
137
|
+
test('fetchSongFilterOptions', async () => {
|
|
138
|
+
const response = await fetchSongFilterOptions('drumeo', {});
|
|
139
|
+
log(response);
|
|
140
|
+
expect(response.genre).toBeDefined();
|
|
141
|
+
expect(response.difficulty).toBeDefined();
|
|
142
|
+
});
|
|
143
|
+
|
|
104
144
|
test('fetchAllSongsGroupByArtist', async () => {
|
|
105
145
|
const response = await fetchAllSongs('drumeo', {groupBy:"artist"});
|
|
106
146
|
expect(response.entity[0].lessons[0].soundslice).toBeDefined();
|
|
@@ -109,22 +149,28 @@ describe('Sanity Queries', function () {
|
|
|
109
149
|
}, 100000);
|
|
110
150
|
|
|
111
151
|
|
|
152
|
+
test('fetchNewReleases', async () => {
|
|
153
|
+
const response = await fetchNewReleases('drumeo');
|
|
154
|
+
log(response);
|
|
155
|
+
expect(response[0].id).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
|
|
112
158
|
test('fetchAllWorkouts', async () => {
|
|
113
159
|
const response = await fetchAll('drumeo', 'workout',{});
|
|
114
|
-
|
|
160
|
+
log(response);
|
|
115
161
|
expect(response.entity[0].id).toBeDefined();
|
|
116
162
|
});
|
|
117
163
|
|
|
118
164
|
test('fetchAllInstructorField', async () => {
|
|
119
165
|
const response = await fetchAll('drumeo', 'quick-tips',{searchTerm: 'Domino Santantonio'});
|
|
120
|
-
|
|
166
|
+
log(response);
|
|
121
167
|
expect(response.entity[0].id).toBeDefined();
|
|
122
168
|
expect(response.entity[0].instructors).toBeTruthy();
|
|
123
169
|
});
|
|
124
170
|
|
|
125
171
|
test('fetchAllSortField', async () => {
|
|
126
172
|
const response = await fetchAll('drumeo', 'rhythmic-adventures-of-captain-carson',{});
|
|
127
|
-
|
|
173
|
+
log(response);
|
|
128
174
|
expect(response.entity[0].id).toBeDefined();
|
|
129
175
|
expect(response.entity[0].sort).toBeDefined();
|
|
130
176
|
});
|
|
@@ -132,7 +178,7 @@ describe('Sanity Queries', function () {
|
|
|
132
178
|
|
|
133
179
|
test('fetchAllChallenges', async () => {
|
|
134
180
|
const response = await fetchAll('drumeo', 'challenge',{});
|
|
135
|
-
|
|
181
|
+
log(response);
|
|
136
182
|
expect(response.entity[0].registration_url).toBeDefined();
|
|
137
183
|
expect(response.entity[0].enrollment_start_time).toBeDefined();
|
|
138
184
|
expect(response.entity[0].enrollment_end_time).toBeDefined();
|
|
@@ -146,22 +192,22 @@ describe('Sanity Queries', function () {
|
|
|
146
192
|
|
|
147
193
|
test('fetchAll-CustomFields', async () => {
|
|
148
194
|
let response = await fetchAll('drumeo', 'challenge',{customFields:['garbage']});
|
|
149
|
-
|
|
195
|
+
log(response);
|
|
150
196
|
expect(response.entity[0].garbage).toBeDefined();
|
|
151
197
|
expect(response.entity[0].id).toBeDefined();
|
|
152
198
|
|
|
153
199
|
response = await fetchAll('drumeo', 'challenge',{useDefaultFields: false, customFields:['garbage']});
|
|
154
|
-
|
|
200
|
+
log(response);
|
|
155
201
|
expect(response.entity[0].garbage).toBeDefined();
|
|
156
202
|
expect.not.objectContaining(response.entity[0].id);
|
|
157
203
|
});
|
|
158
204
|
|
|
159
205
|
test('fetchRelatedLessons', async () => {
|
|
160
206
|
const id = 380094;
|
|
161
|
-
const document = await fetchByRailContentId(id);
|
|
207
|
+
const document = await fetchByRailContentId(id, 'song');
|
|
162
208
|
let artist = document.artist.name;
|
|
163
209
|
const response = await fetchRelatedLessons(id, 'singeo');
|
|
164
|
-
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id);
|
|
210
|
+
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id, 'song');
|
|
165
211
|
// match on artist or any genre
|
|
166
212
|
let isMatch = artist === relatedDoc.artist.name;
|
|
167
213
|
isMatch = isMatch || document.genre.some((genre) => {
|
|
@@ -177,8 +223,8 @@ describe('Sanity Queries', function () {
|
|
|
177
223
|
const id = 191338; ////https://web-staging-one.musora.com/admin/studio/publishing/structure/play-along;play-along_191338
|
|
178
224
|
const expectedChildID = 191492;
|
|
179
225
|
const response = await fetchChildren(id);
|
|
180
|
-
|
|
181
|
-
|
|
226
|
+
log('num children', response.length);
|
|
227
|
+
log(response);
|
|
182
228
|
|
|
183
229
|
expect(response.length > 0).toBeTruthy();
|
|
184
230
|
const foundExpectedChild = response.some((child) => {
|
|
@@ -209,15 +255,14 @@ describe('Sanity Queries', function () {
|
|
|
209
255
|
});
|
|
210
256
|
|
|
211
257
|
test('fetchMethod', async () => {
|
|
212
|
-
const response = await fetchMethod('drumeo', 'drumeo-method');
|
|
213
|
-
//console.log(response);
|
|
258
|
+
const response = await fetchMethod('drumeo', 'drumeo-method');log(response);
|
|
214
259
|
expect(response).toBeDefined();
|
|
215
260
|
expect(response.levels.length).toBeGreaterThan(0);
|
|
216
261
|
});
|
|
217
262
|
|
|
218
263
|
test('fetchMethods', async () => {
|
|
219
264
|
const response = await fetchMethods('drumeo');
|
|
220
|
-
|
|
265
|
+
log(response);
|
|
221
266
|
expect(response.length).toBeGreaterThan(0);
|
|
222
267
|
expect(response[0].type).toBe('learning-path');
|
|
223
268
|
});
|
|
@@ -250,15 +295,14 @@ describe('Sanity Queries', function () {
|
|
|
250
295
|
});
|
|
251
296
|
|
|
252
297
|
test('fetchFoundation', async () => {
|
|
253
|
-
const response = await fetchFoundation('foundations-2019');
|
|
254
|
-
// console.log(response);
|
|
298
|
+
const response = await fetchFoundation('foundations-2019');log(response);
|
|
255
299
|
expect(response.units.length).toBeGreaterThan(0);
|
|
256
300
|
expect(response.type).toBe('foundation');
|
|
257
301
|
});
|
|
258
302
|
|
|
259
303
|
test('fetchPackAll', async () => {
|
|
260
304
|
const response = await fetchPackAll(212899); //https://web-staging-one.musora.com/admin/studio/publishing/structure/pack;pack_212899%2Cinspect%3Don
|
|
261
|
-
|
|
305
|
+
log(response);
|
|
262
306
|
expect(response.slug).toBe('creative-control');
|
|
263
307
|
});
|
|
264
308
|
|
|
@@ -275,7 +319,7 @@ describe('Sanity Queries', function () {
|
|
|
275
319
|
});
|
|
276
320
|
|
|
277
321
|
test('fetchCoachLessons', async () => {
|
|
278
|
-
const response = await fetchCoachLessons('drumeo',
|
|
322
|
+
const response = await fetchCoachLessons('drumeo',411493, {});
|
|
279
323
|
expect(response.entity.length).toBeGreaterThan(0);
|
|
280
324
|
});
|
|
281
325
|
|
|
@@ -293,4 +337,167 @@ describe('Sanity Queries', function () {
|
|
|
293
337
|
const response = await fetchScheduledReleases('drumeo', {});
|
|
294
338
|
expect(response.length).toBeGreaterThan(0);
|
|
295
339
|
});
|
|
340
|
+
|
|
341
|
+
test('fetchAll-GroupBy-Genre', async () => {
|
|
342
|
+
let response = await fetchAll('drumeo', 'solo',{groupBy: 'genre'});
|
|
343
|
+
log(response);
|
|
344
|
+
expect(response.entity[0].web_url_path).toContain('/drumeo/genres/');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test('fetchAll-GroupBy-Artists', async () => {
|
|
348
|
+
let response = await fetchAll('drumeo', 'song',{groupBy: 'artist'});
|
|
349
|
+
log(response);
|
|
350
|
+
expect(response.entity[0].web_url_path).toContain('/drumeo/artists/');
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test('fetchAll-GroupBy-Instructors', async () => {
|
|
354
|
+
let response = await fetchAll('drumeo', 'course',{groupBy: 'instructor'});
|
|
355
|
+
log(response);
|
|
356
|
+
expect(response.entity[0].web_url_path).toContain('/drumeo/coaches/');
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe('Filter Builder', function () {
|
|
361
|
+
|
|
362
|
+
test('baseConstructor', async () => {
|
|
363
|
+
const filter = 'railcontent_id = 111'
|
|
364
|
+
let builder = new FilterBuilder(filter);
|
|
365
|
+
let finalFilter = builder.buildFilter(filter);
|
|
366
|
+
let clauses = spliceFilterForAnds(finalFilter);
|
|
367
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
368
|
+
expect(clauses[1].field).toBe('published_on');
|
|
369
|
+
|
|
370
|
+
builder = new FilterBuilder();
|
|
371
|
+
finalFilter = builder.buildFilter(filter);
|
|
372
|
+
clauses = spliceFilterForAnds(finalFilter);
|
|
373
|
+
expect(clauses[0].field).toBe('published_on');
|
|
374
|
+
expect(clauses[0].operator).toBe('<=');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('withOnlyFilterAvailableStatuses', async () => {
|
|
378
|
+
const filter = 'railcontent_id = 111'
|
|
379
|
+
const builder = FilterBuilder.withOnlyFilterAvailableStatuses(filter,['published', 'unlisted']);
|
|
380
|
+
const finalFilter = builder.buildFilter();
|
|
381
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
382
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
383
|
+
expect(clauses[1].field).toBe('status');
|
|
384
|
+
expect(clauses[1].operator).toBe('in');
|
|
385
|
+
// not sure I like this
|
|
386
|
+
expect(clauses[1].condition).toBe("['published','unlisted']");
|
|
387
|
+
expect(clauses[2].field).toBe('published_on');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('withContentStatusAndFutureScheduledContent', async () => {
|
|
391
|
+
const filter = 'railcontent_id = 111'
|
|
392
|
+
const builder = new FilterBuilder(filter,{
|
|
393
|
+
availableContentStatuses: ['published', 'unlisted', 'scheduled'],
|
|
394
|
+
getFutureScheduledContentsOnly: true});
|
|
395
|
+
const finalFilter = builder.buildFilter();
|
|
396
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
397
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
398
|
+
expect(clauses[1].field).toBe('(status'); // extra ( because it's a multi part filter
|
|
399
|
+
expect(clauses[1].operator).toBe('in');
|
|
400
|
+
// getFutureScheduledContentsOnly doesn't make a filter that's splicable, so we match on the more static string
|
|
401
|
+
const expected = "['published','unlisted'] || (status == 'scheduled' && published_on >=";
|
|
402
|
+
console.log(clauses[1].condition);
|
|
403
|
+
console.log(expected)
|
|
404
|
+
const isMatch = finalFilter.includes(expected);
|
|
405
|
+
expect(isMatch).toBeTruthy();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test('withUserPermissions', async () => {
|
|
409
|
+
const filter = 'railcontent_id = 111'
|
|
410
|
+
const builder = new FilterBuilder(filter,
|
|
411
|
+
{ user: {
|
|
412
|
+
user: {},
|
|
413
|
+
permissions: [91, 92],
|
|
414
|
+
}});
|
|
415
|
+
const finalFilter = builder.buildFilter();
|
|
416
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
417
|
+
const isMatch = finalFilter.includes(expected);
|
|
418
|
+
expect(isMatch).toBeTruthy();
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
test('withUserPermissionsForPlusUser', async () => {
|
|
422
|
+
const filter = 'railcontent_id = 111'
|
|
423
|
+
const builder = new FilterBuilder(filter,
|
|
424
|
+
{
|
|
425
|
+
user: getPlusUser()
|
|
426
|
+
});
|
|
427
|
+
const finalFilter = builder.buildFilter();
|
|
428
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
429
|
+
const isMatch = finalFilter.includes(expected);
|
|
430
|
+
expect(isMatch).toBeTruthy();
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test('withPermissionBypass', async () => {
|
|
434
|
+
const filter = 'railcontent_id = 111'
|
|
435
|
+
const builder = new FilterBuilder(filter,
|
|
436
|
+
{
|
|
437
|
+
user: getPlusUser(),
|
|
438
|
+
bypassPermissions:true
|
|
439
|
+
});
|
|
440
|
+
const finalFilter = builder.buildFilter();
|
|
441
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
442
|
+
const isMatch = finalFilter.includes(expected);
|
|
443
|
+
expect(isMatch).toBeFalsy();
|
|
444
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
445
|
+
expect(clauses[0].field).toBe('railcontent_id');
|
|
446
|
+
expect(clauses[1].field).toBe('published_on');
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
test('withPublishOnRestrictions', async () => {
|
|
451
|
+
// testing dates is a pain more frustration than I'm willing to deal with, so I'm just testing operators.
|
|
452
|
+
|
|
453
|
+
const filter = 'railcontent_id = 111'
|
|
454
|
+
let builder = new FilterBuilder(filter, {
|
|
455
|
+
user: {},
|
|
456
|
+
pullFutureContent: true,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
let finalFilter = builder.buildFilter();
|
|
460
|
+
let clauses = spliceFilterForAnds(finalFilter);
|
|
461
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
462
|
+
|
|
463
|
+
expect(clauses[1].field).toBe('published_on');
|
|
464
|
+
expect(clauses[1].operator).toBe('<=');
|
|
465
|
+
const restrictionDate = new Date(clauses[1].condition)
|
|
466
|
+
const now = new Date();
|
|
467
|
+
expect(now.getTime()).toBeLessThan(restrictionDate.getTime());
|
|
468
|
+
|
|
469
|
+
builder = new FilterBuilder(filter,
|
|
470
|
+
{
|
|
471
|
+
user: {},
|
|
472
|
+
getFutureContentOnly: true,
|
|
473
|
+
});
|
|
474
|
+
finalFilter = builder.buildFilter();
|
|
475
|
+
clauses = spliceFilterForAnds(finalFilter);
|
|
476
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
477
|
+
expect(clauses[1].field).toBe('published_on');
|
|
478
|
+
expect(clauses[1].operator).toBe('>=');
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
function getPlusUser() {
|
|
482
|
+
return {
|
|
483
|
+
permissions: [91,92],
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function spliceFilterForAnds(filter) {
|
|
488
|
+
// this will not correctly split complex filters with && and || conditions.
|
|
489
|
+
let phrases = filter.split(' && ');
|
|
490
|
+
let clauses= [];
|
|
491
|
+
phrases.forEach((phrase) => {
|
|
492
|
+
let field = phrase.substring(0, phrase.indexOf(' '));
|
|
493
|
+
//if(field.charAt(0) === '(' ) field = field.substring(1);
|
|
494
|
+
const temp = phrase.substring(phrase.indexOf(' ') + 1);
|
|
495
|
+
const operator = temp.substring(0, temp.indexOf(' '));
|
|
496
|
+
let condition = temp.substring(temp.indexOf(' ') + 1);
|
|
497
|
+
//if(condition.charAt(condition.length) === ')') condition = condition.slice(-1);
|
|
498
|
+
clauses.push({phrase, field, operator, condition});
|
|
499
|
+
});
|
|
500
|
+
return clauses;
|
|
501
|
+
}
|
|
502
|
+
|
|
296
503
|
});
|