musora-content-services 2.0.7 → 2.1.0
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/.prettierignore +0 -0
- package/.prettierrc +0 -0
- package/CHANGELOG.md +9 -0
- package/README.md +0 -0
- package/babel.config.cjs +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/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/package.json +1 -1
- package/src/contentTypeConfig.js +6 -0
- package/src/index.d.ts +12 -7
- package/src/index.js +11 -7
- package/src/services/contentLikes.js +0 -0
- package/src/services/contentProgress.js +3 -3
- package/src/services/railcontent.js +11 -23
- package/src/services/recommendations.js +2 -2
- package/src/services/sanity.js +76 -3
- package/test/contentProgress.test.js +3 -3
- package/test/initializeTests.js +2 -2
- package/test/live/contentProgressLive.test.js +0 -0
- package/test/live/railcontentLive.test.js +0 -0
- package/test/localStorageMock.js +0 -0
- package/test/log.js +0 -0
- package/test/sanityQueryService.test.js +142 -102
|
File without changes
|
package/.prettierignore
CHANGED
|
File without changes
|
package/.prettierrc
CHANGED
|
File without changes
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
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
|
+
## [2.1.0](https://github.com/railroadmedia/musora-content-services/compare/v2.0.8...v2.1.0) (2025-03-26)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **BEH-326:** update routing for top/all comment endpoints ([#203](https://github.com/railroadmedia/musora-content-services/issues/203)) ([1f4807f](https://github.com/railroadmedia/musora-content-services/commit/1f4807fcef3cb7ce0b03202519b4ccb4fbd6232f))
|
|
11
|
+
|
|
12
|
+
### [2.0.8](https://github.com/railroadmedia/musora-content-services/compare/v2.0.7...v2.0.8) (2025-03-25)
|
|
13
|
+
|
|
5
14
|
### [2.0.7](https://github.com/railroadmedia/musora-content-services/compare/v2.0.6...v2.0.7) (2025-03-21)
|
|
6
15
|
|
|
7
16
|
|
package/README.md
CHANGED
|
File without changes
|
package/babel.config.cjs
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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/scripts/collapse.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/docs/scripts/nav.js
CHANGED
|
File without changes
|
package/docs/scripts/polyfill.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/docs/scripts/search.js
CHANGED
|
File without changes
|
package/docs/styles/jsdoc.css
CHANGED
|
File without changes
|
package/docs/styles/prettify.css
CHANGED
|
File without changes
|
package/jest.config.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/src/contentTypeConfig.js
CHANGED
|
@@ -3,6 +3,12 @@ import {Tabs} from "./contentMetaData.js";
|
|
|
3
3
|
|
|
4
4
|
export const AWSUrl = 'https://s3.us-east-1.amazonaws.com/musora-web-platform'
|
|
5
5
|
export const CloudFrontURl = 'https://d3fzm1tzeyr5n3.cloudfront.net'
|
|
6
|
+
|
|
7
|
+
export const SONG_TYPES = ['song', 'play-along', 'jam-track', 'song-tutorial-children']
|
|
8
|
+
// Challenges are excluded for the moment as they're still in design flex
|
|
9
|
+
// Single hierarchy refers to only one element in the hierarchy has video lessons, not that they have a single parent
|
|
10
|
+
export const SINGLE_PARENT_TYPES = ['course-part', 'pack-bundle-lesson', 'song-tutorial-children']
|
|
11
|
+
|
|
6
12
|
export const DEFAULT_FIELDS = [
|
|
7
13
|
"'sanity_id' : _id",
|
|
8
14
|
"'id': railcontent_id",
|
package/src/index.d.ts
CHANGED
|
@@ -96,7 +96,6 @@ import {
|
|
|
96
96
|
pinPlaylist,
|
|
97
97
|
playback,
|
|
98
98
|
postChallengesCommunityNotification,
|
|
99
|
-
postChallengesCompleteLesson,
|
|
100
99
|
postChallengesEnroll,
|
|
101
100
|
postChallengesEnrollmentNotification,
|
|
102
101
|
postChallengesHideCompletedBanner,
|
|
@@ -104,7 +103,7 @@ import {
|
|
|
104
103
|
postChallengesSetStartDate,
|
|
105
104
|
postChallengesSoloNotification,
|
|
106
105
|
postChallengesUnlock,
|
|
107
|
-
|
|
106
|
+
postContentComplete,
|
|
108
107
|
postContentLiked,
|
|
109
108
|
postContentReset,
|
|
110
109
|
postContentUnliked,
|
|
@@ -120,10 +119,10 @@ import {
|
|
|
120
119
|
} from './services/railcontent.js';
|
|
121
120
|
|
|
122
121
|
import {
|
|
122
|
+
fetchSimilarItems,
|
|
123
123
|
rankCategories,
|
|
124
124
|
rankItems,
|
|
125
|
-
recommendations
|
|
126
|
-
similarItems
|
|
125
|
+
recommendations
|
|
127
126
|
} from './services/recommendations.js';
|
|
128
127
|
|
|
129
128
|
import {
|
|
@@ -144,6 +143,7 @@ import {
|
|
|
144
143
|
fetchHierarchy,
|
|
145
144
|
fetchLeaving,
|
|
146
145
|
fetchLessonContent,
|
|
146
|
+
fetchLessonsFeaturingThisContent,
|
|
147
147
|
fetchLiveEvent,
|
|
148
148
|
fetchMetadata,
|
|
149
149
|
fetchMethod,
|
|
@@ -152,12 +152,14 @@ import {
|
|
|
152
152
|
fetchMethodPreviousNextLesson,
|
|
153
153
|
fetchNewReleases,
|
|
154
154
|
fetchNextPreviousLesson,
|
|
155
|
+
fetchOtherSongVersions,
|
|
155
156
|
fetchPackAll,
|
|
156
157
|
fetchPackData,
|
|
157
158
|
fetchParentForDownload,
|
|
158
159
|
fetchPlayAlongsCount,
|
|
159
160
|
fetchRecent,
|
|
160
161
|
fetchRelatedLessons,
|
|
162
|
+
fetchRelatedRecommendedContent,
|
|
161
163
|
fetchRelatedSongs,
|
|
162
164
|
fetchReturning,
|
|
163
165
|
fetchSanity,
|
|
@@ -237,6 +239,7 @@ declare module 'musora-content-services' {
|
|
|
237
239
|
fetchHierarchy,
|
|
238
240
|
fetchLeaving,
|
|
239
241
|
fetchLessonContent,
|
|
242
|
+
fetchLessonsFeaturingThisContent,
|
|
240
243
|
fetchLiveEvent,
|
|
241
244
|
fetchMetadata,
|
|
242
245
|
fetchMethod,
|
|
@@ -246,6 +249,7 @@ declare module 'musora-content-services' {
|
|
|
246
249
|
fetchNewReleases,
|
|
247
250
|
fetchNextContentDataForParent,
|
|
248
251
|
fetchNextPreviousLesson,
|
|
252
|
+
fetchOtherSongVersions,
|
|
249
253
|
fetchOwnedChallenges,
|
|
250
254
|
fetchPackAll,
|
|
251
255
|
fetchPackData,
|
|
@@ -257,12 +261,14 @@ declare module 'musora-content-services' {
|
|
|
257
261
|
fetchPlaylistItems,
|
|
258
262
|
fetchRecent,
|
|
259
263
|
fetchRelatedLessons,
|
|
264
|
+
fetchRelatedRecommendedContent,
|
|
260
265
|
fetchRelatedSongs,
|
|
261
266
|
fetchReturning,
|
|
262
267
|
fetchSanity,
|
|
263
268
|
fetchScheduledAndNewReleases,
|
|
264
269
|
fetchScheduledReleases,
|
|
265
270
|
fetchShowsData,
|
|
271
|
+
fetchSimilarItems,
|
|
266
272
|
fetchSongArtistCount,
|
|
267
273
|
fetchSongById,
|
|
268
274
|
fetchSongsInProgress,
|
|
@@ -308,7 +314,7 @@ declare module 'musora-content-services' {
|
|
|
308
314
|
pinPlaylist,
|
|
309
315
|
playback,
|
|
310
316
|
postChallengesCommunityNotification,
|
|
311
|
-
|
|
317
|
+
|
|
312
318
|
postChallengesEnroll,
|
|
313
319
|
postChallengesEnrollmentNotification,
|
|
314
320
|
postChallengesHideCompletedBanner,
|
|
@@ -316,7 +322,7 @@ declare module 'musora-content-services' {
|
|
|
316
322
|
postChallengesSetStartDate,
|
|
317
323
|
postChallengesSoloNotification,
|
|
318
324
|
postChallengesUnlock,
|
|
319
|
-
|
|
325
|
+
postContentComplete,
|
|
320
326
|
postContentLiked,
|
|
321
327
|
postContentReset,
|
|
322
328
|
postContentUnliked,
|
|
@@ -329,7 +335,6 @@ declare module 'musora-content-services' {
|
|
|
329
335
|
reportPlaylist,
|
|
330
336
|
reset,
|
|
331
337
|
setStudentViewForUser,
|
|
332
|
-
similarItems,
|
|
333
338
|
unassignModeratorToComment,
|
|
334
339
|
unlikeComment,
|
|
335
340
|
unlikeContent,
|
package/src/index.js
CHANGED
|
@@ -96,7 +96,6 @@ import {
|
|
|
96
96
|
pinPlaylist,
|
|
97
97
|
playback,
|
|
98
98
|
postChallengesCommunityNotification,
|
|
99
|
-
postChallengesCompleteLesson,
|
|
100
99
|
postChallengesEnroll,
|
|
101
100
|
postChallengesEnrollmentNotification,
|
|
102
101
|
postChallengesHideCompletedBanner,
|
|
@@ -104,7 +103,7 @@ import {
|
|
|
104
103
|
postChallengesSetStartDate,
|
|
105
104
|
postChallengesSoloNotification,
|
|
106
105
|
postChallengesUnlock,
|
|
107
|
-
|
|
106
|
+
postContentComplete,
|
|
108
107
|
postContentLiked,
|
|
109
108
|
postContentReset,
|
|
110
109
|
postContentUnliked,
|
|
@@ -120,10 +119,10 @@ import {
|
|
|
120
119
|
} from './services/railcontent.js';
|
|
121
120
|
|
|
122
121
|
import {
|
|
122
|
+
fetchSimilarItems,
|
|
123
123
|
rankCategories,
|
|
124
124
|
rankItems,
|
|
125
|
-
recommendations
|
|
126
|
-
similarItems
|
|
125
|
+
recommendations
|
|
127
126
|
} from './services/recommendations.js';
|
|
128
127
|
|
|
129
128
|
import {
|
|
@@ -144,6 +143,7 @@ import {
|
|
|
144
143
|
fetchHierarchy,
|
|
145
144
|
fetchLeaving,
|
|
146
145
|
fetchLessonContent,
|
|
146
|
+
fetchLessonsFeaturingThisContent,
|
|
147
147
|
fetchLiveEvent,
|
|
148
148
|
fetchMetadata,
|
|
149
149
|
fetchMethod,
|
|
@@ -152,12 +152,14 @@ import {
|
|
|
152
152
|
fetchMethodPreviousNextLesson,
|
|
153
153
|
fetchNewReleases,
|
|
154
154
|
fetchNextPreviousLesson,
|
|
155
|
+
fetchOtherSongVersions,
|
|
155
156
|
fetchPackAll,
|
|
156
157
|
fetchPackData,
|
|
157
158
|
fetchParentForDownload,
|
|
158
159
|
fetchPlayAlongsCount,
|
|
159
160
|
fetchRecent,
|
|
160
161
|
fetchRelatedLessons,
|
|
162
|
+
fetchRelatedRecommendedContent,
|
|
161
163
|
fetchRelatedSongs,
|
|
162
164
|
fetchReturning,
|
|
163
165
|
fetchSanity,
|
|
@@ -236,6 +238,7 @@ export {
|
|
|
236
238
|
fetchHierarchy,
|
|
237
239
|
fetchLeaving,
|
|
238
240
|
fetchLessonContent,
|
|
241
|
+
fetchLessonsFeaturingThisContent,
|
|
239
242
|
fetchLiveEvent,
|
|
240
243
|
fetchMetadata,
|
|
241
244
|
fetchMethod,
|
|
@@ -245,6 +248,7 @@ export {
|
|
|
245
248
|
fetchNewReleases,
|
|
246
249
|
fetchNextContentDataForParent,
|
|
247
250
|
fetchNextPreviousLesson,
|
|
251
|
+
fetchOtherSongVersions,
|
|
248
252
|
fetchOwnedChallenges,
|
|
249
253
|
fetchPackAll,
|
|
250
254
|
fetchPackData,
|
|
@@ -256,12 +260,14 @@ export {
|
|
|
256
260
|
fetchPlaylistItems,
|
|
257
261
|
fetchRecent,
|
|
258
262
|
fetchRelatedLessons,
|
|
263
|
+
fetchRelatedRecommendedContent,
|
|
259
264
|
fetchRelatedSongs,
|
|
260
265
|
fetchReturning,
|
|
261
266
|
fetchSanity,
|
|
262
267
|
fetchScheduledAndNewReleases,
|
|
263
268
|
fetchScheduledReleases,
|
|
264
269
|
fetchShowsData,
|
|
270
|
+
fetchSimilarItems,
|
|
265
271
|
fetchSongArtistCount,
|
|
266
272
|
fetchSongById,
|
|
267
273
|
fetchSongsInProgress,
|
|
@@ -307,7 +313,6 @@ export {
|
|
|
307
313
|
pinPlaylist,
|
|
308
314
|
playback,
|
|
309
315
|
postChallengesCommunityNotification,
|
|
310
|
-
postChallengesCompleteLesson,
|
|
311
316
|
postChallengesEnroll,
|
|
312
317
|
postChallengesEnrollmentNotification,
|
|
313
318
|
postChallengesHideCompletedBanner,
|
|
@@ -315,7 +320,7 @@ export {
|
|
|
315
320
|
postChallengesSetStartDate,
|
|
316
321
|
postChallengesSoloNotification,
|
|
317
322
|
postChallengesUnlock,
|
|
318
|
-
|
|
323
|
+
postContentComplete,
|
|
319
324
|
postContentLiked,
|
|
320
325
|
postContentReset,
|
|
321
326
|
postContentUnliked,
|
|
@@ -328,7 +333,6 @@ export {
|
|
|
328
333
|
reportPlaylist,
|
|
329
334
|
reset,
|
|
330
335
|
setStudentViewForUser,
|
|
331
|
-
similarItems,
|
|
332
336
|
unassignModeratorToComment,
|
|
333
337
|
unlikeComment,
|
|
334
338
|
unlikeContent,
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fetchContentProgress,
|
|
3
|
-
|
|
3
|
+
postContentComplete,
|
|
4
4
|
postContentReset,
|
|
5
5
|
postRecordWatchSession,
|
|
6
6
|
} from './railcontent.js'
|
|
@@ -124,7 +124,7 @@ export async function assignmentStatusCompleted(assignmentId, parentContentId) {
|
|
|
124
124
|
completeStatusInLocalContext(localContext, assignmentId, hierarchy)
|
|
125
125
|
},
|
|
126
126
|
async function () {
|
|
127
|
-
return
|
|
127
|
+
return postContentComplete(assignmentId)
|
|
128
128
|
}
|
|
129
129
|
)
|
|
130
130
|
}
|
|
@@ -136,7 +136,7 @@ export async function contentStatusCompleted(contentId) {
|
|
|
136
136
|
completeStatusInLocalContext(localContext, contentId, hierarchy)
|
|
137
137
|
},
|
|
138
138
|
async function () {
|
|
139
|
-
return
|
|
139
|
+
return postContentComplete(contentId)
|
|
140
140
|
}
|
|
141
141
|
)
|
|
142
142
|
}
|
|
@@ -16,7 +16,7 @@ const excludeFromGeneratedIndex = [
|
|
|
16
16
|
'postContentUnliked',
|
|
17
17
|
'postRecordWatchSession',
|
|
18
18
|
'postContentStarted',
|
|
19
|
-
'
|
|
19
|
+
'postContentComplete',
|
|
20
20
|
'postContentReset',
|
|
21
21
|
'fetchUserPermissionsData',
|
|
22
22
|
]
|
|
@@ -343,18 +343,18 @@ export async function fetchHandler(url, method = 'get', dataVersion = null, body
|
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
export async function fetchUserLikes(currentVersion) {
|
|
346
|
-
let url = `/content/user/likes
|
|
346
|
+
let url = `/api/content/v1/user/likes`
|
|
347
347
|
return fetchDataHandler(url, currentVersion)
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
export async function postContentLiked(contentId) {
|
|
351
|
-
let url = `/content/user/likes
|
|
351
|
+
let url = `/api/content/v1/user/likes/${contentId}`
|
|
352
352
|
return await postDataHandler(url)
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
export async function postContentUnliked(contentId) {
|
|
356
|
-
let url = `/content/user/likes
|
|
357
|
-
return await
|
|
356
|
+
let url = `/api/content/v1/user/likes/${contentId}`
|
|
357
|
+
return await deleteDataHandler(url)
|
|
358
358
|
}
|
|
359
359
|
|
|
360
360
|
export async function fetchContentProgress(currentVersion) {
|
|
@@ -596,18 +596,6 @@ export async function postChallengesSoloNotification(contentId) {
|
|
|
596
596
|
return await fetchHandler(url, 'post')
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
-
/**
|
|
600
|
-
* Complete the challenge lesson and update challenge progress
|
|
601
|
-
*
|
|
602
|
-
* @param {int|string} contentId - railcontent id of the challenge
|
|
603
|
-
* @returns {Promise<any|null>} - Modal data to display
|
|
604
|
-
*/
|
|
605
|
-
export async function postChallengesCompleteLesson(contentId) {
|
|
606
|
-
let url = `/challenges/complete_lesson/${contentId}`
|
|
607
|
-
await contentStatusCompleted(contentId)
|
|
608
|
-
return await fetchHandler(url, 'post')
|
|
609
|
-
}
|
|
610
|
-
|
|
611
599
|
/**
|
|
612
600
|
* Hide challenge completed award bannare
|
|
613
601
|
*
|
|
@@ -926,9 +914,9 @@ export async function fetchPlaylistItem(payload) {
|
|
|
926
914
|
return await fetchHandler(url)
|
|
927
915
|
}
|
|
928
916
|
|
|
929
|
-
export async function
|
|
930
|
-
let url = `/content/user/progress/complete`
|
|
931
|
-
return postDataHandler(url
|
|
917
|
+
export async function postContentComplete(contentId) {
|
|
918
|
+
let url = `/api/content/v1/user/progress/complete/${contentId}`
|
|
919
|
+
return postDataHandler(url)
|
|
932
920
|
}
|
|
933
921
|
|
|
934
922
|
export async function postContentReset(contentId) {
|
|
@@ -1084,7 +1072,7 @@ export async function playback(playlistId) {
|
|
|
1084
1072
|
* Set a user's StudentView Flag
|
|
1085
1073
|
*
|
|
1086
1074
|
* @param {int|string} userId - id of the user (must be currently authenticated)
|
|
1087
|
-
* @param {bool} enable -
|
|
1075
|
+
* @param {bool} enable - truthy value to enable student view
|
|
1088
1076
|
* @returns {Promise<any|null>}
|
|
1089
1077
|
*/
|
|
1090
1078
|
export async function setStudentViewForUser(userId, enable) {
|
|
@@ -1100,7 +1088,7 @@ export async function setStudentViewForUser(userId, enable) {
|
|
|
1100
1088
|
* @returns {Promise<Object|null>} - A promise that resolves to an comment object
|
|
1101
1089
|
*/
|
|
1102
1090
|
export async function fetchTopComment(railcontentId) {
|
|
1103
|
-
const url = `/api/content/v1
|
|
1091
|
+
const url = `/api/content/v1/${railcontentId}/comments?filter=top`
|
|
1104
1092
|
return await fetchHandler(url)
|
|
1105
1093
|
}
|
|
1106
1094
|
|
|
@@ -1112,7 +1100,7 @@ export async function fetchTopComment(railcontentId) {
|
|
|
1112
1100
|
* @returns {Promise<*|null>}
|
|
1113
1101
|
*/
|
|
1114
1102
|
export async function fetchComments(railcontentId, page = 1, limit = 20) {
|
|
1115
|
-
const url = `/api/content/v1
|
|
1103
|
+
const url = `/api/content/v1/${railcontentId}/comments?page=${page}&limit=${limit}`
|
|
1116
1104
|
return await fetchHandler(url)
|
|
1117
1105
|
}
|
|
1118
1106
|
|
|
@@ -14,8 +14,8 @@ const excludeFromGeneratedIndex = []
|
|
|
14
14
|
/**
|
|
15
15
|
* Fetches similar content to the provided content id
|
|
16
16
|
*
|
|
17
|
-
* @param {brand} brand - brand of the content to filter
|
|
18
17
|
* @param {integer} content_id - The ID of the content to find similar items for
|
|
18
|
+
* @param {brand} brand - brand of the content to filter
|
|
19
19
|
* @param {integer} count - number of items to return
|
|
20
20
|
* @returns {Promise<Object|null>} - Returns the content_ids sorted by rank (most significant first)
|
|
21
21
|
* @example
|
|
@@ -23,7 +23,7 @@ const excludeFromGeneratedIndex = []
|
|
|
23
23
|
* .then(status => console.log(status))
|
|
24
24
|
* .catch(error => console.error(error));
|
|
25
25
|
*/
|
|
26
|
-
export async function
|
|
26
|
+
export async function fetchSimilarItems(content_id, brand, count = 10) {
|
|
27
27
|
if (!content_id) {
|
|
28
28
|
return []
|
|
29
29
|
}
|
package/src/services/sanity.js
CHANGED
|
@@ -15,8 +15,9 @@ import {
|
|
|
15
15
|
getNewReleasesTypes,
|
|
16
16
|
coachLessonsTypes,
|
|
17
17
|
getChildFieldsForContentType,
|
|
18
|
+
SONG_TYPES
|
|
18
19
|
} from '../contentTypeConfig.js'
|
|
19
|
-
|
|
20
|
+
import { fetchSimilarItems } from './recommendations.js'
|
|
20
21
|
import { processMetadata, typeWithSortOrder } from '../contentMetaData.js'
|
|
21
22
|
|
|
22
23
|
import { globalConfig } from './config.js'
|
|
@@ -36,7 +37,7 @@ import { getAllCompleted, getAllStarted, getAllStartedOrCompleted } from './cont
|
|
|
36
37
|
*
|
|
37
38
|
* @type {string[]}
|
|
38
39
|
*/
|
|
39
|
-
const excludeFromGeneratedIndex = ['handleCustomFetchAll']
|
|
40
|
+
const excludeFromGeneratedIndex = ['handleCustomFetchAll', 'fetchRelatedByLicense']
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Fetch a song by its document ID from Sanity.
|
|
@@ -1313,6 +1314,78 @@ export async function fetchLessonContent(railContentId) {
|
|
|
1313
1314
|
return fetchSanity(query, false, { customPostProcess: chapterProcess })
|
|
1314
1315
|
}
|
|
1315
1316
|
|
|
1317
|
+
/**
|
|
1318
|
+
*
|
|
1319
|
+
* @param railContentId
|
|
1320
|
+
* @param brand
|
|
1321
|
+
* @param count
|
|
1322
|
+
* @returns {Promise<Array<Object>|null>}
|
|
1323
|
+
*/
|
|
1324
|
+
export async function fetchRelatedRecommendedContent(railContentId, brand, count=10) {
|
|
1325
|
+
const recommendedItems = await fetchSimilarItems(railContentId, brand, count)
|
|
1326
|
+
return fetchByRailContentIds(recommendedItems)
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/**
|
|
1330
|
+
* Get song type (transcriptions, jam packs, play alongs, tutorial children) content documents that share content information with the provided railcontent document.
|
|
1331
|
+
* These are linked through content that shares a license with the provided railcontent document
|
|
1332
|
+
*
|
|
1333
|
+
* @param railcontentId
|
|
1334
|
+
* @param brand
|
|
1335
|
+
* @param count
|
|
1336
|
+
* @returns {Promise<*>}
|
|
1337
|
+
*/
|
|
1338
|
+
export async function fetchOtherSongVersions(railcontentId, brand, count=3){
|
|
1339
|
+
return fetchRelatedByLicense(railcontentId, brand, true, count)
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Get non-song content documents that share content information with the provided railcontent document.
|
|
1344
|
+
* These are linked through content that shares a license with the provided railcontent document
|
|
1345
|
+
*
|
|
1346
|
+
* @param {integer} railcontentId
|
|
1347
|
+
* @param {string} brand
|
|
1348
|
+
* @param {integer:3} count
|
|
1349
|
+
* @returns {Promise<*>}
|
|
1350
|
+
*/
|
|
1351
|
+
export async function fetchLessonsFeaturingThisContent(railcontentId, brand, count=3){
|
|
1352
|
+
return fetchRelatedByLicense(railcontentId, brand, false, count)
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
/**
|
|
1356
|
+
* Get content documents that share license information with the provided railcontent id
|
|
1357
|
+
*
|
|
1358
|
+
* @param {integer} railcontentId
|
|
1359
|
+
* @param {string} brand
|
|
1360
|
+
* @param {boolean} onlyUseSongTypes - if true, only return the song type documents. If false, return everything except those
|
|
1361
|
+
* @param {integer:3} count
|
|
1362
|
+
* @returns {Promise<*[]>}
|
|
1363
|
+
*/
|
|
1364
|
+
async function fetchRelatedByLicense(railcontentId, brand, onlyUseSongTypes, count) {
|
|
1365
|
+
const typeCheck = `@->_type in [${arrayJoinWithQuotes(SONG_TYPES)}]`
|
|
1366
|
+
const typeCheckString = onlyUseSongTypes ? `${typeCheck}` : `!(${typeCheck})`
|
|
1367
|
+
const contentFromLicenseFilter =`_type == 'license' && references(^._id)].content[${typeCheckString} && @->railcontent_id != ${railcontentId}`
|
|
1368
|
+
let filterSongTypesWithSameLicense = await new FilterBuilder(
|
|
1369
|
+
contentFromLicenseFilter,
|
|
1370
|
+
{isChildrenFilter: true},
|
|
1371
|
+
).buildFilter()
|
|
1372
|
+
let queryFields = getFieldsForContentType()
|
|
1373
|
+
const baseParentQuery = `railcontent_id == ${railcontentId}`
|
|
1374
|
+
let parentQuery = await new FilterBuilder(baseParentQuery).buildFilter()
|
|
1375
|
+
|
|
1376
|
+
// queryFields = 'railcontent_id, title'
|
|
1377
|
+
// parentQuery = baseParentQuery
|
|
1378
|
+
// filterSongTypesWithSameLicense = contentFromLicenseFilter
|
|
1379
|
+
const query = `*[${parentQuery}]{
|
|
1380
|
+
_type, railcontent_id,
|
|
1381
|
+
"related_by_license" :
|
|
1382
|
+
*[${filterSongTypesWithSameLicense}]->{${queryFields}}|order(published_on desc, title asc)[0...${count}],
|
|
1383
|
+
}[0...1]`
|
|
1384
|
+
|
|
1385
|
+
const results = await fetchSanity(query, false)
|
|
1386
|
+
return results['related_by_license'] ?? [];
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1316
1389
|
/**
|
|
1317
1390
|
* Fetch related lessons for a specific lesson by RailContent ID and type.
|
|
1318
1391
|
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
@@ -2272,9 +2345,9 @@ export async function fetchScheduledAndNewReleases(
|
|
|
2272
2345
|
published_on,
|
|
2273
2346
|
"type": _type,
|
|
2274
2347
|
show_in_new_feed,
|
|
2275
|
-
web_url_path,
|
|
2276
2348
|
"permission_id": permission[]->railcontent_id
|
|
2277
2349
|
}`
|
|
2278
2350
|
|
|
2279
2351
|
return fetchSanity(query, true)
|
|
2280
2352
|
}
|
|
2353
|
+
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getAllStartedOrCompleted,
|
|
15
15
|
} from '../src/services/contentProgress'
|
|
16
16
|
import { initializeTestService } from './initializeTests'
|
|
17
|
-
import {getLessonContentRows,
|
|
17
|
+
import {getLessonContentRows, postContentComplete} from '../src'
|
|
18
18
|
import {fetchRecent} from "../src/services/sanity";
|
|
19
19
|
import {getRecent, getTabResults} from "../src/services/content";
|
|
20
20
|
import {individualLessonsTypes, playAlongLessonTypes, transcriptionsLessonTypes, tutorialsLessonTypes} from "../src/contentTypeConfig";
|
|
@@ -40,7 +40,7 @@ describe('contentProgressDataContext', function () {
|
|
|
40
40
|
let mock2 = jest.spyOn(railContentModule, 'postRecordWatchSession')
|
|
41
41
|
mock2.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`))
|
|
42
42
|
|
|
43
|
-
let mock3 = jest.spyOn(railContentModule, '
|
|
43
|
+
let mock3 = jest.spyOn(railContentModule, 'postContentComplete')
|
|
44
44
|
mock3.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`))
|
|
45
45
|
|
|
46
46
|
let mock4 = jest.spyOn(railContentModule, 'postContentReset')
|
|
@@ -120,7 +120,7 @@ describe('contentProgressDataContext', function () {
|
|
|
120
120
|
// });
|
|
121
121
|
|
|
122
122
|
// test('getAllCompletedWithUpdate', async () => {
|
|
123
|
-
// let mock2 = jest.spyOn(railContentModule, '
|
|
123
|
+
// let mock2 = jest.spyOn(railContentModule, 'postContentComplete');
|
|
124
124
|
// let serverVersion = 2;
|
|
125
125
|
// mock2.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`));
|
|
126
126
|
//
|
package/test/initializeTests.js
CHANGED
|
@@ -5,7 +5,7 @@ const railContentModule = require('../src/services/railcontent.js')
|
|
|
5
5
|
let token = null
|
|
6
6
|
let userId = process.env.RAILCONTENT_USER_ID ?? null
|
|
7
7
|
|
|
8
|
-
export async function initializeTestService(useLive = false) {
|
|
8
|
+
export async function initializeTestService(useLive = false, isAdmin = false) {
|
|
9
9
|
if (useLive && !token && process.env.RAILCONTENT_BASE_URL) {
|
|
10
10
|
let data = await fetchLoginToken(
|
|
11
11
|
process.env.RAILCONTENT_EMAIL,
|
|
@@ -39,7 +39,7 @@ export async function initializeTestService(useLive = false) {
|
|
|
39
39
|
initializeService(config)
|
|
40
40
|
|
|
41
41
|
let mock = jest.spyOn(railContentModule, 'fetchUserPermissionsData')
|
|
42
|
-
let testData = { permissions: [78, 91, 92], isAdmin:
|
|
42
|
+
let testData = { permissions: [78, 91, 92], isAdmin: isAdmin }
|
|
43
43
|
mock.mockImplementation(() => testData)
|
|
44
44
|
}
|
|
45
45
|
|
|
File without changes
|
|
File without changes
|
package/test/localStorageMock.js
CHANGED
|
File without changes
|
package/test/log.js
CHANGED
|
File without changes
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { getFieldsForContentType} from '../src/contentTypeConfig'
|
|
1
|
+
import { getFieldsForContentType, SONG_TYPES } from '../src/contentTypeConfig'
|
|
2
|
+
|
|
2
3
|
const railContentModule = require('../src/services/railcontent.js')
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
-
fetchCommentModContentData,
|
|
6
|
-
fetchMethodPreviousNextLesson,
|
|
7
|
-
fetchSanity,
|
|
8
|
-
} from '../src/services/sanity'
|
|
9
5
|
import { log } from './log.js'
|
|
10
6
|
import { initializeTestService } from './initializeTests'
|
|
11
7
|
import { dataContext } from '../src/services/contentProgress'
|
|
12
|
-
import {fetchOwnedChallenges, getRecommendedForYou, globalConfig, recommendations} from '../src'
|
|
8
|
+
import { fetchOwnedChallenges, getRecommendedForYou, globalConfig, recommendations } from '../src'
|
|
9
|
+
import { fetchLessonsFeaturingThisContent } from '../src/services/sanity.js'
|
|
13
10
|
|
|
14
11
|
const {
|
|
15
12
|
fetchSongById,
|
|
@@ -42,13 +39,17 @@ const {
|
|
|
42
39
|
fetchNextPreviousLesson,
|
|
43
40
|
fetchHierarchy,
|
|
44
41
|
fetchTopLevelParentId,
|
|
42
|
+
fetchOtherSongVersions,
|
|
43
|
+
fetchCommentModContentData,
|
|
44
|
+
fetchMethodPreviousNextLesson,
|
|
45
|
+
fetchSanity,
|
|
45
46
|
} = require('../src/services/sanity.js')
|
|
46
47
|
|
|
47
48
|
const { FilterBuilder } = require('../src/filterBuilder.js')
|
|
48
49
|
|
|
49
50
|
const { processMetadata } = require('../src/contentMetaData.js')
|
|
50
51
|
|
|
51
|
-
describe('Sanity Queries', function
|
|
52
|
+
describe('Sanity Queries', function() {
|
|
52
53
|
beforeEach(() => {
|
|
53
54
|
initializeTestService()
|
|
54
55
|
})
|
|
@@ -62,21 +63,21 @@ describe('Sanity Queries', function () {
|
|
|
62
63
|
test('fetchReturning', async () => {
|
|
63
64
|
const brand = 'guitareo'
|
|
64
65
|
const page = 1
|
|
65
|
-
const response = await fetchReturning(brand, {pageNumber: 1})
|
|
66
|
+
const response = await fetchReturning(brand, { pageNumber: 1 })
|
|
66
67
|
expect(response).toBeDefined()
|
|
67
|
-
})
|
|
68
|
+
})
|
|
68
69
|
|
|
69
70
|
test('fetchLeaving', async () => {
|
|
70
71
|
const brand = 'guitareo'
|
|
71
|
-
const response = await fetchLeaving(brand, {pageNumber: 1})
|
|
72
|
+
const response = await fetchLeaving(brand, { pageNumber: 1 })
|
|
72
73
|
expect(response).toBeDefined()
|
|
73
|
-
})
|
|
74
|
+
})
|
|
74
75
|
|
|
75
76
|
test('fetchComingSoon', async () => {
|
|
76
77
|
const brand = 'guitareo'
|
|
77
|
-
const response = await fetchComingSoon(brand, {pageNumber: 2, contentPerPage: 20})
|
|
78
|
+
const response = await fetchComingSoon(brand, { pageNumber: 2, contentPerPage: 20 })
|
|
78
79
|
expect(response).toBeDefined()
|
|
79
|
-
})
|
|
80
|
+
})
|
|
80
81
|
|
|
81
82
|
|
|
82
83
|
test('fetchArtists', async () => {
|
|
@@ -154,9 +155,7 @@ describe('Sanity Queries', function () {
|
|
|
154
155
|
|
|
155
156
|
test('fetchAllSongsInProgress', async () => {
|
|
156
157
|
var mock = jest.spyOn(dataContext, 'fetchData')
|
|
157
|
-
var json = JSON.parse(
|
|
158
|
-
`{"version":1,"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"412941":{"s":"started","p":6,"t":20,"u":1731108082}}}`
|
|
159
|
-
)
|
|
158
|
+
var json = JSON.parse(`{"version":1,"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"412941":{"s":"started","p":6,"t":20,"u":1731108082}}}`)
|
|
160
159
|
mock.mockImplementation(() => json)
|
|
161
160
|
const response = await fetchAll('drumeo', 'song', { progress: 'in progress' })
|
|
162
161
|
expect(response.entity[0].id).toBe(412941)
|
|
@@ -262,8 +261,7 @@ describe('Sanity Queries', function () {
|
|
|
262
261
|
expect(response.entity[0].id).toBeDefined()
|
|
263
262
|
|
|
264
263
|
response = await fetchAll('drumeo', 'challenge', {
|
|
265
|
-
useDefaultFields: false,
|
|
266
|
-
customFields: ['garbage'],
|
|
264
|
+
useDefaultFields: false, customFields: ['garbage'],
|
|
267
265
|
})
|
|
268
266
|
log(response)
|
|
269
267
|
expect(response.entity[0].garbage).toBeDefined()
|
|
@@ -278,13 +276,11 @@ describe('Sanity Queries', function () {
|
|
|
278
276
|
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id, 'song')
|
|
279
277
|
// match on artist or any genre
|
|
280
278
|
let isMatch = artist === relatedDoc.artist.name
|
|
281
|
-
isMatch =
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return relatedDoc.genre.some((relatedGenre) => {
|
|
285
|
-
return genre._ref === relatedGenre._ref
|
|
286
|
-
})
|
|
279
|
+
isMatch = isMatch || document.genre.some((genre) => {
|
|
280
|
+
return relatedDoc.genre.some((relatedGenre) => {
|
|
281
|
+
return genre._ref === relatedGenre._ref
|
|
287
282
|
})
|
|
283
|
+
})
|
|
288
284
|
expect(isMatch).toBeTruthy()
|
|
289
285
|
})
|
|
290
286
|
|
|
@@ -347,16 +343,14 @@ describe('Sanity Queries', function () {
|
|
|
347
343
|
test('fetchAll-WithProgress', async () => {
|
|
348
344
|
const ids = [410213, 410215]
|
|
349
345
|
let response = await fetchAll('drumeo', 'song', {
|
|
350
|
-
sort: 'slug',
|
|
351
|
-
progressIds: ids,
|
|
346
|
+
sort: 'slug', progressIds: ids,
|
|
352
347
|
})
|
|
353
348
|
expect(response.entity.length).toBe(2)
|
|
354
349
|
expect((response.entity[0].id = 410215))
|
|
355
350
|
expect((response.entity[1].id = 410213))
|
|
356
351
|
// change the type and we expect no results
|
|
357
352
|
response = await fetchAll('drumeo', 'quick-tip', {
|
|
358
|
-
sort: 'slug',
|
|
359
|
-
progressIds: ids,
|
|
353
|
+
sort: 'slug', progressIds: ids,
|
|
360
354
|
})
|
|
361
355
|
expect(response.entity.length).toBe(0)
|
|
362
356
|
})
|
|
@@ -400,16 +394,7 @@ describe('Sanity Queries', function () {
|
|
|
400
394
|
expect(response.entity.length).toBeGreaterThan(0)
|
|
401
395
|
})
|
|
402
396
|
test('fetchCoachLessons-WithTypeFilters', async () => {
|
|
403
|
-
const response = await fetchAllFilterOptions(
|
|
404
|
-
'drumeo',
|
|
405
|
-
['type,course', 'type,live'],
|
|
406
|
-
'',
|
|
407
|
-
'',
|
|
408
|
-
'coach-lessons',
|
|
409
|
-
'',
|
|
410
|
-
[],
|
|
411
|
-
31880
|
|
412
|
-
)
|
|
397
|
+
const response = await fetchAllFilterOptions('drumeo', ['type,course', 'type,live'], '', '', 'coach-lessons', '', [], 31880)
|
|
413
398
|
log(response)
|
|
414
399
|
expect(response.meta.filterOptions.difficulty).toBeDefined()
|
|
415
400
|
expect(response.meta.filterOptions.type).toBeDefined()
|
|
@@ -422,18 +407,7 @@ describe('Sanity Queries', function () {
|
|
|
422
407
|
const coachId = 31880
|
|
423
408
|
const invalidContentType = 'course' // Not 'coach-lessons'
|
|
424
409
|
|
|
425
|
-
await expect(
|
|
426
|
-
fetchAllFilterOptions(
|
|
427
|
-
brand,
|
|
428
|
-
['type,course', 'type,live'],
|
|
429
|
-
'',
|
|
430
|
-
'',
|
|
431
|
-
invalidContentType,
|
|
432
|
-
'',
|
|
433
|
-
[],
|
|
434
|
-
coachId
|
|
435
|
-
)
|
|
436
|
-
).rejects.toThrow("Invalid contentType: 'course' for coachId. It must be 'coach-lessons'.")
|
|
410
|
+
await expect(fetchAllFilterOptions(brand, ['type,course', 'type,live'], '', '', invalidContentType, '', [], coachId)).rejects.toThrow(`Invalid contentType: 'course' for coachId. It must be 'coach-lessons'.`)
|
|
437
411
|
})
|
|
438
412
|
|
|
439
413
|
test('fetchCoachLessons-IncludedFields', async () => {
|
|
@@ -637,15 +611,13 @@ describe('Sanity Queries', function () {
|
|
|
637
611
|
let data = await fetchCommentModContentData([241251, 241252, 211153])
|
|
638
612
|
expect(data[241251].title).toBe('Setting Up Your Space')
|
|
639
613
|
expect(data[241251].type).toBe('learning-path-lesson')
|
|
640
|
-
expect(data[241251].url).toBe(
|
|
641
|
-
'/drumeo/method/drumeo-method/241247/getting-started-on-the-drums/241248/gear/241249/setting-up-your-space/241251'
|
|
642
|
-
)
|
|
614
|
+
expect(data[241251].url).toBe('/drumeo/method/drumeo-method/241247/getting-started-on-the-drums/241248/gear/241249/setting-up-your-space/241251')
|
|
643
615
|
expect(data[241251].parentTitle).toBe('Gear')
|
|
644
616
|
expect(data[241252].title).toBe('Setting Up Your Pedals & Throne')
|
|
645
617
|
})
|
|
646
618
|
})
|
|
647
619
|
|
|
648
|
-
describe('Filter Builder', function
|
|
620
|
+
describe('Filter Builder', function() {
|
|
649
621
|
beforeEach(() => {
|
|
650
622
|
initializeTestService()
|
|
651
623
|
})
|
|
@@ -670,26 +642,21 @@ describe('Filter Builder', function () {
|
|
|
670
642
|
|
|
671
643
|
test('withOnlyFilterAvailableStatuses', async () => {
|
|
672
644
|
const filter = 'railcontent_id = 111'
|
|
673
|
-
const builder = FilterBuilder.withOnlyFilterAvailableStatuses(
|
|
674
|
-
filter,
|
|
675
|
-
['published', 'unlisted'],
|
|
676
|
-
true
|
|
677
|
-
)
|
|
645
|
+
const builder = FilterBuilder.withOnlyFilterAvailableStatuses(filter, ['published', 'unlisted'], true)
|
|
678
646
|
const finalFilter = await builder.buildFilter()
|
|
679
647
|
const clauses = spliceFilterForAnds(finalFilter)
|
|
680
648
|
expect(clauses[0].phrase).toBe(filter)
|
|
681
649
|
expect(clauses[1].field).toBe('status')
|
|
682
650
|
expect(clauses[1].operator).toBe('in')
|
|
683
651
|
// not sure I like this
|
|
684
|
-
expect(clauses[1].condition).toBe(
|
|
652
|
+
expect(clauses[1].condition).toBe(`['published','unlisted']`)
|
|
685
653
|
expect(clauses[2].field).toBe('published_on')
|
|
686
654
|
})
|
|
687
655
|
|
|
688
656
|
test('withContentStatusAndFutureScheduledContent', async () => {
|
|
689
657
|
const filter = 'railcontent_id = 111'
|
|
690
658
|
const builder = new FilterBuilder(filter, {
|
|
691
|
-
availableContentStatuses: ['published', 'unlisted', 'scheduled'],
|
|
692
|
-
getFutureScheduledContentsOnly: true,
|
|
659
|
+
availableContentStatuses: ['published', 'unlisted', 'scheduled'], getFutureScheduledContentsOnly: true,
|
|
693
660
|
})
|
|
694
661
|
const finalFilter = await builder.buildFilter()
|
|
695
662
|
const clauses = spliceFilterForAnds(finalFilter)
|
|
@@ -697,8 +664,7 @@ describe('Filter Builder', function () {
|
|
|
697
664
|
expect(clauses[1].field).toBe('(status') // extra ( because it's a multi part filter
|
|
698
665
|
expect(clauses[1].operator).toBe('in')
|
|
699
666
|
// getFutureScheduledContentsOnly doesn't make a filter that's splicable, so we match on the more static string
|
|
700
|
-
const expected =
|
|
701
|
-
"['published','unlisted'] || (status == 'scheduled' && defined(published_on) && published_on >="
|
|
667
|
+
const expected = `['published','unlisted'] || (status == 'scheduled' && defined(published_on) && published_on >=`
|
|
702
668
|
const isMatch = finalFilter.includes(expected)
|
|
703
669
|
expect(isMatch).toBeTruthy()
|
|
704
670
|
})
|
|
@@ -707,7 +673,7 @@ describe('Filter Builder', function () {
|
|
|
707
673
|
const filter = 'railcontent_id = 111'
|
|
708
674
|
const builder = new FilterBuilder(filter)
|
|
709
675
|
const finalFilter = await builder.buildFilter()
|
|
710
|
-
const expected =
|
|
676
|
+
const expected = `references(*[_type == 'permission' && railcontent_id in [78,91,92]]._id)`
|
|
711
677
|
const isMatch = finalFilter.includes(expected)
|
|
712
678
|
expect(isMatch).toBeTruthy()
|
|
713
679
|
})
|
|
@@ -716,7 +682,7 @@ describe('Filter Builder', function () {
|
|
|
716
682
|
const filter = 'railcontent_id = 111'
|
|
717
683
|
const builder = new FilterBuilder(filter)
|
|
718
684
|
const finalFilter = await builder.buildFilter()
|
|
719
|
-
const expected =
|
|
685
|
+
const expected = `references(*[_type == 'permission' && railcontent_id in [78,91,92]]._id)`
|
|
720
686
|
const isMatch = finalFilter.includes(expected)
|
|
721
687
|
expect(isMatch).toBeTruthy()
|
|
722
688
|
})
|
|
@@ -724,11 +690,10 @@ describe('Filter Builder', function () {
|
|
|
724
690
|
test('withPermissionBypass', async () => {
|
|
725
691
|
const filter = 'railcontent_id = 111'
|
|
726
692
|
const builder = new FilterBuilder(filter, {
|
|
727
|
-
bypassPermissions: true,
|
|
728
|
-
pullFutureContent: false,
|
|
693
|
+
bypassPermissions: true, pullFutureContent: false,
|
|
729
694
|
})
|
|
730
695
|
const finalFilter = await builder.buildFilter()
|
|
731
|
-
const expected =
|
|
696
|
+
const expected = `references(*[_type == 'permission' && railcontent_id in [78,91,92]]._id)`
|
|
732
697
|
const isMatch = finalFilter.includes(expected)
|
|
733
698
|
expect(isMatch).toBeFalsy()
|
|
734
699
|
const clauses = spliceFilterForAnds(finalFilter)
|
|
@@ -742,8 +707,7 @@ describe('Filter Builder', function () {
|
|
|
742
707
|
|
|
743
708
|
const filter = 'railcontent_id = 111'
|
|
744
709
|
let builder = new FilterBuilder(filter, {
|
|
745
|
-
pullFutureContent: true,
|
|
746
|
-
bypassPermissions: true,
|
|
710
|
+
pullFutureContent: true, bypassPermissions: true,
|
|
747
711
|
})
|
|
748
712
|
|
|
749
713
|
let finalFilter = await builder.buildFilter()
|
|
@@ -755,8 +719,7 @@ describe('Filter Builder', function () {
|
|
|
755
719
|
expect(clauses[3].field).toBe('published_on')
|
|
756
720
|
|
|
757
721
|
builder = new FilterBuilder(filter, {
|
|
758
|
-
getFutureContentOnly: true,
|
|
759
|
-
bypassPermissions: true,
|
|
722
|
+
getFutureContentOnly: true, bypassPermissions: true,
|
|
760
723
|
})
|
|
761
724
|
finalFilter = await builder.buildFilter()
|
|
762
725
|
clauses = spliceFilterForAnds(finalFilter)
|
|
@@ -815,28 +778,13 @@ describe('Filter Builder', function () {
|
|
|
815
778
|
})
|
|
816
779
|
|
|
817
780
|
test('fetchAllFilterOptions-filter-selected', async () => {
|
|
818
|
-
let response = await fetchAllFilterOptions(
|
|
819
|
-
'drumeo',
|
|
820
|
-
[
|
|
821
|
-
'theory,notation',
|
|
822
|
-
'theory,time signatures',
|
|
823
|
-
'creativity,Grooves',
|
|
824
|
-
'creativity,Fills & Chops',
|
|
825
|
-
'difficulty,Beginner',
|
|
826
|
-
'difficulty,Intermediate',
|
|
827
|
-
'difficulty,Expert',
|
|
828
|
-
],
|
|
829
|
-
'',
|
|
830
|
-
'',
|
|
831
|
-
'course',
|
|
832
|
-
''
|
|
833
|
-
)
|
|
781
|
+
let response = await fetchAllFilterOptions('drumeo', ['theory,notation', 'theory,time signatures', 'creativity,Grooves', 'creativity,Fills & Chops', 'difficulty,Beginner', 'difficulty,Intermediate', 'difficulty,Expert'], '', '', 'course', '')
|
|
834
782
|
log(response)
|
|
835
783
|
expect(response.meta.filterOptions).toBeDefined()
|
|
836
784
|
})
|
|
837
785
|
})
|
|
838
786
|
|
|
839
|
-
describe('MetaData', function
|
|
787
|
+
describe('MetaData', function() {
|
|
840
788
|
test('customBrandTypeExists', async () => {
|
|
841
789
|
const metaData = processMetadata('guitareo', 'recording')
|
|
842
790
|
expect(metaData.type).toBe('recording')
|
|
@@ -871,7 +819,7 @@ describe('MetaData', function () {
|
|
|
871
819
|
})
|
|
872
820
|
})
|
|
873
821
|
|
|
874
|
-
describe('
|
|
822
|
+
describe('api.v1', function() {
|
|
875
823
|
beforeEach(() => {
|
|
876
824
|
initializeTestService()
|
|
877
825
|
})
|
|
@@ -892,19 +840,13 @@ describe('v2', function () {
|
|
|
892
840
|
})
|
|
893
841
|
|
|
894
842
|
test('fetchAllFilterOptionsLessons', async () => {
|
|
895
|
-
const response = await fetchAllFilterOptions(
|
|
896
|
-
'pianote',
|
|
897
|
-
[],null,null,'lessons'
|
|
898
|
-
)
|
|
843
|
+
const response = await fetchAllFilterOptions('pianote', [], null, null, 'lessons')
|
|
899
844
|
log(response)
|
|
900
845
|
expect(response.meta.filters).toBeDefined()
|
|
901
846
|
})
|
|
902
847
|
|
|
903
848
|
test('fetchAllFilterOptionsSongs', async () => {
|
|
904
|
-
const response = await fetchAllFilterOptions(
|
|
905
|
-
'pianote',
|
|
906
|
-
[],null,null,'songs'
|
|
907
|
-
)
|
|
849
|
+
const response = await fetchAllFilterOptions('pianote', [], null, null, 'songs')
|
|
908
850
|
log(response)
|
|
909
851
|
expect(response.meta.filters).toBeDefined()
|
|
910
852
|
})
|
|
@@ -914,9 +856,105 @@ describe('v2', function () {
|
|
|
914
856
|
log(liveEvent)
|
|
915
857
|
//expect(metaData).toBeNull()
|
|
916
858
|
})
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
test('fetchRelatedLessons-pack-bundle-lessons', async () => {
|
|
863
|
+
//https://www.musora.com/singeo/packs/sing-harmony-in-30-days/410537/sing-harmony-in-30-days/410538/day-2/410541
|
|
864
|
+
const railContentId = 410541
|
|
865
|
+
const relatedLessons = await fetchRelatedLessons(railContentId, 'singeo')
|
|
866
|
+
log(relatedLessons)
|
|
867
|
+
const expectedPath = ['', 'singeo', 'packs', 'sing-harmony-in-30-days', '410537', 'sing-harmony-in-30-days', '410538']
|
|
868
|
+
expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
|
|
869
|
+
relatedLessons['related_lessons'].forEach(document => {
|
|
870
|
+
expect('pack-bundle-lesson').toStrictEqual(document.type)
|
|
871
|
+
// there are other ways to check that these all have the same parent, but I don't want to write it
|
|
872
|
+
let web_url_path = document.web_url_path.split('/')
|
|
873
|
+
// remove id and slug
|
|
874
|
+
web_url_path.pop()
|
|
875
|
+
web_url_path.pop()
|
|
876
|
+
expect(web_url_path).toEqual(expectedPath)
|
|
877
|
+
})
|
|
878
|
+
})
|
|
879
|
+
|
|
880
|
+
test('fetchRelatedLessons-course-parts', async () => {
|
|
881
|
+
///drumeo/courses/ultra-compact-drum-set-gear-guide/295177/gigpig-standard-and-extendable/297929
|
|
882
|
+
const railContentId = 297929
|
|
883
|
+
const relatedLessons = await fetchRelatedLessons(railContentId, 'drumeo')
|
|
884
|
+
log(relatedLessons)
|
|
885
|
+
const expectedPath = ['', 'drumeo', 'courses', 'ultra-compact-drum-set-gear-guide', '295177']
|
|
886
|
+
expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
|
|
887
|
+
relatedLessons['related_lessons'].forEach(document => {
|
|
888
|
+
expect('course-part').toStrictEqual(document.type)
|
|
889
|
+
// there are other ways to check that these all have the same parent, but I don't want to write it
|
|
890
|
+
let web_url_path = document.web_url_path.split('/')
|
|
891
|
+
// remove id and slug
|
|
892
|
+
web_url_path.pop()
|
|
893
|
+
web_url_path.pop()
|
|
894
|
+
expect(web_url_path).toEqual(expectedPath)
|
|
895
|
+
})
|
|
896
|
+
})
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
describe('api.v1.admin', function() {
|
|
900
|
+
beforeEach(() => {
|
|
901
|
+
initializeTestService(false, true)
|
|
902
|
+
})
|
|
903
|
+
|
|
904
|
+
test('fetchOtherSongVersions', async () => {
|
|
905
|
+
// much of the licensed content is currently drafted, so this must be run in the admin test-suite
|
|
906
|
+
const railContentId = 386901
|
|
907
|
+
const licenseQuery = `*[railcontent_id == ${railContentId}]{
|
|
908
|
+
'content_ids': *[_type == 'license' && references(^._id)].content[]->railcontent_id
|
|
909
|
+
}[0]`
|
|
910
|
+
const otherReferencedContent = (await fetchSanity(licenseQuery, true))['content_ids']
|
|
911
|
+
log(otherReferencedContent)
|
|
912
|
+
const relatedSongsTypes = await fetchOtherSongVersions(railContentId, 'drumeo', 100)
|
|
913
|
+
log(relatedSongsTypes)
|
|
914
|
+
expect(relatedSongsTypes.length).toBeGreaterThanOrEqual(1)
|
|
915
|
+
relatedSongsTypes.forEach(document => {
|
|
916
|
+
expect(SONG_TYPES).toContain(document.type)
|
|
917
|
+
expect(document.id).not.toStrictEqual(railContentId)
|
|
918
|
+
expect(otherReferencedContent).toContain(document.id)
|
|
919
|
+
})
|
|
920
|
+
})
|
|
921
|
+
|
|
922
|
+
test('fetchLessonsFeaturingThisContent', async () => {
|
|
923
|
+
// much of the licensed content is currently drafted, so this must be run in the admin test-suite
|
|
924
|
+
const railContentId = 386901
|
|
925
|
+
const licenseQuery = `*[railcontent_id == ${railContentId}]{
|
|
926
|
+
'content_ids': *[_type == 'license' && references(^._id)].content[]->railcontent_id
|
|
927
|
+
}[0]`
|
|
928
|
+
const otherReferencedContent = (await fetchSanity(licenseQuery, true))['content_ids']
|
|
929
|
+
const relatedNotSongs = await fetchLessonsFeaturingThisContent(railContentId, 'drumeo', 100)
|
|
930
|
+
log(relatedNotSongs)
|
|
931
|
+
expect(relatedNotSongs.length).toBeGreaterThanOrEqual(1)
|
|
932
|
+
relatedNotSongs.forEach(document => {
|
|
933
|
+
expect(SONG_TYPES).not.toContain(document.type)
|
|
934
|
+
expect(document.id).not.toStrictEqual(railContentId)
|
|
935
|
+
expect(otherReferencedContent).toContain(document.id)
|
|
936
|
+
})
|
|
937
|
+
})
|
|
938
|
+
|
|
939
|
+
test('fetchRelatedLessons-song-tutorial-children', async () => {
|
|
940
|
+
// When I wrote this it didn't need admin, but something changed. Shrug
|
|
941
|
+
const railContentId = 222633
|
|
942
|
+
const relatedLessons = await fetchRelatedLessons(railContentId, 'pianote')
|
|
943
|
+
log(relatedLessons)
|
|
944
|
+
const expectedPath = ['', 'pianote', 'song-tutorials', 'hallelujah', '221831']
|
|
945
|
+
expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
|
|
946
|
+
relatedLessons['related_lessons'].forEach(document => {
|
|
947
|
+
expect('song-tutorial-children').toStrictEqual(document.type)
|
|
948
|
+
let web_url_path = document.web_url_path.split('/')
|
|
949
|
+
// remove id, slug
|
|
950
|
+
web_url_path.pop()
|
|
951
|
+
web_url_path.pop()
|
|
952
|
+
expect(web_url_path).toEqual(expectedPath)
|
|
953
|
+
})
|
|
954
|
+
})
|
|
917
955
|
})
|
|
918
956
|
|
|
919
|
-
describe('Recommended System', function
|
|
957
|
+
describe('Recommended System', function() {
|
|
920
958
|
beforeEach(() => {
|
|
921
959
|
initializeTestService()
|
|
922
960
|
})
|
|
@@ -931,7 +969,7 @@ describe('Recommended System', function () {
|
|
|
931
969
|
})
|
|
932
970
|
|
|
933
971
|
test('getRecommendedForYou-SeeAll', async () => {
|
|
934
|
-
const results = await getRecommendedForYou('drumeo', 'recommended', {page: 1, limit:20})
|
|
972
|
+
const results = await getRecommendedForYou('drumeo', 'recommended', { page: 1, limit: 20 })
|
|
935
973
|
log(results)
|
|
936
974
|
expect(results.type).toBeDefined()
|
|
937
975
|
expect(results.data).toBeDefined()
|
|
@@ -939,3 +977,5 @@ describe('Recommended System', function () {
|
|
|
939
977
|
expect(results.data.length).toBeGreaterThanOrEqual(1)
|
|
940
978
|
})
|
|
941
979
|
})
|
|
980
|
+
|
|
981
|
+
|