musora-content-services 1.0.115 → 1.0.118
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 +6 -0
- package/README.md +0 -0
- package/babel.config.js +0 -0
- package/docs/config.js.html +0 -0
- 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 +0 -0
- package/docs/module-Config.html +0 -0
- package/docs/module-Railcontent-Services.html +0 -0
- package/docs/module-Sanity-Services.html +0 -0
- package/docs/railcontent.js.html +0 -0
- package/docs/sanity.js.html +0 -0
- 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/package.json +2 -1
- package/src/contentMetaData.js +1091 -0
- package/src/contentTypeConfig.js +45 -1414
- package/src/filterBuilder.js +0 -0
- package/src/index.d.ts +137 -88
- package/src/index.js +135 -97
- package/src/services/config.js +1 -0
- package/src/services/railcontent.js +24 -12
- package/src/services/sanity.js +178 -77
- package/src/services/userContext.js +0 -0
- package/test/localStorageMock.js +0 -0
- package/test/log.js +0 -0
- package/test/sanityQueryService.test.js +154 -2
- package/test/userContext.test.js +0 -0
- package/tools/generate-index.js +85 -0
package/src/services/sanity.js
CHANGED
|
@@ -11,13 +11,17 @@ import {
|
|
|
11
11
|
getFieldsForContentType,
|
|
12
12
|
filtersToGroq,
|
|
13
13
|
getUpcomingEventsTypes,
|
|
14
|
-
getNewReleasesTypes,
|
|
15
14
|
showsTypes,
|
|
16
|
-
|
|
15
|
+
getNewReleasesTypes,
|
|
17
16
|
} from "../contentTypeConfig";
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
processMetadata,
|
|
20
|
+
} from "../contentMetaData";
|
|
21
|
+
|
|
18
22
|
import {globalConfig} from "./config";
|
|
19
23
|
|
|
20
|
-
import { fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
|
|
24
|
+
import { fetchUserPermissions, fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
|
|
21
25
|
import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -495,58 +499,51 @@ export async function fetchAll(brand, type, {
|
|
|
495
499
|
|
|
496
500
|
// Determine the group by clause
|
|
497
501
|
let query = "";
|
|
502
|
+
let entityFieldsString = "";
|
|
503
|
+
let filter = "";
|
|
498
504
|
if (groupBy !== "" && isGroupByOneToOne) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
"total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
|
|
503
|
-
"entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
|
|
504
|
-
{
|
|
505
|
+
const webUrlPath = 'artists';
|
|
506
|
+
const lessonsFilter = `_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
|
|
507
|
+
entityFieldsString = `
|
|
505
508
|
'id': _id,
|
|
506
509
|
'type': _type,
|
|
507
510
|
name,
|
|
508
511
|
'head_shot_picture_url': thumbnail_url.asset->url,
|
|
509
512
|
'web_url_path': '/${brand}/${webUrlPath}/'+name+'?included_fieds[]=type,${type}',
|
|
510
|
-
'all_lessons_count': count(*[
|
|
511
|
-
'lessons': *[
|
|
513
|
+
'all_lessons_count': count(*[${lessonsFilter}]._id),
|
|
514
|
+
'lessons': *[${lessonsFilter}]{
|
|
512
515
|
${fieldsString},
|
|
513
516
|
${groupBy}
|
|
514
517
|
}[0...20]
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
[${start}...${end}]
|
|
518
|
-
}`;
|
|
518
|
+
`;
|
|
519
|
+
filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
|
|
519
520
|
} else if (groupBy !== "") {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
"total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
|
|
524
|
-
"entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
|
|
525
|
-
{
|
|
521
|
+
const webUrlPath = (groupBy == 'genre')?'/genres':'';
|
|
522
|
+
const lessonsFilter = `brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
|
|
523
|
+
entityFieldsString = `
|
|
526
524
|
'id': _id,
|
|
527
525
|
'type': _type,
|
|
528
526
|
name,
|
|
529
527
|
'head_shot_picture_url': thumbnail_url.asset->url,
|
|
530
528
|
'web_url_path': select(defined(web_url_path)=> web_url_path +'?included_fieds[]=type,${type}',!defined(web_url_path)=> '/${brand}${webUrlPath}/'+name+'/${webUrlPathType}'),
|
|
531
|
-
'all_lessons_count': count(*[
|
|
532
|
-
'lessons': *[
|
|
529
|
+
'all_lessons_count': count(*[${lessonsFilter}]._id),
|
|
530
|
+
'lessons': *[${lessonsFilter}]{
|
|
533
531
|
${fieldsString},
|
|
534
532
|
${groupBy}
|
|
535
|
-
}[0...20]
|
|
536
|
-
|
|
537
|
-
|order(${sortOrder})
|
|
538
|
-
[${start}...${end}]
|
|
539
|
-
}`;
|
|
533
|
+
}[0...20]`;
|
|
534
|
+
filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
|
|
540
535
|
} else {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
"entity": *[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}] | order(${sortOrder}) [${start}...${end}] {
|
|
544
|
-
${fieldsString},
|
|
545
|
-
},
|
|
546
|
-
"total": count(*[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}])
|
|
547
|
-
}
|
|
548
|
-
`;
|
|
536
|
+
filter = `brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`
|
|
537
|
+
entityFieldsString = fieldsString;
|
|
549
538
|
}
|
|
539
|
+
query = buildEntityAndTotalQuery(
|
|
540
|
+
filter,
|
|
541
|
+
entityFieldsString,
|
|
542
|
+
{
|
|
543
|
+
sortOrder: sortOrder,
|
|
544
|
+
start: start,
|
|
545
|
+
end: end,
|
|
546
|
+
});
|
|
550
547
|
|
|
551
548
|
return fetchSanity(query, true);
|
|
552
549
|
}
|
|
@@ -597,40 +594,39 @@ export function getSortOrder(sort= '-published_on', groupBy)
|
|
|
597
594
|
*/
|
|
598
595
|
export async function fetchAllFilterOptions(
|
|
599
596
|
brand,
|
|
600
|
-
filters,
|
|
597
|
+
filters = [],
|
|
601
598
|
style,
|
|
602
599
|
artist,
|
|
603
600
|
contentType,
|
|
604
601
|
term,
|
|
605
602
|
progressIds = undefined
|
|
606
603
|
) {
|
|
604
|
+
filters = Array.isArray(filters) ? filters : [];
|
|
607
605
|
const includedFieldsFilter = filters?.length > 0 ? filtersToGroq(filters) : undefined;
|
|
608
606
|
|
|
609
607
|
const progressFilter = progressIds !== undefined ?
|
|
610
608
|
`&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
611
609
|
|
|
612
610
|
const commonFilter = `_type == '${contentType}' && brand == "${brand}"${style ? ` && '${style}' in genre[]->name` : ''}${artist ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
|
|
611
|
+
const metaData = processMetadata(brand, contentType, true);
|
|
612
|
+
const allowableFilters = metaData?.allowableFilters || [];
|
|
613
|
+
|
|
614
|
+
const dynamicFilterOptions = allowableFilters.map(filter => {
|
|
615
|
+
// Create a modified common filter for each allowable filter
|
|
616
|
+
let includedFieldsFilterWithoutSelectedOption = filters?.length > 0 ? filtersToGroq(filters, filter) : undefined;
|
|
617
|
+
const commonFilterWithoutSelectedOption = `_type == '${contentType}' && brand == "${brand}"${(style && filter !== "style") ? ` && '${style}' in genre[]->name` : ''}${(artist && filter !== "artist") ? ` && artist->name == '${artist}'` : ''} ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
|
|
618
|
+
|
|
619
|
+
// Call getFilterOptions with the modified common filter
|
|
620
|
+
return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType);
|
|
621
|
+
}).join(' ');
|
|
622
|
+
|
|
613
623
|
const query = `
|
|
614
624
|
{
|
|
615
625
|
"meta": {
|
|
616
626
|
"totalResults": count(*[${commonFilter}
|
|
617
627
|
${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
|
|
618
628
|
"filterOptions": {
|
|
619
|
-
|
|
620
|
-
{"type": "Introductory", "count": count(*[${commonFilter} && difficulty_string == "Introductory"])},
|
|
621
|
-
{"type": "Beginner", "count": count(*[${commonFilter} && difficulty_string == "Beginner"])},
|
|
622
|
-
{"type": "Intermediate", "count": count(*[${commonFilter} && difficulty_string == "Intermediate" ])},
|
|
623
|
-
{"type": "Advanced", "count": count(*[${commonFilter} && difficulty_string == "Advanced" ])},
|
|
624
|
-
{"type": "Expert", "count": count(*[${commonFilter} && difficulty_string == "Expert" ])}
|
|
625
|
-
][count > 0],
|
|
626
|
-
"instrumentless": [
|
|
627
|
-
{"type": "Full Song Only", "count": count(*[${commonFilter} && instrumentless == false ])},
|
|
628
|
-
{"type": "Instrument Removed", "count": count(*[${commonFilter} && instrumentless == true ])}
|
|
629
|
-
][count > 0],
|
|
630
|
-
"genre": *[_type == 'genre' && '${contentType}' in filter_types] {
|
|
631
|
-
"type": name,
|
|
632
|
-
"count": count(*[${commonFilter} && references(^._id)])
|
|
633
|
-
}[count > 0]
|
|
629
|
+
${dynamicFilterOptions}
|
|
634
630
|
}
|
|
635
631
|
}
|
|
636
632
|
}`;
|
|
@@ -971,10 +967,11 @@ export async function fetchAllPacks(brand, sort = "-published_on", searchTerm =
|
|
|
971
967
|
const sortOrder = getSortOrder(sort);
|
|
972
968
|
const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
|
|
973
969
|
const filterParams = {};
|
|
970
|
+
const fields = getFieldsForContentType('pack');
|
|
974
971
|
const query = buildQuery(
|
|
975
972
|
filter,
|
|
976
973
|
filterParams,
|
|
977
|
-
|
|
974
|
+
getFieldsForContentType('pack'),
|
|
978
975
|
{
|
|
979
976
|
logo_image_url: 'logo_image_url.asset->url',
|
|
980
977
|
sortOrder: sortOrder,
|
|
@@ -1249,13 +1246,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
|
|
|
1249
1246
|
}
|
|
1250
1247
|
|
|
1251
1248
|
|
|
1252
|
-
|
|
1253
1249
|
/**
|
|
1254
|
-
* Fetch data from the Sanity API based on a provided query.
|
|
1255
1250
|
*
|
|
1256
1251
|
* @param {string} query - The GROQ query to execute against the Sanity API.
|
|
1257
1252
|
* @param {boolean} isList - Whether to return an array or a single result.
|
|
1258
|
-
* @
|
|
1253
|
+
* @param {Function} [customPostProcess=null] - custom post process callback
|
|
1254
|
+
* @param {boolean} [processNeedAccess=true] - execute the needs_access callback
|
|
1255
|
+
* @returns {Promise<*|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
|
|
1259
1256
|
*
|
|
1260
1257
|
* @example
|
|
1261
1258
|
* const query = `*[_type == "song"]{title, artist->name}`;
|
|
@@ -1263,7 +1260,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
|
|
|
1263
1260
|
* .then(data => console.log(data))
|
|
1264
1261
|
* .catch(error => console.error(error));
|
|
1265
1262
|
*/
|
|
1266
|
-
|
|
1263
|
+
|
|
1264
|
+
export async function fetchSanity(query,
|
|
1265
|
+
isList,
|
|
1266
|
+
{ customPostProcess = null,
|
|
1267
|
+
processNeedAccess = true,} = {}
|
|
1268
|
+
) {
|
|
1269
|
+
|
|
1267
1270
|
// Check the config object before proceeding
|
|
1268
1271
|
if (!checkSanityConfig(globalConfig)) {
|
|
1269
1272
|
return null;
|
|
@@ -1291,7 +1294,9 @@ export async function fetchSanity(query, isList) {
|
|
|
1291
1294
|
if (globalConfig.sanityConfig.debug) {
|
|
1292
1295
|
console.log("fetchSanity Results:", result);
|
|
1293
1296
|
}
|
|
1294
|
-
|
|
1297
|
+
let results = isList ? result.result : result.result[0];
|
|
1298
|
+
results = processNeedAccess ? await needsAccessDecorator(results) : results;
|
|
1299
|
+
return customPostProcess ? customPostProcess(results) : results;
|
|
1295
1300
|
} else {
|
|
1296
1301
|
throw new Error('No results found');
|
|
1297
1302
|
}
|
|
@@ -1301,6 +1306,41 @@ export async function fetchSanity(query, isList) {
|
|
|
1301
1306
|
}
|
|
1302
1307
|
}
|
|
1303
1308
|
|
|
1309
|
+
async function needsAccessDecorator(results)
|
|
1310
|
+
{
|
|
1311
|
+
if (globalConfig.sanityConfig.useDummyRailContentMethods) return results;
|
|
1312
|
+
let userPermissions = await getUserPermissions();
|
|
1313
|
+
userPermissions = new Set(userPermissions);
|
|
1314
|
+
if (Array.isArray(results)) {
|
|
1315
|
+
results.forEach((result) => {
|
|
1316
|
+
result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
|
|
1317
|
+
});
|
|
1318
|
+
} else {
|
|
1319
|
+
results['need_access'] = doesUserNeedAccessToContent(results, userPermissions);
|
|
1320
|
+
}
|
|
1321
|
+
return results;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
function doesUserNeedAccessToContent(result, userPermissions)
|
|
1325
|
+
{
|
|
1326
|
+
const permissions = new Set(result.permission_id ?? []);
|
|
1327
|
+
if (permissions.length === 0) {
|
|
1328
|
+
return false;
|
|
1329
|
+
}
|
|
1330
|
+
for (let permission of permissions) {
|
|
1331
|
+
if (userPermissions.has(permission)) {
|
|
1332
|
+
return false;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
async function getUserPermissions()
|
|
1339
|
+
{
|
|
1340
|
+
return await fetchUserPermissions();
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
|
|
1304
1344
|
/**
|
|
1305
1345
|
* Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
|
|
1306
1346
|
* It's an ongoing discussion (Aug 2024), but it's been included here if necessary
|
|
@@ -1352,7 +1392,7 @@ export async function fetchShowsData(brand) {
|
|
|
1352
1392
|
}
|
|
1353
1393
|
|
|
1354
1394
|
/**
|
|
1355
|
-
* Fetch metadata from the
|
|
1395
|
+
* Fetch metadata from the contentMetaData.js based on brand and type.
|
|
1356
1396
|
*
|
|
1357
1397
|
* @param {string} brand - The brand for which to fetch metadata.
|
|
1358
1398
|
* @param {string} type - The type for which to fetch metadata.
|
|
@@ -1463,27 +1503,88 @@ function buildEntityAndTotalQuery(
|
|
|
1463
1503
|
}`;
|
|
1464
1504
|
return query;
|
|
1465
1505
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
function getFilterOptions(option, commonFilter,contentType){
|
|
1509
|
+
let filterGroq = '';
|
|
1510
|
+
switch (option) {
|
|
1511
|
+
case "difficulty":
|
|
1512
|
+
filterGroq = `
|
|
1513
|
+
"difficulty": [
|
|
1514
|
+
{"type": "Introductory", "count": count(*[${commonFilter} && difficulty_string == "Introductory"])},
|
|
1515
|
+
{"type": "Beginner", "count": count(*[${commonFilter} && difficulty_string == "Beginner"])},
|
|
1516
|
+
{"type": "Intermediate", "count": count(*[${commonFilter} && difficulty_string == "Intermediate" ])},
|
|
1517
|
+
{"type": "Advanced", "count": count(*[${commonFilter} && difficulty_string == "Advanced" ])},
|
|
1518
|
+
{"type": "Expert", "count": count(*[${commonFilter} && difficulty_string == "Expert" ])}
|
|
1519
|
+
][count > 0],`;
|
|
1520
|
+
break;
|
|
1521
|
+
case "genre":
|
|
1522
|
+
case "essential":
|
|
1523
|
+
case "focus":
|
|
1524
|
+
case "theory":
|
|
1525
|
+
case "topic":
|
|
1526
|
+
case "lifestyle":
|
|
1527
|
+
case "creativity":
|
|
1528
|
+
filterGroq = `
|
|
1529
|
+
"${option}": *[_type == '${option}' && '${contentType}' in filter_types] {
|
|
1530
|
+
"type": name,
|
|
1531
|
+
"count": count(*[${commonFilter} && references(^._id)])
|
|
1532
|
+
}[count > 0],`;
|
|
1533
|
+
break;
|
|
1534
|
+
case "instrumentless":
|
|
1535
|
+
filterGroq = `
|
|
1536
|
+
"${option}": [
|
|
1537
|
+
{"type": "Full Song Only", "count": count(*[${commonFilter} && instrumentless == false ])},
|
|
1538
|
+
{"type": "Instrument Removed", "count": count(*[${commonFilter} && instrumentless == true ])}
|
|
1539
|
+
][count > 0],`;
|
|
1540
|
+
break;
|
|
1541
|
+
case "gear":
|
|
1542
|
+
filterGroq = `
|
|
1543
|
+
"${option}": [
|
|
1544
|
+
{"type": "Practice Pad", "count": count(*[${commonFilter} && gear match 'Practice Pad' ])},
|
|
1545
|
+
{"type": "Drum-Set", "count": count(*[${commonFilter} && gear match 'Drum-Set'])}
|
|
1546
|
+
][count > 0],`;
|
|
1547
|
+
break;
|
|
1548
|
+
case "bpm":
|
|
1549
|
+
filterGroq = `
|
|
1550
|
+
"${option}": [
|
|
1551
|
+
{"type": "50-90", "count": count(*[${commonFilter} && bpm > 50 && bpm < 91])},
|
|
1552
|
+
{"type": "91-120", "count": count(*[${commonFilter} && bpm > 90 && bpm < 121])},
|
|
1553
|
+
{"type": "121-150", "count": count(*[${commonFilter} && bpm > 120 && bpm < 151])},
|
|
1554
|
+
{"type": "151-180", "count": count(*[${commonFilter} && bpm > 150 && bpm < 181])},
|
|
1555
|
+
{"type": "180+", "count": count(*[${commonFilter} && bpm > 180])},
|
|
1556
|
+
][count > 0],`;
|
|
1557
|
+
break;
|
|
1558
|
+
default:
|
|
1559
|
+
filterGroq = "";
|
|
1560
|
+
break;
|
|
1470
1561
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1562
|
+
|
|
1563
|
+
return filterGroq;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
function cleanUpGroq(query) {
|
|
1567
|
+
// Split the query into clauses based on the logical operators
|
|
1568
|
+
const clauses = query.split(/(\s*&&|\s*\|\|)/).map(clause => clause.trim());
|
|
1569
|
+
|
|
1570
|
+
// Filter out empty clauses
|
|
1571
|
+
const filteredClauses = clauses.filter(clause => clause.length > 0);
|
|
1572
|
+
|
|
1573
|
+
// Check if there are valid conditions in the clauses
|
|
1574
|
+
const hasConditions = filteredClauses.some(clause => !clause.match(/^\s*&&\s*|\s*\|\|\s*$/));
|
|
1575
|
+
|
|
1576
|
+
if (!hasConditions) {
|
|
1577
|
+
// If no valid conditions, return an empty string or the original query
|
|
1578
|
+
return '';
|
|
1484
1579
|
}
|
|
1485
1580
|
|
|
1486
|
-
|
|
1581
|
+
// Remove occurrences of '&& ()'
|
|
1582
|
+
const cleanedQuery = filteredClauses.join(' ')
|
|
1583
|
+
.replace(/&&\s*\(\)/g, '')
|
|
1584
|
+
.replace(/(\s*&&|\s*\|\|)(?=\s*[\s()]*$|(?=\s*&&|\s*\|\|))/g, '')
|
|
1585
|
+
.trim();
|
|
1586
|
+
|
|
1587
|
+
return cleanedQuery;
|
|
1487
1588
|
}
|
|
1488
1589
|
|
|
1489
1590
|
|
|
File without changes
|
package/test/localStorageMock.js
CHANGED
|
File without changes
|
package/test/log.js
CHANGED
|
File without changes
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {initializeService} from '../src/services/config.js';
|
|
2
|
+
import {getFieldsForContentType} from "../src/contentTypeConfig";
|
|
3
|
+
import {fetchSanity} from "../src/services/sanity";
|
|
2
4
|
import {log} from './log.js';
|
|
3
5
|
|
|
4
6
|
const {
|
|
@@ -14,6 +16,7 @@ const {
|
|
|
14
16
|
fetchByRailContentId,
|
|
15
17
|
fetchByRailContentIds,
|
|
16
18
|
fetchAll,
|
|
19
|
+
fetchAllOld,
|
|
17
20
|
fetchAllFilterOptions,
|
|
18
21
|
fetchFoundation,
|
|
19
22
|
fetchMethods,
|
|
@@ -39,6 +42,10 @@ const {
|
|
|
39
42
|
FilterBuilder,
|
|
40
43
|
} = require('../src/filterBuilder.js');
|
|
41
44
|
|
|
45
|
+
const {
|
|
46
|
+
processMetadata,
|
|
47
|
+
} = require('../src/contentMetaData.js');
|
|
48
|
+
|
|
42
49
|
describe('Sanity Queries', function () {
|
|
43
50
|
beforeEach(() => {
|
|
44
51
|
const config = {
|
|
@@ -48,7 +55,8 @@ describe('Sanity Queries', function () {
|
|
|
48
55
|
dataset: process.env.SANITY_DATASET,
|
|
49
56
|
useCachedAPI: process.env.SANITY_USE_CACHED_API === 'true' || true,
|
|
50
57
|
version: '2021-06-07',
|
|
51
|
-
debug: process.env.DEBUG === 'true' || false
|
|
58
|
+
debug: process.env.DEBUG === 'true' || false,
|
|
59
|
+
useDummyRailContentMethods: true,
|
|
52
60
|
}
|
|
53
61
|
};
|
|
54
62
|
initializeService(config);
|
|
@@ -61,6 +69,7 @@ describe('Sanity Queries', function () {
|
|
|
61
69
|
|
|
62
70
|
});
|
|
63
71
|
|
|
72
|
+
|
|
64
73
|
test('fetchArtists', async () => {
|
|
65
74
|
const response = await fetchArtists('drumeo');
|
|
66
75
|
const artistNames = response.map((x) => x.name);
|
|
@@ -72,9 +81,29 @@ describe('Sanity Queries', function () {
|
|
|
72
81
|
const response = await fetchSongArtistCount('drumeo');
|
|
73
82
|
log(response);
|
|
74
83
|
expect(response).toBeGreaterThan(1000);
|
|
84
|
+
}, 10000);
|
|
85
|
+
|
|
86
|
+
test('fetchSanity-WithPostProcess', async () => {
|
|
87
|
+
const id = 380094;
|
|
88
|
+
const query = `*[railcontent_id == ${id}]{
|
|
89
|
+
${getFieldsForContentType('song')}
|
|
90
|
+
}`
|
|
91
|
+
const newSlug = 'keysmash1';
|
|
92
|
+
const newField = 1
|
|
93
|
+
const postProcess = (result) => {
|
|
94
|
+
result['new_field'] = newField;
|
|
95
|
+
result['slug'] = newSlug;
|
|
96
|
+
return result;
|
|
97
|
+
};
|
|
98
|
+
const response = await fetchSanity(query, false, {customPostProcess: postProcess});
|
|
99
|
+
log(response);
|
|
100
|
+
expect(response.id).toBe(id);
|
|
101
|
+
expect(response.new_field).toBe(newField);
|
|
102
|
+
expect(response.slug).toBe(newSlug);
|
|
75
103
|
});
|
|
76
104
|
|
|
77
|
-
|
|
105
|
+
|
|
106
|
+
test('fetchSanityPostProcess', async () => {
|
|
78
107
|
const id = 380094;
|
|
79
108
|
const response = await fetchByRailContentId(id, "song");
|
|
80
109
|
expect(response.id).toBe(id);
|
|
@@ -85,6 +114,7 @@ describe('Sanity Queries', function () {
|
|
|
85
114
|
const response = await fetchChallengeOverview(id);
|
|
86
115
|
expect(response.lessons).toBeDefined();
|
|
87
116
|
expect(response.id).toBe(id);
|
|
117
|
+
|
|
88
118
|
});
|
|
89
119
|
|
|
90
120
|
test('fetchByRailContentIds', async () => {
|
|
@@ -327,6 +357,37 @@ describe('Sanity Queries', function () {
|
|
|
327
357
|
|
|
328
358
|
test('fetchAll-IncludedFields', async () => {
|
|
329
359
|
let response = await fetchAll('drumeo', 'instructor',{includedFields: ['is_active']});
|
|
360
|
+
console.log(response);
|
|
361
|
+
expect(response.entity.length).toBeGreaterThan(0);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('fetchAll-IncludedFields-multiple', async () => {
|
|
365
|
+
let response = await fetchAll('drumeo', 'course',{includedFields: ['essential,Dynamics','essential,Timing','difficulty,Beginner']});
|
|
366
|
+
log(response);
|
|
367
|
+
expect(response.entity.length).toBeGreaterThan(0);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test('fetchAll-IncludedFields-playalong-multiple', async () => {
|
|
371
|
+
let response = await fetchAll('drumeo', 'play-along',{includedFields: ['bpm,91-120','bpm,181+','genre,Blues']});
|
|
372
|
+
log(response);
|
|
373
|
+
expect(response.entity.length).toBeGreaterThan(0);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('fetchAll-IncludedFields-rudiment-multiple-gear', async () => {
|
|
377
|
+
let response = await fetchAll('drumeo', 'rudiment',{includedFields: ['gear,Drum-Set','gear,Practice Pad']});
|
|
378
|
+
log(response);
|
|
379
|
+
expect(response.entity.length).toBeGreaterThan(0);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test('fetchAll-IncludedFields-coaches-multiple-focus', async () => {
|
|
383
|
+
let response = await fetchAll('drumeo', 'instructor',{includedFields: ['focus,drumline','focus,recording']});
|
|
384
|
+
log(response);
|
|
385
|
+
expect(response.entity.length).toBeGreaterThan(0);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test('fetchAll-IncludedFields-songs-multiple-instrumentless', async () => {
|
|
389
|
+
let response = await fetchAll('drumeo', 'song',{includedFields: ['instrumentless,true','instrumentless,false']});
|
|
390
|
+
log(response);
|
|
330
391
|
expect(response.entity.length).toBeGreaterThan(0);
|
|
331
392
|
});
|
|
332
393
|
|
|
@@ -517,4 +578,95 @@ describe('Filter Builder', function () {
|
|
|
517
578
|
return clauses;
|
|
518
579
|
}
|
|
519
580
|
|
|
581
|
+
test('fetchAllFilterOptions', async () => {
|
|
582
|
+
let response = await fetchAllFilterOptions('drumeo', [], '', '', 'song', '');
|
|
583
|
+
log(response);
|
|
584
|
+
expect(response.meta.filterOptions.difficulty).toBeDefined();
|
|
585
|
+
expect(response.meta.filterOptions.genre).toBeDefined();
|
|
586
|
+
expect(response.meta.filterOptions.lifestyle).toBeDefined();
|
|
587
|
+
expect(response.meta.filterOptions.instrumentless).toBeDefined();
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
test('fetchAllFilterOptions-Rudiment', async () => {
|
|
591
|
+
let response = await fetchAllFilterOptions('drumeo', [], '', '', 'rudiment', '');
|
|
592
|
+
log(response);
|
|
593
|
+
expect(response.meta.filterOptions.gear).toBeDefined();
|
|
594
|
+
expect(response.meta.filterOptions.genre).toBeDefined();
|
|
595
|
+
expect(response.meta.filterOptions.topic).toBeDefined();
|
|
596
|
+
});
|
|
597
|
+
test('fetchAllFilterOptions-PlayAlong', async () => {
|
|
598
|
+
let response = await fetchAllFilterOptions('drumeo', [], '', '', 'play-along', '');
|
|
599
|
+
log(response);
|
|
600
|
+
expect(response.meta.filterOptions.difficulty).toBeDefined();
|
|
601
|
+
expect(response.meta.filterOptions.genre).toBeDefined();
|
|
602
|
+
expect(response.meta.filterOptions.bpm).toBeDefined();
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
test('fetchAllFilterOptions-Coaches', async () => {
|
|
606
|
+
let response = await fetchAllFilterOptions('drumeo', [], '', '', 'instructor', '');
|
|
607
|
+
log(response);
|
|
608
|
+
expect(response.meta.filterOptions.focus).toBeDefined();
|
|
609
|
+
expect(response.meta.filterOptions.focus.length).toBeGreaterThan(0);
|
|
610
|
+
expect(response.meta.filterOptions.genre).toBeDefined();
|
|
611
|
+
expect(response.meta.filterOptions.genre.length).toBeGreaterThan(0);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
test('fetchAllFilterOptions-filter-selected', async () => {
|
|
615
|
+
let response = await fetchAllFilterOptions('drumeo', ['theory,notation','theory,time signatures','creativity,Grooves','creativity,Fills & Chops','difficulty,Beginner','difficulty,Intermediate','difficulty,Expert'], '', '', 'course', '');
|
|
616
|
+
log(response);
|
|
617
|
+
expect(response.meta.filterOptions).toBeDefined();
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
describe('MetaData', function () {
|
|
622
|
+
|
|
623
|
+
test('customBrandTypeExists', async () => {
|
|
624
|
+
const metaData = processMetadata('guitareo', 'recording');
|
|
625
|
+
expect(metaData.type).toBe('recording');
|
|
626
|
+
expect(metaData.name).toBe('Archives');
|
|
627
|
+
expect(metaData.description).toBeDefined();
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
test('invalidContentType', async () => {
|
|
631
|
+
const metaData = processMetadata('guitareo', 'not a real type');
|
|
632
|
+
expect(metaData).toBeNull();
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
test('onlyCommon', async () => {
|
|
636
|
+
const guitareoMetaData = processMetadata('guitareo', 'challenge');
|
|
637
|
+
const drumeoMetaData = processMetadata('drumeo', 'challenge');
|
|
638
|
+
expect(guitareoMetaData).toStrictEqual(drumeoMetaData);
|
|
639
|
+
expect(guitareoMetaData.type).toBe('challenge');
|
|
640
|
+
expect(guitareoMetaData.name).toBe('Challenges');
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test('withCommon', async () => {
|
|
644
|
+
const guitareoMetaData = processMetadata('guitareo', 'instructor');
|
|
645
|
+
const drumeoMetaData = processMetadata('drumeo', 'instructor');
|
|
646
|
+
expect(guitareoMetaData.description).not.toBe(drumeoMetaData.description);
|
|
647
|
+
guitareoMetaData.description = ''
|
|
648
|
+
drumeoMetaData.description = ''
|
|
649
|
+
expect(guitareoMetaData).toStrictEqual(drumeoMetaData);
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
test('withWithoutFilters', async () => {
|
|
653
|
+
let metaData = processMetadata('singeo', 'student-review', true);
|
|
654
|
+
expect(metaData.type).toBeDefined()
|
|
655
|
+
expect(metaData.name).toBeDefined()
|
|
656
|
+
expect(metaData.description).toBeDefined();
|
|
657
|
+
expect(metaData.thumbnailUrl).toBeDefined();
|
|
658
|
+
expect(metaData.tabs).toBeDefined();
|
|
659
|
+
metaData = processMetadata('singeo', 'student-review', false);
|
|
660
|
+
expect(metaData.type).toBeDefined()
|
|
661
|
+
expect(metaData.name).toBeDefined()
|
|
662
|
+
expect(metaData.description).toBeDefined();
|
|
663
|
+
expect(metaData.tabs).not.toBeDefined();
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test('nulled', async () => {
|
|
667
|
+
let metaData = processMetadata('drumeo', 'student-review');
|
|
668
|
+
expect(metaData).toBeNull();
|
|
669
|
+
metaData = processMetadata('singeo', 'student-review');
|
|
670
|
+
expect(metaData).not.toBeNull();
|
|
671
|
+
});
|
|
520
672
|
});
|
package/test/userContext.test.js
CHANGED
|
File without changes
|