musora-content-services 1.0.142 → 1.0.144
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/.github/workflows/node.js.yml +0 -0
- package/CHANGELOG.md +4 -0
- package/README.md +0 -0
- package/babel.config.js +0 -0
- package/docs/config.js.html +8 -4
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/index.html +2 -2
- package/docs/module-Config.html +30 -5
- package/docs/module-Railcontent-Services.html +2 -2
- package/docs/module-Sanity-Services.html +285 -46
- package/docs/railcontent.js.html +19 -2
- package/docs/sanity.js.html +79 -73
- package/docs/scripts/collapse.js +0 -0
- package/docs/scripts/commonNav.js +0 -0
- package/docs/scripts/linenumber.js +0 -0
- package/docs/scripts/nav.js +0 -0
- package/docs/scripts/polyfill.js +0 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
- package/docs/scripts/prettify/lang-css.js +0 -0
- package/docs/scripts/prettify/prettify.js +0 -0
- package/docs/scripts/search.js +0 -0
- package/docs/styles/jsdoc.css +0 -0
- package/docs/styles/prettify.css +0 -0
- package/jest.config.js +0 -0
- package/jsdoc.json +0 -0
- package/link_mcs.sh +0 -0
- package/package.json +1 -1
- package/src/contentMetaData.js +0 -0
- package/src/contentTypeConfig.js +1 -0
- package/src/filterBuilder.js +0 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +6 -0
- package/src/services/config.js +0 -0
- package/src/services/contentLikes.js +0 -0
- package/src/services/dataContext.js +0 -0
- package/src/services/railcontent.js +17 -0
- package/src/services/sanity.js +55 -71
- package/test/contentLikes.test.js +0 -0
- package/test/localStorageMock.js +0 -0
- package/test/log.js +0 -0
- package/test/sanityQueryService.test.js +0 -0
- package/tools/generate-index.js +0 -0
- package/test/playlists.test.js +0 -86
package/src/services/sanity.js
CHANGED
|
@@ -586,101 +586,84 @@ export function getSortOrder(sort= '-published_on', groupBy)
|
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
/**
|
|
589
|
-
* Fetches all available filter options based on
|
|
589
|
+
* Fetches all available filter options based on brand, filters, and various optional criteria.
|
|
590
590
|
*
|
|
591
591
|
* This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
|
|
592
592
|
* The filter options are dynamically generated based on the provided filters, style, artist, and content type.
|
|
593
593
|
* If a coachId is provided, the content type must be 'coach-lessons'.
|
|
594
594
|
*
|
|
595
|
-
* @param {string} brand -
|
|
596
|
-
* @param {string[]} filters -
|
|
597
|
-
* @param {string} [style] - Optional style
|
|
598
|
-
* @param {string} [artist] - Optional artist name
|
|
599
|
-
* @param {string} contentType -
|
|
600
|
-
* @param {string} [term] - Optional search term
|
|
601
|
-
* @param {Array<string>} [progressIds
|
|
602
|
-
* @param {string} [coachId
|
|
603
|
-
* @
|
|
595
|
+
* @param {string} brand - Brand to filter.
|
|
596
|
+
* @param {string[]} filters - Key-value pairs to filter the query.
|
|
597
|
+
* @param {string} [style] - Optional style/genre filter.
|
|
598
|
+
* @param {string} [artist] - Optional artist name filter.
|
|
599
|
+
* @param {string} contentType - Content type (e.g., 'song', 'lesson').
|
|
600
|
+
* @param {string} [term] - Optional search term for title, album, artist, or genre.
|
|
601
|
+
* @param {Array<string>} [progressIds] - Optional array of progress IDs to filter by.
|
|
602
|
+
* @param {string} [coachId] - Optional coach ID (only valid if contentType is 'coach-lessons').
|
|
603
|
+
* @param {boolean} [includeTabs=false] - Whether to include tabs in the returned metadata.
|
|
604
|
+
* @returns {Promise<Object>} - The filter options and metadata.
|
|
605
|
+
* @throws {Error} If coachId is provided but contentType isn't 'coach-lessons'.
|
|
604
606
|
*
|
|
605
|
-
* @throws {Error} Will throw an error if coachId is provided but contentType is not 'coach-lessons'.
|
|
606
|
-
*
|
|
607
607
|
* @example
|
|
608
|
-
* //
|
|
609
|
-
* fetchAllFilterOptions('myBrand',
|
|
608
|
+
* // Fetch filter options for 'song' content type:
|
|
609
|
+
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
|
|
610
610
|
* .then(options => console.log(options))
|
|
611
611
|
* .catch(error => console.error(error));
|
|
612
612
|
*
|
|
613
613
|
* @example
|
|
614
|
-
* //
|
|
615
|
-
* fetchAllFilterOptions('myBrand',
|
|
614
|
+
* // Fetch filter options for a coach's lessons with coachId:
|
|
615
|
+
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
|
|
616
616
|
* .then(options => console.log(options))
|
|
617
617
|
* .catch(error => console.error(error));
|
|
618
618
|
*/
|
|
619
619
|
export async function fetchAllFilterOptions(
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
620
|
+
brand,
|
|
621
|
+
filters = [],
|
|
622
|
+
style,
|
|
623
|
+
artist,
|
|
624
|
+
contentType,
|
|
625
|
+
term,
|
|
626
|
+
progressIds,
|
|
627
|
+
coachId,
|
|
628
|
+
includeTabs = false,
|
|
628
629
|
) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
filters = Array.isArray(filters) ? filters : [];
|
|
635
|
-
const includedFieldsFilter = filters?.length > 0 ? filtersToGroq(filters) : undefined;
|
|
636
|
-
|
|
637
|
-
const progressFilter = progressIds !== undefined ?
|
|
638
|
-
`&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
630
|
+
if (coachId && contentType !== 'coach-lessons') {
|
|
631
|
+
throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
|
|
632
|
+
}
|
|
639
633
|
|
|
640
|
-
|
|
641
|
-
|
|
634
|
+
const includedFieldsFilter = filters?.length ? filtersToGroq(filters) : undefined;
|
|
635
|
+
const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
642
636
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
637
|
+
const constructCommonFilter = (excludeFilter) => {
|
|
638
|
+
const filterWithoutOption = excludeFilter ? filtersToGroq(filters, excludeFilter) : includedFieldsFilter;
|
|
639
|
+
return coachId
|
|
640
|
+
? `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''}`
|
|
641
|
+
: `_type == '${contentType}' && brand == "${brand}"${style && excludeFilter !== "style" ? ` && '${style}' in genre[]->name` : ''}${artist && excludeFilter !== "artist" ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${filterWithoutOption || ''}`;
|
|
642
|
+
};
|
|
650
643
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
644
|
+
const metaData = processMetadata(brand, contentType, true);
|
|
645
|
+
const allowableFilters = metaData?.allowableFilters || [];
|
|
646
|
+
const tabs = metaData?.tabs || [];
|
|
654
647
|
|
|
655
|
-
|
|
656
|
-
const dynamicFilterOptions = allowableFilters.map(filter => {
|
|
657
|
-
let includedFieldsFilterWithoutSelectedOption = filters?.length > 0 ? filtersToGroq(filters, filter) : undefined;
|
|
658
|
-
let commonFilterWithoutSelectedOption;
|
|
648
|
+
const dynamicFilterOptions = allowableFilters.map(filter => getFilterOptions(filter, constructCommonFilter(filter), contentType, brand)).join(' ');
|
|
659
649
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
650
|
+
const query = `
|
|
651
|
+
{
|
|
652
|
+
"meta": {
|
|
653
|
+
"totalResults": count(*[${constructCommonFilter()}
|
|
654
|
+
${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
|
|
655
|
+
"filterOptions": {
|
|
656
|
+
${dynamicFilterOptions}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}`;
|
|
666
660
|
|
|
667
|
-
|
|
668
|
-
return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType, brand);
|
|
669
|
-
}).join(' ');
|
|
661
|
+
const results = await fetchSanity(query, true, { processNeedAccess: false });
|
|
670
662
|
|
|
671
|
-
|
|
672
|
-
{
|
|
673
|
-
"meta": {
|
|
674
|
-
"totalResults": count(*[${commonFilter}
|
|
675
|
-
${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
|
|
676
|
-
"filterOptions": {
|
|
677
|
-
${dynamicFilterOptions}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}`;
|
|
681
|
-
return fetchSanity(query, true, {processNeedAccess:false});
|
|
663
|
+
return includeTabs ? { ...results, tabs } : results;
|
|
682
664
|
}
|
|
683
665
|
|
|
666
|
+
|
|
684
667
|
/**
|
|
685
668
|
* Fetch children content by Railcontent ID.
|
|
686
669
|
* @param {string} railcontentId - The Railcontent ID of the parent content.
|
|
@@ -961,7 +944,8 @@ export async function fetchLessonContent(railContentId) {
|
|
|
961
944
|
mp3_yes_drums_yes_click_url,
|
|
962
945
|
"permission_id": permission[]->railcontent_id,
|
|
963
946
|
parent_content_data,
|
|
964
|
-
sort
|
|
947
|
+
sort,
|
|
948
|
+
xp`;
|
|
965
949
|
const query = buildQuery(
|
|
966
950
|
`railcontent_id == ${railContentId}`,
|
|
967
951
|
filterParams,
|
|
File without changes
|
package/test/localStorageMock.js
CHANGED
|
File without changes
|
package/test/log.js
CHANGED
|
File without changes
|
|
File without changes
|
package/tools/generate-index.js
CHANGED
|
File without changes
|
package/test/playlists.test.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import {isContentLiked, dataContext, likeContent, unlikeContent} from "../src/services/contentLikes";
|
|
2
|
-
import {LocalStorageMock} from "./localStorageMock";
|
|
3
|
-
import {initializeService} from "../src";
|
|
4
|
-
|
|
5
|
-
const railContentModule = require('../src/services/railcontent.js')
|
|
6
|
-
|
|
7
|
-
describe('playlistsContext', function () {
|
|
8
|
-
let mock = null;
|
|
9
|
-
const testVersion = 1;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
initializeService({localStorage: new LocalStorageMock()});
|
|
13
|
-
mock = jest.spyOn(dataContext, 'fetchData');
|
|
14
|
-
var json = JSON.parse(`{"version":${testVersion},"data":[308516,308515,308514,308518]}`);
|
|
15
|
-
mock.mockImplementation(() => json);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('contentLiked', async () => {
|
|
19
|
-
let result = await isContentLiked(308516);
|
|
20
|
-
expect(result).toBe(true);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('contentNotLiked', async () => {
|
|
24
|
-
let result = await isContentLiked(121111);
|
|
25
|
-
expect(result).toBe(false);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('ensureOnlyOneServerFetchRequest', async () => {
|
|
29
|
-
dataContext.clearCache();
|
|
30
|
-
await isContentLiked(308516);
|
|
31
|
-
await isContentLiked(308514);
|
|
32
|
-
await isContentLiked(121111);
|
|
33
|
-
expect(dataContext.fetchData).toHaveBeenCalledTimes(1);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('ensureDataPulledFromLocalCache', async () => {
|
|
37
|
-
dataContext.clearCache();
|
|
38
|
-
await isContentLiked(308516);
|
|
39
|
-
dataContext.clearContext();
|
|
40
|
-
await isContentLiked(308514);
|
|
41
|
-
expect(dataContext.fetchData).toHaveBeenCalledTimes(1);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('likeContent', async () => {
|
|
45
|
-
mock = jest.spyOn(railContentModule, 'postContentLiked');
|
|
46
|
-
var json = JSON.parse(`{"version":${testVersion + 1}}`);
|
|
47
|
-
mock.mockImplementation(() => json);
|
|
48
|
-
|
|
49
|
-
dataContext.clearCache();
|
|
50
|
-
let isLiked = await isContentLiked(111111);
|
|
51
|
-
expect(isLiked).toBe(false);
|
|
52
|
-
|
|
53
|
-
await likeContent(111111);
|
|
54
|
-
isLiked = await isContentLiked(111111);
|
|
55
|
-
expect(isLiked).toBe(true);
|
|
56
|
-
|
|
57
|
-
dataContext.clearContext();
|
|
58
|
-
isLiked = await isContentLiked(111111);
|
|
59
|
-
expect(isLiked).toBe(true);
|
|
60
|
-
|
|
61
|
-
expect(dataContext.version()).toBe(testVersion + 1);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
test('unlikeContent', async () => {
|
|
66
|
-
mock = jest.spyOn(railContentModule, 'postContentUnliked');
|
|
67
|
-
var json = JSON.parse(`{"version":${testVersion + 1}}`);
|
|
68
|
-
mock.mockImplementation(() => json);
|
|
69
|
-
|
|
70
|
-
dataContext.clearCache();
|
|
71
|
-
let isLiked = await isContentLiked(308516);
|
|
72
|
-
expect(isLiked).toBe(true);
|
|
73
|
-
|
|
74
|
-
await unlikeContent(308516);
|
|
75
|
-
console.log(dataContext.context);
|
|
76
|
-
isLiked = await isContentLiked(308516);
|
|
77
|
-
expect(isLiked).toBe(false);
|
|
78
|
-
|
|
79
|
-
dataContext.clearContext();
|
|
80
|
-
isLiked = await isContentLiked(308516);
|
|
81
|
-
expect(isLiked).toBe(false);
|
|
82
|
-
|
|
83
|
-
expect(dataContext.version()).toBe(testVersion + 1);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
});
|