musora-content-services 1.0.116 → 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.
Files changed (58) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +4 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/config.js.html +0 -0
  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 +0 -0
  25. package/docs/module-Config.html +0 -0
  26. package/docs/module-Railcontent-Services.html +0 -0
  27. package/docs/module-Sanity-Services.html +0 -0
  28. package/docs/railcontent.js.html +0 -0
  29. package/docs/sanity.js.html +0 -0
  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/link_mcs.sh +0 -0
  44. package/package.json +1 -1
  45. package/src/contentMetaData.js +1091 -0
  46. package/src/contentTypeConfig.js +45 -1414
  47. package/src/filterBuilder.js +0 -0
  48. package/src/index.d.ts +0 -0
  49. package/src/index.js +0 -0
  50. package/src/services/config.js +1 -0
  51. package/src/services/railcontent.js +24 -12
  52. package/src/services/sanity.js +118 -71
  53. package/src/services/userContext.js +0 -0
  54. package/test/localStorageMock.js +0 -0
  55. package/test/log.js +0 -0
  56. package/test/sanityQueryService.test.js +126 -6
  57. package/test/userContext.test.js +0 -0
  58. package/tools/generate-index.js +0 -0
File without changes
package/src/index.d.ts CHANGED
File without changes
package/src/index.js CHANGED
File without changes
@@ -19,6 +19,7 @@ let globalConfig = {
19
19
  * @param {string} config.sanityConfig.version - The API version to use.
20
20
  * @param {boolean} [config.sanityConfig.debug=false] - Optional flag to enable debug mode.
21
21
  * @param {boolean} [config.sanityConfig.useCachedAPI=true] - Optional flag to enable or disable the use of the cached API.
22
+ * @param {boolean} [config.sanityConfig.useDummyRailContentMethods=false] - Optional flag to use test harness for railcontent methods. Should only be used by jest tests.
22
23
  * @param {Object} config.railcontentConfig - Configuration for user services.
23
24
  * @param {string} config.railcontentConfig.token - The token for authenticating user-specific requests.
24
25
  * @param {string} config.railcontentConfig.userId - The user ID for fetching user-specific data.
@@ -254,15 +254,6 @@ export async function fetchContentPageUserData(contentId) {
254
254
  }
255
255
  }
256
256
 
257
- function fetchAbsolute(url, params) {
258
- if(globalConfig.railcontentConfig.baseUrl) {
259
- if (url.startsWith('/')) {
260
- return fetch(globalConfig.railcontentConfig.baseUrl + url, params)
261
- }
262
- }
263
- return fetch(url, params);
264
- }
265
-
266
257
  export async function fetchUserContext() {
267
258
  let url = `/content/user_data_all`;
268
259
  const headers = {
@@ -270,7 +261,7 @@ export async function fetchUserContext() {
270
261
  'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
271
262
  };
272
263
  try {
273
- const response = await fetch(url, {headers});
264
+ const response = await fetchAbsolute(url, {headers});
274
265
  const result = await response.json();
275
266
  if (result) {
276
267
  console.log('fetchUserContext', result);
@@ -284,13 +275,25 @@ export async function fetchUserContext() {
284
275
  }
285
276
  }
286
277
 
278
+ export async function fetchUserPermissions() {
279
+ //TODO: Should be investigate why throw 500 errors on MA
280
+ return [];
281
+ let url = `/content/user_data_permissions`;
282
+ const headers = {
283
+ 'Content-Type': 'application/json',
284
+ 'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
285
+ };
286
+ // in the case of an unauthorized user, we return empty permissions
287
+ return fetchHandler(url, 'get') ?? [];
288
+ }
289
+
287
290
  export async function fetchHandler(url, method = "get") {
288
291
  const headers = {
289
292
  'Content-Type': 'application/json',
290
293
  'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
291
294
  };
292
295
  try {
293
- const response = await fetch(url, {method, headers});
296
+ const response = await fetchAbsolute(url, {method, headers});
294
297
  const result = await response.json();
295
298
  if (result) {
296
299
  return result;
@@ -299,8 +302,8 @@ export async function fetchHandler(url, method = "get") {
299
302
  }
300
303
  } catch (error) {
301
304
  console.error('Fetch error:', error);
302
- return null;
303
305
  }
306
+ return null;
304
307
  }
305
308
 
306
309
  export async function fetchLikeContent(contentId) {
@@ -311,4 +314,13 @@ export async function fetchLikeContent(contentId) {
311
314
  export async function fetchUnlikeContent(contentId) {
312
315
  let url = `/content/${contentId}/unlike`;
313
316
  return await fetchHandler(url, "post");
317
+ }
318
+
319
+ function fetchAbsolute(url, params) {
320
+ if(globalConfig.railcontentConfig.baseUrl) {
321
+ if (url.startsWith('/')) {
322
+ return fetch(globalConfig.railcontentConfig.baseUrl + url, params)
323
+ }
324
+ }
325
+ return fetch(url, params);
314
326
  }
@@ -11,13 +11,17 @@ import {
11
11
  getFieldsForContentType,
12
12
  filtersToGroq,
13
13
  getUpcomingEventsTypes,
14
- getNewReleasesTypes,
15
14
  showsTypes,
16
- contentMetadata
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
- let webUrlPath = 'artists';
500
- query = `
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(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id),
511
- 'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{
513
+ 'all_lessons_count': count(*[${lessonsFilter}]._id),
514
+ 'lessons': *[${lessonsFilter}]{
512
515
  ${fieldsString},
513
516
  ${groupBy}
514
517
  }[0...20]
515
- }
516
- |order(${sortOrder})
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
- let webUrlPath = (groupBy == 'genre')?'/genres':'';
521
- query = `
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(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id),
532
- 'lessons': *[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{
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
- query = `
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,13 +594,14 @@ 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 ?
@@ -611,13 +609,16 @@ export async function fetchAllFilterOptions(
611
609
 
612
610
  const commonFilter = `_type == '${contentType}' && brand == "${brand}"${style ? ` && '${style}' in genre[]->name` : ''}${artist ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
613
611
  const metaData = processMetadata(brand, contentType, true);
614
- const allowableFilters = (metaData) ? metaData['allowableFilters'] : [];
612
+ const allowableFilters = metaData?.allowableFilters || [];
615
613
 
616
- let dynamicFilterOptions = '';
617
- allowableFilters.forEach(filter => {
618
- const filterOption = getFilterOptions(filter, commonFilter, contentType);
619
- dynamicFilterOptions += filterOption;
620
- });
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(' ');
621
622
 
622
623
  const query = `
623
624
  {
@@ -970,7 +971,7 @@ export async function fetchAllPacks(brand, sort = "-published_on", searchTerm =
970
971
  const query = buildQuery(
971
972
  filter,
972
973
  filterParams,
973
- fields,
974
+ getFieldsForContentType('pack'),
974
975
  {
975
976
  logo_image_url: 'logo_image_url.asset->url',
976
977
  sortOrder: sortOrder,
@@ -1245,13 +1246,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
1245
1246
  }
1246
1247
 
1247
1248
 
1248
-
1249
1249
  /**
1250
- * Fetch data from the Sanity API based on a provided query.
1251
1250
  *
1252
1251
  * @param {string} query - The GROQ query to execute against the Sanity API.
1253
1252
  * @param {boolean} isList - Whether to return an array or a single result.
1254
- * @returns {Promise<Object|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
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.
1255
1256
  *
1256
1257
  * @example
1257
1258
  * const query = `*[_type == "song"]{title, artist->name}`;
@@ -1259,7 +1260,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
1259
1260
  * .then(data => console.log(data))
1260
1261
  * .catch(error => console.error(error));
1261
1262
  */
1262
- export async function fetchSanity(query, isList) {
1263
+
1264
+ export async function fetchSanity(query,
1265
+ isList,
1266
+ { customPostProcess = null,
1267
+ processNeedAccess = true,} = {}
1268
+ ) {
1269
+
1263
1270
  // Check the config object before proceeding
1264
1271
  if (!checkSanityConfig(globalConfig)) {
1265
1272
  return null;
@@ -1287,7 +1294,9 @@ export async function fetchSanity(query, isList) {
1287
1294
  if (globalConfig.sanityConfig.debug) {
1288
1295
  console.log("fetchSanity Results:", result);
1289
1296
  }
1290
- return isList ? result.result : result.result[0];
1297
+ let results = isList ? result.result : result.result[0];
1298
+ results = processNeedAccess ? await needsAccessDecorator(results) : results;
1299
+ return customPostProcess ? customPostProcess(results) : results;
1291
1300
  } else {
1292
1301
  throw new Error('No results found');
1293
1302
  }
@@ -1297,6 +1306,41 @@ export async function fetchSanity(query, isList) {
1297
1306
  }
1298
1307
  }
1299
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
+
1300
1344
  /**
1301
1345
  * Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
1302
1346
  * It's an ongoing discussion (Aug 2024), but it's been included here if necessary
@@ -1348,7 +1392,7 @@ export async function fetchShowsData(brand) {
1348
1392
  }
1349
1393
 
1350
1394
  /**
1351
- * Fetch metadata from the contentTypeConfig.js based on brand and type.
1395
+ * Fetch metadata from the contentMetaData.js based on brand and type.
1352
1396
  *
1353
1397
  * @param {string} brand - The brand for which to fetch metadata.
1354
1398
  * @param {string} type - The type for which to fetch metadata.
@@ -1459,28 +1503,7 @@ function buildEntityAndTotalQuery(
1459
1503
  }`;
1460
1504
  return query;
1461
1505
  }
1462
- function processMetadata(brand, type, withFilters = false) {
1463
- const metadataElement = contentMetadata[brand]?.[type];
1464
- if (!metadataElement) {
1465
- return null;
1466
- }
1467
- const processedData = {
1468
- type,
1469
- thumbnailUrl: metadataElement.thumbnailUrl || null,
1470
- name: metadataElement.name || null,
1471
- description: metadataElement.description || null
1472
- };
1473
-
1474
- if (withFilters) {
1475
- Object.keys(metadataElement).forEach(key => {
1476
- if ( !['thumbnailUrl', 'name', 'description'].includes(key) ) {
1477
- processedData[key] = metadataElement[key];
1478
- }
1479
- });
1480
- }
1481
1506
 
1482
- return processedData;
1483
- }
1484
1507
 
1485
1508
  function getFilterOptions(option, commonFilter,contentType){
1486
1509
  let filterGroq = '';
@@ -1540,6 +1563,30 @@ function getFilterOptions(option, commonFilter,contentType){
1540
1563
  return filterGroq;
1541
1564
  }
1542
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 '';
1579
+ }
1580
+
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;
1588
+ }
1589
+
1543
1590
 
1544
1591
 
1545
1592
 
File without changes
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
- test('fetchByRailContentId', async () => {
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
 
@@ -518,7 +579,7 @@ describe('Filter Builder', function () {
518
579
  }
519
580
 
520
581
  test('fetchAllFilterOptions', async () => {
521
- let response = await fetchAllFilterOptions('drumeo', '', '', '', 'song', '');
582
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'song', '');
522
583
  log(response);
523
584
  expect(response.meta.filterOptions.difficulty).toBeDefined();
524
585
  expect(response.meta.filterOptions.genre).toBeDefined();
@@ -527,14 +588,14 @@ describe('Filter Builder', function () {
527
588
  });
528
589
 
529
590
  test('fetchAllFilterOptions-Rudiment', async () => {
530
- let response = await fetchAllFilterOptions('drumeo', '', '', '', 'rudiment', '');
591
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'rudiment', '');
531
592
  log(response);
532
593
  expect(response.meta.filterOptions.gear).toBeDefined();
533
594
  expect(response.meta.filterOptions.genre).toBeDefined();
534
595
  expect(response.meta.filterOptions.topic).toBeDefined();
535
596
  });
536
597
  test('fetchAllFilterOptions-PlayAlong', async () => {
537
- let response = await fetchAllFilterOptions('drumeo', '', '', '', 'play-along', '');
598
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'play-along', '');
538
599
  log(response);
539
600
  expect(response.meta.filterOptions.difficulty).toBeDefined();
540
601
  expect(response.meta.filterOptions.genre).toBeDefined();
@@ -542,11 +603,70 @@ describe('Filter Builder', function () {
542
603
  });
543
604
 
544
605
  test('fetchAllFilterOptions-Coaches', async () => {
545
- let response = await fetchAllFilterOptions('drumeo', '', '', '', 'instructor', '');
606
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'instructor', '');
546
607
  log(response);
547
608
  expect(response.meta.filterOptions.focus).toBeDefined();
548
609
  expect(response.meta.filterOptions.focus.length).toBeGreaterThan(0);
549
610
  expect(response.meta.filterOptions.genre).toBeDefined();
550
611
  expect(response.meta.filterOptions.genre.length).toBeGreaterThan(0);
551
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
+ });
552
672
  });
File without changes
File without changes