musora-content-services 1.0.18 → 1.0.20

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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.0.19](https://github.com/railroadmedia/musora-content-services/compare/v1.0.18...v1.0.19) (2024-08-13)
6
+
5
7
  ### [1.0.18](https://github.com/railroadmedia/musora-content-services/compare/v1.0.17...v1.0.18) (2024-08-13)
6
8
 
7
9
  ### [1.0.17](https://github.com/railroadmedia/musora-content-services/compare/v1.0.16...v1.0.17) (2024-08-13)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/docs/global.html CHANGED
@@ -5330,7 +5330,7 @@ initializeSanityService({
5330
5330
  <br class="clear">
5331
5331
 
5332
5332
  <footer>
5333
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 18:37:07 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
5333
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 19:10:16 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
5334
5334
  </footer>
5335
5335
 
5336
5336
  <script>prettyPrint();</script>
package/docs/index.html CHANGED
@@ -103,7 +103,7 @@ Run the following to execute the tests</p>
103
103
  <br class="clear">
104
104
 
105
105
  <footer>
106
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 18:37:07 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
106
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 19:10:16 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
107
107
  </footer>
108
108
 
109
109
  <script>prettyPrint();</script>
@@ -543,9 +543,9 @@ async function fetchLiveEvent(brand) {
543
543
  // Adjust the query to filter events based on the calculated time window
544
544
  const query = `
545
545
  *[_type in [${typesString}] &amp;&amp; brand == '${brand}'
546
- &amp;&amp; published_on > '${twoDaysAgo}'
547
- &amp;&amp; published_on &lt;= '${now}'
548
- &amp;&amp; dateTime(published_on) + length_in_seconds * 1000 > '${now}'] {
546
+ &amp;&amp; published_on > '${twoDaysAgo}'
547
+ || (published_on &lt;= '${now}' &amp;&amp; dateTime(published_on) + length_in_seconds * 1000 > '${now}')
548
+ ] {
549
549
  "id": railcontent_id,
550
550
  title,
551
551
  "image": thumbnail.asset->url,
@@ -1081,6 +1081,7 @@ module.exports = {
1081
1081
  fetchSongCount,
1082
1082
  fetchWorkouts,
1083
1083
  fetchNewReleases,
1084
+ fetchLiveEvent,
1084
1085
  fetchUpcomingEvents,
1085
1086
  fetchByRailContentId,
1086
1087
  fetchByRailContentIds,
@@ -1108,7 +1109,7 @@ module.exports = {
1108
1109
  <br class="clear">
1109
1110
 
1110
1111
  <footer>
1111
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 18:37:07 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1112
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 13 2024 19:10:16 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1112
1113
  </footer>
1113
1114
 
1114
1115
  <script>prettyPrint();</script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/publish.sh CHANGED
File without changes
@@ -0,0 +1,30 @@
1
+ let contentTypeConfig = {
2
+ 'song': {
3
+ 'fields': [
4
+ '"artist_name": artist->name',
5
+ 'soundslice',
6
+ 'instrumentless'
7
+ ],
8
+ 'relationships': {
9
+ 'artist': {
10
+ isOneToOne: true
11
+ }
12
+ }
13
+ },
14
+ 'challenge':{
15
+ 'fields':[
16
+ 'enrollment_start_time',
17
+ 'enrollment_end_time',
18
+ 'registration_url',
19
+ '"lesson_count": child_count',
20
+ '"primary_cta_text": select(dateTime(published_on) > dateTime(now()) && dateTime(enrollment_start_time) > dateTime(now()) => "Notify Me", "Start Challenge")',
21
+ 'challenge_state',
22
+ 'challenge_state_text',
23
+ ]
24
+ }
25
+ }
26
+
27
+
28
+ module.exports = {
29
+ contentTypeConfig
30
+ }
package/src/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ const {contentTypeConfig} = require('../src/contentTypeConfig.js');
2
+
1
3
  let globalConfig = {};
2
4
 
3
5
  /**
@@ -11,7 +13,7 @@ let globalConfig = {};
11
13
  * @param {string} config.version - The API version to use.
12
14
  * @param {boolean} [config.debug=false] - Optional flag to enable debug mode, which logs the query and results.
13
15
  * @param {boolean} [config.useCachedAPI=true] - Optional flag to disable cached API.
14
- *
16
+ *
15
17
  * @example
16
18
  * // Initialize the Sanity service in your app.js
17
19
  * initializeSanityService({
@@ -179,7 +181,7 @@ async function fetchRelatedSongs(brand, songId) {
179
181
  * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
180
182
  * @param {string} [params.groupBy=""] - The field to group the results by.
181
183
  * @returns {Promise<Object|null>} - The fetched song data or null if not found.
182
- *
184
+ *
183
185
  * @example
184
186
  * fetchAllSongs('drumeo', {
185
187
  * page: 2,
@@ -200,124 +202,7 @@ async function fetchAllSongs(brand, {
200
202
  includedFields = [],
201
203
  groupBy = ""
202
204
  }) {
203
- console.log('groupBy', groupBy)
204
- const start = (page - 1) * limit;
205
- const end = start + limit;
206
-
207
- // Construct the search filter
208
- const searchFilter = searchTerm
209
- ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
210
- : "";
211
-
212
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
213
- const includedFieldsFilter = includedFields.length > 0
214
- ? includedFields.map(field => {
215
- let [key, value] = field.split(',');
216
- if (key === 'difficulty') {
217
- key = 'difficulty_string';
218
- }
219
- return `&& ${key} == "${value}"`;
220
- }).join(' ')
221
- : "";
222
-
223
- // Determine the sort order
224
- let sortOrder;
225
- switch (sort) {
226
- case "slug":
227
- sortOrder = "artist->name asc";
228
- break;
229
- case "published_on":
230
- sortOrder = "published_on desc";
231
- break;
232
- case "-published_on":
233
- sortOrder = "published_on asc";
234
- break;
235
- case "-slug":
236
- sortOrder = "artist->name desc";
237
- break;
238
- case "-popularity":
239
- sortOrder = "popularity desc";
240
- break;
241
- default:
242
- sortOrder = "published_on asc";
243
- break;
244
- }
245
-
246
- // Determine the group by clause
247
- let query = "";
248
- if (groupBy === "artist") {
249
- query = `
250
- {
251
- "total": count(*[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]),
252
- "entity": *[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]
253
- {
254
- 'id': _id,
255
- 'type': _type,
256
- name,
257
- 'head_shot_picture_url': thumbnail_url.asset->url,
258
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id),
259
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]{
260
- "id": railcontent_id,
261
- "type": _type,
262
- title,
263
- "thumbnail_url": thumbnail.asset->url,
264
- "artist_name": artist->name,
265
- difficulty_string,
266
- published_on,
267
- soundslice,
268
- instrumentless,
269
- }[0...10]
270
- }
271
- |order(${sortOrder})
272
- [${start}...${end}]
273
- }`;
274
- } else if (groupBy === "style") {
275
- query = `
276
- {
277
- "total": count(*[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id) > 0]),
278
- "entity":
279
- *[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id)>0]
280
- {
281
- 'id': _id,
282
- 'type': _type,
283
- name,
284
- 'head_shot_picture_url': thumbnail_url.asset->url,
285
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id),
286
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]{
287
- "id": railcontent_id,
288
- "type": _type,
289
- title,
290
- "thumbnail_url": thumbnail.asset->url,
291
- "artist_name": artist->name,
292
- difficulty_string,
293
- published_on,
294
- soundslice,
295
- instrumentless,
296
- }[0...10]
297
- }
298
- |order(${sortOrder})
299
- [${start}...${end}]
300
- }`;
301
- } else {
302
- query = `
303
- {
304
- "entity": *[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
305
- "id": railcontent_id,
306
- "type": _type,
307
- title,
308
- "thumbnail_url": thumbnail.asset->url,
309
- "artist_name": artist->name,
310
- difficulty_string,
311
- published_on,
312
- soundslice,
313
- instrumentless,
314
- },
315
- "total": count(*[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
316
- }
317
- `;
318
- }
319
-
320
- return fetchSanity(query, true);
205
+ return fetchAll(brand, 'song', {page, limit, searchTerm, sort, includedFields, groupBy});
321
206
  }
322
207
 
323
208
  /**
@@ -496,9 +381,9 @@ async function fetchLiveEvent(brand) {
496
381
  // Adjust the query to filter events based on the calculated time window
497
382
  const query = `
498
383
  *[_type in [${typesString}] && brand == '${brand}'
499
- && published_on > '${twoDaysAgo}'
500
- && published_on <= '${now}'
501
- && dateTime(published_on) + length_in_seconds * 1000 > '${now}'] {
384
+ && published_on > '${twoDaysAgo}'
385
+ || (published_on <= '${now}' && dateTime(published_on) + length_in_seconds * 1000 > '${now}')
386
+ ] {
502
387
  "id": railcontent_id,
503
388
  title,
504
389
  "image": thumbnail.asset->url,
@@ -581,7 +466,7 @@ async function fetchByRailContentIds(ids) {
581
466
  * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
582
467
  * @param {string} [params.groupBy=""] - The field to group the results by (e.g., 'artist', 'genre').
583
468
  * @returns {Promise<Object|null>} - The fetched content data or null if not found.
584
- *
469
+ *
585
470
  * @example
586
471
  * fetchAll('drumeo', 'song', {
587
472
  * page: 2,
@@ -602,6 +487,9 @@ async function fetchAll(brand, type, {
602
487
  includedFields = [],
603
488
  groupBy = ""
604
489
  }) {
490
+ let config = contentTypeConfig[type] ?? {};
491
+ let additionalFields = config?.fields ?? [];
492
+ let isGroupByOneToOne = (groupBy ? config?.relationships[groupBy]?.isOneToOne : false) ?? false;
605
493
  const start = (page - 1) * limit;
606
494
  const end = start + limit;
607
495
 
@@ -644,10 +532,20 @@ async function fetchAll(brand, type, {
644
532
  break;
645
533
  }
646
534
 
535
+ let defaultFields = ['railcontent_id',
536
+ 'title',
537
+ '"image": thumbnail.asset->url',
538
+ 'difficulty',
539
+ 'difficulty_string',
540
+ 'web_url_path',
541
+ 'published_on'];
542
+
543
+ let fields = defaultFields.concat(additionalFields);
544
+ let fieldsString = fields.join(',');
545
+
647
546
  // Determine the group by clause
648
547
  let query = "";
649
- let manyReference = true; //TODO: define whether reference is one to one or one to many
650
- if (groupBy !== "" && !manyReference) {
548
+ if (groupBy !== "" && isGroupByOneToOne) {
651
549
  query = `
652
550
  {
653
551
  "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]),
@@ -659,20 +557,14 @@ async function fetchAll(brand, type, {
659
557
  'head_shot_picture_url': thumbnail_url.asset->url,
660
558
  'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id),
661
559
  'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]{
662
- railcontent_id,
663
- title,
664
- "image": thumbnail.asset->url,
665
- difficulty,
666
- difficulty_string,
667
- web_url_path,
668
- published_on,
669
- ${groupBy}
560
+ ${fieldsString},
561
+ ${groupBy}
670
562
  }[0...10]
671
563
  }
672
564
  |order(${sortOrder})
673
565
  [${start}...${end}]
674
566
  }`;
675
- } else if (groupBy !== "" && manyReference) {
567
+ } else if (groupBy !== "") {
676
568
  query = `
677
569
  {
678
570
  "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id)>0]),
@@ -684,14 +576,8 @@ async function fetchAll(brand, type, {
684
576
  'head_shot_picture_url': thumbnail_url.asset->url,
685
577
  'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]._id),
686
578
  'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]{
687
- railcontent_id,
688
- title,
689
- "image": thumbnail.asset->url,
690
- difficulty,
691
- difficulty_string,
692
- web_url_path,
693
- published_on,
694
- ${groupBy}
579
+ ${fieldsString},
580
+ ${groupBy}
695
581
  }[0...10]
696
582
  }
697
583
  |order(${sortOrder})
@@ -701,20 +587,14 @@ async function fetchAll(brand, type, {
701
587
  query = `
702
588
  {
703
589
  "entity": *[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
704
- railcontent_id,
705
- title,
706
- "image": thumbnail.asset->url,
707
- difficulty,
708
- difficulty_string,
709
- web_url_path,
710
- published_on
590
+ ${fieldsString}
711
591
  },
712
592
  "total": count(*[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
713
593
  }
714
594
  `;
715
595
  }
716
596
 
717
- return fetchSanity(query, false);
597
+ return fetchSanity(query, true);
718
598
  }
719
599
 
720
600
  /**
@@ -739,14 +619,14 @@ async function fetchAll(brand, type, {
739
619
  * .catch(error => console.error(error));
740
620
  */
741
621
  async function fetchAllFilterOptions(
742
- brand,
743
- filters,
744
- style,
745
- artist,
746
- contentType,
747
- term
748
- ){
749
- const query = `
622
+ brand,
623
+ filters,
624
+ style,
625
+ artist,
626
+ contentType,
627
+ term
628
+ ) {
629
+ const query = `
750
630
  {
751
631
  "meta": {
752
632
  "totalResults": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} ${filters}
@@ -772,7 +652,7 @@ async function fetchAllFilterOptions(
772
652
  }
773
653
  `;
774
654
 
775
- return fetchSanity(query, false);
655
+ return fetchSanity(query, false);
776
656
  }
777
657
 
778
658
  /**
@@ -852,7 +732,7 @@ async function fetchNextPreviousLesson(railcontentId) {
852
732
  * Fetch the page data for a specific lesson by Railcontent ID.
853
733
  * @param {string} railContentId - The Railcontent ID of the current lesson.
854
734
  * @returns {Promise<Object|null>} - The fetched page data or null if found.
855
- *
735
+ *
856
736
  * @example
857
737
  * fetchLessonContent('lesson123')
858
738
  * .then(data => console.log(data))
@@ -932,7 +812,7 @@ async function fetchPackAll(railcontentId) {
932
812
  * Fetch all children of a specific pack by Railcontent ID.
933
813
  * @param {string} railcontentId - The Railcontent ID of the pack.
934
814
  * @returns {Promise<Array<Object>|null>} - The fetched pack children data or null if not found.
935
- *
815
+ *
936
816
  * @example
937
817
  * fetchPackChildren('pack123')
938
818
  * .then(children => console.log(children))
@@ -956,38 +836,38 @@ async function fetchPackChildren(railcontentId) {
956
836
  * .catch(error => console.error(error));
957
837
  */
958
838
  async function fetchSanity(query, isList) {
959
- // Check the config object before proceeding
960
- if (!checkConfig(globalConfig)) {
961
- return null;
962
- }
839
+ // Check the config object before proceeding
840
+ if (!checkConfig(globalConfig)) {
841
+ return null;
842
+ }
963
843
 
964
- if (globalConfig.debug) {
965
- console.log("fetchSanity Query:", query);
966
- }
844
+ if (globalConfig.debug) {
845
+ console.log("fetchSanity Query:", query);
846
+ }
967
847
 
968
- const encodedQuery = encodeURIComponent(query);
969
- const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
970
- const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
971
- const headers = {
972
- 'Authorization': `Bearer ${globalConfig.token}`,
973
- 'Content-Type': 'application/json'
974
- };
848
+ const encodedQuery = encodeURIComponent(query);
849
+ const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
850
+ const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
851
+ const headers = {
852
+ 'Authorization': `Bearer ${globalConfig.token}`,
853
+ 'Content-Type': 'application/json'
854
+ };
975
855
 
976
- try {
977
- const response = await fetch(url, {headers});
978
- const result = await response.json();
979
- if (result.result) {
980
- if (globalConfig.debug) {
981
- console.log("fetchSanity Results:", result);
982
- }
983
- return isList ? result.result : result.result[0];
984
- } else {
985
- throw new Error('No results found');
986
- }
987
- } catch (error) {
988
- console.error('fetchSanity: Fetch error:', error);
989
- return null;
990
- }
856
+ try {
857
+ const response = await fetch(url, {headers});
858
+ const result = await response.json();
859
+ if (result.result) {
860
+ if (globalConfig.debug) {
861
+ console.log("fetchSanity Results:", result);
862
+ }
863
+ return isList ? result.result : result.result[0];
864
+ } else {
865
+ throw new Error('No results found');
866
+ }
867
+ } catch (error) {
868
+ console.error('fetchSanity: Fetch error:', error);
869
+ return null;
870
+ }
991
871
  }
992
872
 
993
873
 
@@ -79,6 +79,41 @@ describe('Sanity Queries', function () {
79
79
  expect(response.railcontent_id).toBe(id);
80
80
  });
81
81
 
82
+ test('fetchAllSongs', async () => {
83
+ const response = await fetchAllSongs('drumeo', {});
84
+ console.log(response);
85
+ expect(response.entity[0].soundslice).toBeDefined();
86
+ expect(response.entity[0].artist_name).toBeDefined();
87
+ expect(response.entity[0].instrumentless).toBeDefined();
88
+ });
89
+
90
+ test('fetchAllSongsGroupByArtist', async () => {
91
+ const response = await fetchAllSongs('drumeo', {groupBy:"artist"});
92
+ expect(response.entity[0].lessons[0].soundslice).toBeDefined();
93
+ expect(response.entity[0].lessons[0].artist_name).toBeDefined();
94
+ expect(response.entity[0].lessons[0].instrumentless).toBeDefined();
95
+ }, 100000);
96
+
97
+
98
+ test('fetchAllWorkouts', async () => {
99
+ const response = await fetchAll('drumeo', 'workout',{});
100
+ console.log(response);
101
+ expect(response.entity[0].railcontent_id).toBeDefined();
102
+ });
103
+
104
+ test('fetchAllChallenges', async () => {
105
+ const response = await fetchAll('drumeo', 'challenge',{});
106
+ console.log(response);
107
+ expect(response.entity[0].registration_url).toBeDefined();
108
+ expect(response.entity[0].enrollment_start_time).toBeDefined();
109
+ expect(response.entity[0].enrollment_end_time).toBeDefined();
110
+
111
+ expect(response.entity[0].lesson_count).toBeDefined();
112
+ expect(response.entity[0].primary_cta_text).toBeDefined();
113
+ expect(response.entity[0].challenge_state).toBeDefined();
114
+ expect(response.entity[0].challenge_state_text).toBeDefined();
115
+
116
+ });
82
117
  // test('fetchRelatedLessons', async () => {
83
118
  // const id = 380094;
84
119
  // const response = await fetchRelatedLessons(id, 'singeo', 'song');