musora-content-services 2.158.3 → 2.159.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/.claude/settings.local.json +12 -0
- package/.github/workflows/automated-testing.yml +21 -1
- package/CHANGELOG.md +8 -0
- package/README.md +21 -2
- package/jest.config.js +1 -4
- package/jest.integration.config.js +6 -0
- package/jest.live.config.js +1 -5
- package/package.json +5 -2
- package/src/contentTypeConfig.js +8 -5
- package/src/index.d.ts +2 -6
- package/src/index.js +2 -6
- package/src/services/content-org/learning-paths.ts +44 -39
- package/src/services/contentProgress.js +216 -207
- package/src/services/offline/progress.ts +107 -27
- package/src/services/sanity.js +55 -64
- package/src/services/sync/models/ContentProgress.ts +50 -34
- package/src/services/sync/repositories/content-progress.ts +105 -92
- package/test/{unit → integration}/awards/award-exclusion-handling.test.ts +2 -2
- package/test/integration/content-progress/__mocks__/mocks.ts +104 -0
- package/test/integration/content-progress/contentProgress.test.ts +335 -0
- package/test/integration/content-progress/e2eOfflineProgress.test.ts +352 -0
- package/test/integration/content-progress/e2eProgress.test.ts +612 -0
- package/test/integration/content-progress/getters.test.ts +334 -0
- package/test/integration/content-progress/helpers.test.ts +263 -0
- package/test/integration/content-progress/offlineContentProgress.test.ts +226 -0
- package/test/integration/forums.test.ts +209 -0
- package/test/integration/initializeTestDB.ts +80 -0
- package/test/{unit → integration}/sync/fetch.test.ts +1 -1
- package/test/{unit → integration}/sync/repositories/content-likes.test.ts +1 -1
- package/test/{unit → integration}/sync/repositories/practices.test.ts +1 -1
- package/test/{unit → integration}/sync/repositories/progress.test.ts +1 -1
- package/test/{unit → integration}/sync/repositories/user-award-progress.test.ts +1 -1
- package/test/{unit → integration}/sync/store/cross-user-protection.test.ts +2 -2
- package/test/{unit → integration}/sync/store/store-idb.test.ts +2 -2
- package/test/{unit → integration}/sync/store/store.test.ts +2 -2
- package/test/unit/content-progress/bubbleTrickle.test.ts +322 -0
- package/test/unit/content-progress/helpers.test.ts +329 -0
- package/test/unit/content-progress/navigateTo.test.ts +381 -0
- package/test/unit/contentMetaData.test.ts +58 -0
- package/tools/generate-index.cjs +6 -3
- package/test/SKIPPED_TESTS.md +0 -151
- package/test/integration/content.test.js +0 -107
- package/test/integration/contentProgress.test.js +0 -73
- package/test/integration/forum.test.js +0 -16
- package/test/integration/sanityQueryService.test.js +0 -681
- package/test/unit/contentProgress.test.ts +0 -81
- /package/test/{unit → integration}/awards/internal/image-utils.test.ts +0 -0
- /package/test/{unit → integration}/infrastructure/FetchRequestExecutor.test.ts +0 -0
- /package/test/{unit → integration}/notifications.test.ts +0 -0
- /package/test/{unit → integration}/sync/adapters/idb-errors.test.ts +0 -0
- /package/test/{unit → integration}/sync/adapters/sqlite-errors.test.ts +0 -0
- /package/test/{unit → integration}/sync/repositories/user-award-progress.static.test.ts +0 -0
- /package/test/{unit → integration}/userActivity.test.ts +0 -0
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
|
-
_recordWatchSession,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
_recordWatchSession,
|
|
3
|
+
filterOutLearningPathsForDuplication,
|
|
4
|
+
filterOutNegativeProgress,
|
|
5
|
+
getProgressDataByIds,
|
|
6
|
+
normalizeCollection,
|
|
7
|
+
normalizeContentId,
|
|
8
|
+
} from '../../services/contentProgress.js'
|
|
9
|
+
import { COLLECTION_ID_SELF, COLLECTION_TYPE, CollectionParameter } from '../sync/models/ContentProgress'
|
|
10
|
+
import { db } from '../../services/sync'
|
|
11
|
+
|
|
12
|
+
const excludeFromGeneratedIndex = [
|
|
13
|
+
'duplicateProgressToALaCarteOffline',
|
|
14
|
+
]
|
|
7
15
|
|
|
8
16
|
interface HierarchyParameter {
|
|
9
17
|
topLevelId: number
|
|
10
|
-
parents:
|
|
11
|
-
children:
|
|
12
|
-
metadata:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
parents: Record<string, number>
|
|
19
|
+
children: Record<string, number[]>
|
|
20
|
+
metadata: Record<string, MetadataParameter>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface MetadataParameter {
|
|
24
|
+
brand: string
|
|
25
|
+
parent_id: number
|
|
26
|
+
type: string
|
|
17
27
|
}
|
|
18
28
|
|
|
19
29
|
/**
|
|
@@ -37,10 +47,10 @@ export async function recordWatchSessionOffline(
|
|
|
37
47
|
instrumentId = null,
|
|
38
48
|
categoryId = null,
|
|
39
49
|
}: {
|
|
40
|
-
collection?: CollectionParameter|null,
|
|
41
|
-
instrumentId?: number|null,
|
|
42
|
-
categoryId?: number|null
|
|
43
|
-
} = {}
|
|
50
|
+
collection?: CollectionParameter | null,
|
|
51
|
+
instrumentId?: number | null,
|
|
52
|
+
categoryId?: number | null
|
|
53
|
+
} = {},
|
|
44
54
|
) {
|
|
45
55
|
return _recordWatchSession(
|
|
46
56
|
contentId,
|
|
@@ -62,8 +72,8 @@ export async function recordWatchSessionOffline(
|
|
|
62
72
|
* @param hierarchy - Content hierarchy used to update parent progress offline
|
|
63
73
|
*/
|
|
64
74
|
export async function contentStatusCompletedOffline(contentId: number, collection: CollectionParameter = null, hierarchy: HierarchyParameter) {
|
|
65
|
-
collection = collection ?? {id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF}
|
|
66
|
-
return
|
|
75
|
+
collection = collection ?? { id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF }
|
|
76
|
+
return setStartedOrCompletedStatusOffline(contentId, collection, true, hierarchy)
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
/**
|
|
@@ -72,8 +82,8 @@ export async function contentStatusCompletedOffline(contentId: number, collectio
|
|
|
72
82
|
* @param hierarchy - Content hierarchy used to update parent progress offline
|
|
73
83
|
*/
|
|
74
84
|
export async function contentStatusCompletedManyOffline(contentIds: number[], collection: CollectionParameter = null, hierarchy: HierarchyParameter) {
|
|
75
|
-
collection = collection ?? {id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF}
|
|
76
|
-
return
|
|
85
|
+
collection = collection ?? { id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF }
|
|
86
|
+
return setStartedOrCompletedStatusManyOffline(contentIds, collection, true, hierarchy)
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
/**
|
|
@@ -82,19 +92,89 @@ export async function contentStatusCompletedManyOffline(contentIds: number[], co
|
|
|
82
92
|
* @param hierarchy - Content hierarchy used to update parent progress offline
|
|
83
93
|
*/
|
|
84
94
|
export async function contentStatusStartedOffline(contentId: number, collection: CollectionParameter = null, hierarchy: HierarchyParameter) {
|
|
85
|
-
collection = collection ?? {id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF}
|
|
86
|
-
return
|
|
95
|
+
collection = collection ?? { id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF }
|
|
96
|
+
return setStartedOrCompletedStatusOffline(contentId, collection, false, hierarchy)
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
/**
|
|
90
100
|
* @param contentId
|
|
91
101
|
* @param collection - Collection context; defaults to self
|
|
92
|
-
* @param hierarchy - Content hierarchy used to update parent progress offline
|
|
93
|
-
* @param options.skipPush - Skip queuing the reset for server sync (default false)
|
|
94
102
|
*/
|
|
95
|
-
export async function contentStatusResetOffline(contentId: number, collection: CollectionParameter = null
|
|
96
|
-
collection = collection ?? {id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF}
|
|
97
|
-
return
|
|
103
|
+
export async function contentStatusResetOffline(contentId: number, collection: CollectionParameter = null) {
|
|
104
|
+
collection = collection ?? { id: COLLECTION_ID_SELF, type: COLLECTION_TYPE.SELF }
|
|
105
|
+
return resetStatusOffline(contentId, collection)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function setStartedOrCompletedStatusOffline(contentId: number, collection: CollectionParameter, isCompleted: boolean, hierarchy: HierarchyParameter) {
|
|
109
|
+
const metadata = hierarchy.metadata || {}
|
|
110
|
+
|
|
111
|
+
const progress = isCompleted ? 100 : 0
|
|
112
|
+
const response = await db.contentProgress.recordProgress(
|
|
113
|
+
normalizeContentId(contentId),
|
|
114
|
+
normalizeCollection(collection),
|
|
115
|
+
progress,
|
|
116
|
+
metadata[contentId],
|
|
117
|
+
null,
|
|
118
|
+
{ skipPush: true },
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
let allProgresses = { [contentId]: progress }
|
|
122
|
+
|
|
123
|
+
if (collection?.type === COLLECTION_TYPE.LEARNING_PATH) {
|
|
124
|
+
await duplicateProgressToALaCarteOffline(allProgresses, metadata, collection)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
db.contentProgress.requestPushUnsynced('save-content-progress')
|
|
128
|
+
return response
|
|
98
129
|
}
|
|
99
130
|
|
|
131
|
+
async function setStartedOrCompletedStatusManyOffline(contentIds: number[], collection: CollectionParameter, isCompleted: boolean, hierarchy: HierarchyParameter) {
|
|
132
|
+
const metadata = hierarchy.metadata || {}
|
|
133
|
+
|
|
134
|
+
const progress = isCompleted ? 100 : 0
|
|
135
|
+
let allProgresses = Object.fromEntries(contentIds.map(id => [id, progress]))
|
|
136
|
+
|
|
137
|
+
const response = await db.contentProgress.recordProgressMany(
|
|
138
|
+
allProgresses,
|
|
139
|
+
normalizeCollection(collection),
|
|
140
|
+
metadata,
|
|
141
|
+
{ skipPush: true },
|
|
142
|
+
)
|
|
100
143
|
|
|
144
|
+
if (collection?.type === COLLECTION_TYPE.LEARNING_PATH) {
|
|
145
|
+
await duplicateProgressToALaCarteOffline(allProgresses, metadata, collection)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
db.contentProgress.requestPushUnsynced('save-content-progress')
|
|
149
|
+
return response
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function resetStatusOffline(contentId: number, collection: CollectionParameter = null) {
|
|
153
|
+
contentId = normalizeContentId(contentId)
|
|
154
|
+
collection = normalizeCollection(collection)
|
|
155
|
+
|
|
156
|
+
const progress = 0
|
|
157
|
+
const response = await db.contentProgress.eraseProgress(contentId, collection, { skipPush: true })
|
|
158
|
+
|
|
159
|
+
let allProgresses = {}
|
|
160
|
+
allProgresses[contentId] = progress
|
|
161
|
+
|
|
162
|
+
db.contentProgress.requestPushUnsynced('reset-status')
|
|
163
|
+
return response
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// todo: move getters and helper functions into separate file to unwind circular dependencies with ofline/progress.ts
|
|
167
|
+
export async function duplicateProgressToALaCarteOffline(progresses: Record<string, number>, metadata: Record<string, MetadataParameter>, collection: CollectionParameter) {
|
|
168
|
+
let filteredProgresses = filterOutLearningPathsForDuplication(progresses, collection)
|
|
169
|
+
|
|
170
|
+
const externalProgresses = await getProgressDataByIds(Object.keys(filteredProgresses), null)
|
|
171
|
+
|
|
172
|
+
filteredProgresses = filterOutNegativeProgress(filteredProgresses, externalProgresses)
|
|
173
|
+
|
|
174
|
+
await db.contentProgress.recordProgressMany(
|
|
175
|
+
filteredProgresses,
|
|
176
|
+
null,
|
|
177
|
+
metadata,
|
|
178
|
+
{ skipPush: true },
|
|
179
|
+
)
|
|
180
|
+
}
|
package/src/services/sanity.js
CHANGED
|
@@ -5,58 +5,47 @@ import {
|
|
|
5
5
|
artistOrInstructorName,
|
|
6
6
|
coachLessonsTypes,
|
|
7
7
|
contentTypeConfig,
|
|
8
|
+
coursesLessonTypes,
|
|
8
9
|
DEFAULT_FIELDS,
|
|
10
|
+
entertainmentLessonTypes,
|
|
9
11
|
filtersToGroq,
|
|
12
|
+
filterTypes,
|
|
10
13
|
getChildFieldsForContentType,
|
|
11
14
|
getFieldsForContentType,
|
|
12
15
|
getFieldsForContentTypeWithFilteredChildren,
|
|
13
16
|
getIntroVideoFields,
|
|
17
|
+
getLiveFields,
|
|
14
18
|
getNewReleasesTypes,
|
|
15
19
|
getUpcomingEventsTypes,
|
|
20
|
+
grandParentReferenceField,
|
|
21
|
+
individualLessonsTypes,
|
|
16
22
|
instructorField,
|
|
23
|
+
jamTrackLessonTypes,
|
|
17
24
|
lessonTypesMapping,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
skillLessonTypes,
|
|
21
|
-
entertainmentLessonTypes,
|
|
22
|
-
filterTypes,
|
|
23
|
-
tutorialsLessonTypes,
|
|
24
|
-
transcriptionsLessonTypes,
|
|
25
|
+
parentRecentTypes,
|
|
26
|
+
parentReferenceField,
|
|
25
27
|
playAlongLessonTypes,
|
|
26
|
-
|
|
28
|
+
postProcessBadge,
|
|
27
29
|
showsTypes,
|
|
30
|
+
skillLessonTypes,
|
|
28
31
|
SONG_TYPES,
|
|
29
32
|
SONG_TYPES_WITH_CHILDREN,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
parentReferenceField,
|
|
33
|
-
grandParentReferenceField,
|
|
34
|
-
getLiveFields,
|
|
33
|
+
transcriptionsLessonTypes,
|
|
34
|
+
tutorialsLessonTypes,
|
|
35
35
|
} from '../contentTypeConfig.js'
|
|
36
36
|
import { fetchSimilarItems } from './recommendations.js'
|
|
37
|
-
import {
|
|
38
|
-
getSongType,
|
|
39
|
-
processMetadata,
|
|
40
|
-
ALWAYS_VISIBLE_TABS,
|
|
41
|
-
CONTENT_STATUSES,
|
|
42
|
-
} from '../contentMetaData.js'
|
|
37
|
+
import { ALWAYS_VISIBLE_TABS, CONTENT_STATUSES, getSongType, processMetadata } from '../contentMetaData.js'
|
|
43
38
|
import { GET } from '../infrastructure/http/HttpClient.ts'
|
|
44
39
|
|
|
45
40
|
import { globalConfig } from './config.js'
|
|
46
41
|
|
|
47
42
|
import { arrayToStringRepresentation, FilterBuilder } from '../filterBuilder.js'
|
|
48
43
|
import { getPermissionsAdapter } from './permissions/index.ts'
|
|
49
|
-
import {
|
|
50
|
-
getAllCompleted,
|
|
51
|
-
getAllCompletedByIds,
|
|
52
|
-
getAllStarted,
|
|
53
|
-
getAllStartedOrCompleted,
|
|
54
|
-
} from './contentProgress.js'
|
|
44
|
+
import { getAllCompleted, getAllCompletedByIds, getAllStarted, getAllStartedOrCompleted } from './contentProgress.js'
|
|
55
45
|
import { fetchRecentActivitiesActiveTabs } from './userActivity.js'
|
|
56
46
|
import { query } from '../lib/sanity/query'
|
|
57
47
|
import { Filters as f } from '../lib/sanity/filter'
|
|
58
48
|
import { COLLECTION_TYPE } from './sync/models/ContentProgress'
|
|
59
|
-
import { MEMBERSHIP_PERMISSIONS } from '../constants/membership-permissions'
|
|
60
49
|
|
|
61
50
|
/**
|
|
62
51
|
* Exported functions that are excluded from index generation.
|
|
@@ -112,7 +101,7 @@ export async function fetchSongById(documentId) {
|
|
|
112
101
|
fields,
|
|
113
102
|
{
|
|
114
103
|
isSingle: true,
|
|
115
|
-
}
|
|
104
|
+
},
|
|
116
105
|
)
|
|
117
106
|
return fetchSanity(query, false)
|
|
118
107
|
}
|
|
@@ -139,7 +128,7 @@ export async function fetchLeaving(brand, { pageNumber = 1, contentPerPage = 20
|
|
|
139
128
|
filterString,
|
|
140
129
|
{ pullFutureContent: false, availableContentStatuses: CONTENT_STATUSES.PUBLISHED_ONLY },
|
|
141
130
|
getFieldsForContentType('leaving'),
|
|
142
|
-
sortOrder
|
|
131
|
+
sortOrder,
|
|
143
132
|
)
|
|
144
133
|
return fetchSanity(query, true)
|
|
145
134
|
}
|
|
@@ -166,7 +155,7 @@ export async function fetchReturning(brand, { pageNumber = 1, contentPerPage = 2
|
|
|
166
155
|
filterString,
|
|
167
156
|
{ pullFutureContent: true, availableContentStatuses: CONTENT_STATUSES.DRAFT_ONLY },
|
|
168
157
|
getFieldsForContentType('returning'),
|
|
169
|
-
sortOrder
|
|
158
|
+
sortOrder,
|
|
170
159
|
)
|
|
171
160
|
|
|
172
161
|
return fetchSanity(query, true)
|
|
@@ -192,7 +181,7 @@ export async function fetchComingSoon(brand, { pageNumber = 1, contentPerPage =
|
|
|
192
181
|
filterString,
|
|
193
182
|
{ getFutureContentOnly: true },
|
|
194
183
|
getFieldsForContentType(),
|
|
195
|
-
sortOrder
|
|
184
|
+
sortOrder,
|
|
196
185
|
)
|
|
197
186
|
return fetchSanity(query, true)
|
|
198
187
|
}
|
|
@@ -219,7 +208,7 @@ function getQueryFromPage(pageNumber, contentPerPage) {
|
|
|
219
208
|
export async function fetchSongArtistCount(brand) {
|
|
220
209
|
const filter = await new FilterBuilder(
|
|
221
210
|
`_type == "song" && brand == "${brand}" && references(^._id)`,
|
|
222
|
-
{ bypassPermissions: true }
|
|
211
|
+
{ bypassPermissions: true },
|
|
223
212
|
).buildFilter()
|
|
224
213
|
const query = `
|
|
225
214
|
count(*[_type == "artist"]{
|
|
@@ -231,7 +220,7 @@ export async function fetchSongArtistCount(brand) {
|
|
|
231
220
|
|
|
232
221
|
export async function fetchPlayAlongsCount(
|
|
233
222
|
brand,
|
|
234
|
-
{ searchTerm, includedFields, progressIds, progress }
|
|
223
|
+
{ searchTerm, includedFields, progressIds, progress },
|
|
235
224
|
) {
|
|
236
225
|
const searchFilter = searchTerm
|
|
237
226
|
? `&& (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
|
|
@@ -336,7 +325,7 @@ export async function fetchRelatedSongs(brand, songId) {
|
|
|
336
325
|
*/
|
|
337
326
|
export async function fetchNewReleases(
|
|
338
327
|
brand,
|
|
339
|
-
{ page = 1, limit = 20, sort = '-published_on' } = {}
|
|
328
|
+
{ page = 1, limit = 20, sort = '-published_on' } = {},
|
|
340
329
|
) {
|
|
341
330
|
const newTypes = getNewReleasesTypes(brand)
|
|
342
331
|
const typesString = arrayToStringRepresentation(newTypes)
|
|
@@ -413,7 +402,7 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
|
|
|
413
402
|
sortOrder: 'published_on asc',
|
|
414
403
|
start: start,
|
|
415
404
|
end: end,
|
|
416
|
-
}
|
|
405
|
+
},
|
|
417
406
|
)
|
|
418
407
|
return fetchSanity(query, true)
|
|
419
408
|
}
|
|
@@ -492,7 +481,7 @@ export async function fetchByRailContentId(id, contentType) {
|
|
|
492
481
|
entityFieldsString,
|
|
493
482
|
{
|
|
494
483
|
isSingle: true,
|
|
495
|
-
}
|
|
484
|
+
},
|
|
496
485
|
)
|
|
497
486
|
|
|
498
487
|
return fetchSanity(query, false)
|
|
@@ -515,7 +504,7 @@ export async function fetchByRailContentIds(
|
|
|
515
504
|
contentType = undefined,
|
|
516
505
|
brand = undefined,
|
|
517
506
|
includePermissionsAndStatusFilter = false,
|
|
518
|
-
filterOptions = {}
|
|
507
|
+
filterOptions = {},
|
|
519
508
|
) {
|
|
520
509
|
if (!ids?.length) {
|
|
521
510
|
return []
|
|
@@ -663,7 +652,7 @@ export async function fetchAll(
|
|
|
663
652
|
customFields = [],
|
|
664
653
|
progress = 'all',
|
|
665
654
|
onlyPublished = true,
|
|
666
|
-
} = {}
|
|
655
|
+
} = {},
|
|
667
656
|
) {
|
|
668
657
|
let config = contentTypeConfig[type] ?? {}
|
|
669
658
|
let additionalFields = config?.fields ?? []
|
|
@@ -881,7 +870,7 @@ export async function fetchAllFilterOptions(
|
|
|
881
870
|
term,
|
|
882
871
|
progressIds,
|
|
883
872
|
coachId,
|
|
884
|
-
includeTabs = false
|
|
873
|
+
includeTabs = false,
|
|
885
874
|
) {
|
|
886
875
|
if (contentType == 'lessons' || contentType == 'songs') {
|
|
887
876
|
const metaData = processMetadata(brand, contentType, true)
|
|
@@ -892,7 +881,7 @@ export async function fetchAllFilterOptions(
|
|
|
892
881
|
|
|
893
882
|
if (coachId && contentType !== 'coach-lessons') {
|
|
894
883
|
throw new Error(
|
|
895
|
-
`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'
|
|
884
|
+
`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`,
|
|
896
885
|
)
|
|
897
886
|
}
|
|
898
887
|
|
|
@@ -976,7 +965,7 @@ export async function fetchLessonContent(railContentId, { forDownload = false }
|
|
|
976
965
|
showMembershipRestrictedContent: true,
|
|
977
966
|
}
|
|
978
967
|
|
|
979
|
-
const fields = getFieldsForContentType('download')
|
|
968
|
+
const fields = getFieldsForContentType('download') // todo(BEHTP-7): a later refactor can make this 'playback'.
|
|
980
969
|
|
|
981
970
|
const query = await buildQuery(`railcontent_id == ${railContentId}`, filterParams, fields, {
|
|
982
971
|
isSingle: true,
|
|
@@ -1027,7 +1016,7 @@ export async function fetchRelatedRecommendedContent(railContentId, brand, count
|
|
|
1027
1016
|
}
|
|
1028
1017
|
|
|
1029
1018
|
return await fetchRelatedLessons(railContentId, brand).then((result) =>
|
|
1030
|
-
result.related_lessons?.splice(0, count)
|
|
1019
|
+
result.related_lessons?.splice(0, count),
|
|
1031
1020
|
)
|
|
1032
1021
|
}
|
|
1033
1022
|
|
|
@@ -1152,15 +1141,15 @@ export async function fetchRelatedLessons(railContentId) {
|
|
|
1152
1141
|
}
|
|
1153
1142
|
const filterSameArtist = await new FilterBuilder(
|
|
1154
1143
|
`${defaultFilterFields} && references(^.artist->_id)`,
|
|
1155
|
-
params
|
|
1144
|
+
params,
|
|
1156
1145
|
).buildFilter()
|
|
1157
1146
|
const filterSameGenre = await new FilterBuilder(
|
|
1158
1147
|
`${defaultFilterFields} && references(^.genre[]->_id)`,
|
|
1159
|
-
params
|
|
1148
|
+
params,
|
|
1160
1149
|
).buildFilter()
|
|
1161
1150
|
const filterSameDifficulty = await new FilterBuilder(
|
|
1162
1151
|
`${defaultFilterFields} && difficulty == ^.difficulty`,
|
|
1163
|
-
params
|
|
1152
|
+
params,
|
|
1164
1153
|
).buildFilter()
|
|
1165
1154
|
const queryFields = getFieldsForContentType()
|
|
1166
1155
|
|
|
@@ -1199,12 +1188,12 @@ export async function fetchLiveEvent(brand, forcedContentId = null) {
|
|
|
1199
1188
|
let endDateTemp = new Date()
|
|
1200
1189
|
|
|
1201
1190
|
startDateTemp = new Date(
|
|
1202
|
-
startDateTemp.setMinutes(startDateTemp.getMinutes() + LIVE_EXTRA_MINUTES)
|
|
1191
|
+
startDateTemp.setMinutes(startDateTemp.getMinutes() + LIVE_EXTRA_MINUTES),
|
|
1203
1192
|
)
|
|
1204
1193
|
endDateTemp = new Date(endDateTemp.setMinutes(endDateTemp.getMinutes() - LIVE_EXTRA_MINUTES))
|
|
1205
1194
|
|
|
1206
1195
|
const liveEventFields = getLiveFields().concat(
|
|
1207
|
-
`'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}')
|
|
1196
|
+
`'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}')`,
|
|
1208
1197
|
)
|
|
1209
1198
|
const fieldsString = liveEventFields.join(',')
|
|
1210
1199
|
|
|
@@ -1271,7 +1260,7 @@ export async function fetchPackData(id) {
|
|
|
1271
1260
|
*/
|
|
1272
1261
|
export async function fetchByReference(
|
|
1273
1262
|
brand,
|
|
1274
|
-
{ sortOrder = '-published_on', searchTerm = '', page = 1, limit = 20, includedFields = [] } = {}
|
|
1263
|
+
{ sortOrder = '-published_on', searchTerm = '', page = 1, limit = 20, includedFields = [] } = {},
|
|
1275
1264
|
) {
|
|
1276
1265
|
const fieldsString = getFieldsForContentType()
|
|
1277
1266
|
const start = (page - 1) * limit
|
|
@@ -1411,6 +1400,7 @@ function mapHierarchyDataToContentIds(hierarchyData, contentIds) {
|
|
|
1411
1400
|
|
|
1412
1401
|
function extractMetadataFromHierarchy(hierarchyData) {
|
|
1413
1402
|
let metadata = {}
|
|
1403
|
+
|
|
1414
1404
|
function recursiveExtract(currentLevel, parentMetadata = {}) {
|
|
1415
1405
|
const railcontentIdField = currentLevel.railcontent_id ? 'railcontent_id' : 'id'
|
|
1416
1406
|
let contentId = currentLevel[railcontentIdField]
|
|
@@ -1432,6 +1422,7 @@ function extractMetadataFromHierarchy(hierarchyData) {
|
|
|
1432
1422
|
}
|
|
1433
1423
|
}
|
|
1434
1424
|
}
|
|
1425
|
+
|
|
1435
1426
|
recursiveExtract(hierarchyData)
|
|
1436
1427
|
return metadata
|
|
1437
1428
|
}
|
|
@@ -1545,11 +1536,11 @@ export async function fetchCommentModContentData(ids) {
|
|
|
1545
1536
|
`railcontent_id in [${idsString}]`,
|
|
1546
1537
|
{ bypassPermissions: true },
|
|
1547
1538
|
fields,
|
|
1548
|
-
{ end: 50 }
|
|
1539
|
+
{ end: 50 },
|
|
1549
1540
|
)
|
|
1550
1541
|
let data = await fetchSanity(query, true)
|
|
1551
1542
|
let mapped = {}
|
|
1552
|
-
data.forEach(function
|
|
1543
|
+
data.forEach(function(content) {
|
|
1553
1544
|
mapped[content.id] = {
|
|
1554
1545
|
id: content.id,
|
|
1555
1546
|
type: content.type,
|
|
@@ -1581,7 +1572,7 @@ export async function fetchCommentModContentData(ids) {
|
|
|
1581
1572
|
export async function fetchSanity(
|
|
1582
1573
|
query,
|
|
1583
1574
|
isList,
|
|
1584
|
-
{ customPostProcess = null, processNeedAccess = true, processPageType = true } = {}
|
|
1575
|
+
{ customPostProcess = null, processNeedAccess = true, processPageType = true } = {},
|
|
1585
1576
|
) {
|
|
1586
1577
|
// Check the config object before proceeding
|
|
1587
1578
|
if (!checkSanityConfig(globalConfig)) {
|
|
@@ -1713,7 +1704,7 @@ function contentResultsDecorator(results, fieldName, callback) {
|
|
|
1713
1704
|
}
|
|
1714
1705
|
|
|
1715
1706
|
function pageTypeDecorator(results) {
|
|
1716
|
-
return contentResultsDecorator(results, 'page_type', function
|
|
1707
|
+
return contentResultsDecorator(results, 'page_type', function(content) {
|
|
1717
1708
|
return SONG_TYPES_WITH_CHILDREN.includes(content['type']) ? 'song' : 'lesson'
|
|
1718
1709
|
})
|
|
1719
1710
|
}
|
|
@@ -1721,7 +1712,7 @@ function pageTypeDecorator(results) {
|
|
|
1721
1712
|
function needsAccessDecorator(results, userPermissions) {
|
|
1722
1713
|
if (globalConfig.sanityConfig.useDummyRailContentMethods) return results
|
|
1723
1714
|
const adapter = getPermissionsAdapter()
|
|
1724
|
-
return contentResultsDecorator(results, 'need_access', function
|
|
1715
|
+
return contentResultsDecorator(results, 'need_access', function(content) {
|
|
1725
1716
|
return adapter.doesUserNeedAccess(content, userPermissions)
|
|
1726
1717
|
})
|
|
1727
1718
|
}
|
|
@@ -1798,7 +1789,7 @@ export async function fetchMetadata(brand, type, options = {}) {
|
|
|
1798
1789
|
if (processedData.filters) {
|
|
1799
1790
|
processedData.filters = filterTypeOptionsByContentCounts(
|
|
1800
1791
|
processedData.filters,
|
|
1801
|
-
contentTypeCounts
|
|
1792
|
+
contentTypeCounts,
|
|
1802
1793
|
)
|
|
1803
1794
|
}
|
|
1804
1795
|
} catch (error) {
|
|
@@ -1838,7 +1829,7 @@ export function getSanityDate(date, roundToHourForCaching = true) {
|
|
|
1838
1829
|
date.getFullYear(),
|
|
1839
1830
|
date.getMonth(),
|
|
1840
1831
|
date.getDate(),
|
|
1841
|
-
date.getHours()
|
|
1832
|
+
date.getHours(),
|
|
1842
1833
|
)
|
|
1843
1834
|
|
|
1844
1835
|
return roundedDate.toISOString()
|
|
@@ -1881,7 +1872,7 @@ function checkSanityConfig(config) {
|
|
|
1881
1872
|
function buildRawQuery(
|
|
1882
1873
|
filter = '',
|
|
1883
1874
|
fields = '...',
|
|
1884
|
-
{ sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
|
|
1875
|
+
{ sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false },
|
|
1885
1876
|
) {
|
|
1886
1877
|
const sortString = sortOrder ? `order(${sortOrder})` : ''
|
|
1887
1878
|
const countString = isSingle ? '[0...1]' : `[${start}...${end}]`
|
|
@@ -1895,7 +1886,7 @@ async function buildQuery(
|
|
|
1895
1886
|
baseFilter = '',
|
|
1896
1887
|
filterParams = { pullFutureContent: false },
|
|
1897
1888
|
fields = '...',
|
|
1898
|
-
{ sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
|
|
1889
|
+
{ sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false },
|
|
1899
1890
|
) {
|
|
1900
1891
|
const filter = await new FilterBuilder(baseFilter, filterParams).buildFilter()
|
|
1901
1892
|
return buildRawQuery(filter, fields, { sortOrder, start, end, isSingle })
|
|
@@ -1910,7 +1901,7 @@ export function buildEntityAndTotalQuery(
|
|
|
1910
1901
|
end = 10,
|
|
1911
1902
|
isSingle = false,
|
|
1912
1903
|
withoutPagination = false,
|
|
1913
|
-
}
|
|
1904
|
+
},
|
|
1914
1905
|
) {
|
|
1915
1906
|
const sortString = sortOrder ? ` | order(${sortOrder})` : ''
|
|
1916
1907
|
const countString = isSingle ? '[0...1]' : withoutPagination ? `` : `[${start}...${end}]`
|
|
@@ -2032,7 +2023,7 @@ export async function fetchTabData(
|
|
|
2032
2023
|
progressIds = undefined,
|
|
2033
2024
|
progress = 'all',
|
|
2034
2025
|
excludeIds = [],
|
|
2035
|
-
} = {}
|
|
2026
|
+
} = {},
|
|
2036
2027
|
) {
|
|
2037
2028
|
const start = (page - 1) * limit
|
|
2038
2029
|
const end = start + limit
|
|
@@ -2135,7 +2126,7 @@ export async function fetchTabData(
|
|
|
2135
2126
|
export async function fetchRecent(
|
|
2136
2127
|
brand,
|
|
2137
2128
|
pageName,
|
|
2138
|
-
{ page = 1, limit = 10, sort = '-published_on', includedFields = [], progress = 'recent' } = {}
|
|
2129
|
+
{ page = 1, limit = 10, sort = '-published_on', includedFields = [], progress = 'recent' } = {},
|
|
2139
2130
|
) {
|
|
2140
2131
|
const mergedIncludedFields = [...includedFields, `tab,all`]
|
|
2141
2132
|
const results = await fetchTabData(brand, pageName, {
|
|
@@ -2152,7 +2143,7 @@ export async function fetchScheduledAndNewReleases(
|
|
|
2152
2143
|
brand,
|
|
2153
2144
|
// page param deprecated, doesnt have 1-1 affect on this functionality
|
|
2154
2145
|
// if we want to allow pagination, this requires a revisit
|
|
2155
|
-
{ limit = 10 } = {}
|
|
2146
|
+
{ limit = 10 } = {},
|
|
2156
2147
|
) {
|
|
2157
2148
|
const maxLessons = 3
|
|
2158
2149
|
const maxSongs = 5
|
|
@@ -2172,7 +2163,7 @@ export async function fetchScheduledAndNewReleases(
|
|
|
2172
2163
|
f.typeIn(parentsWithoutSong),
|
|
2173
2164
|
f.statusIn(['published']),
|
|
2174
2165
|
f.publishedBefore(now),
|
|
2175
|
-
f.publishedAfter(fifteenDaysAgo)
|
|
2166
|
+
f.publishedAfter(fifteenDaysAgo),
|
|
2176
2167
|
)
|
|
2177
2168
|
|
|
2178
2169
|
const songFilter = f.combine(
|
|
@@ -2181,14 +2172,14 @@ export async function fetchScheduledAndNewReleases(
|
|
|
2181
2172
|
f.type('song'),
|
|
2182
2173
|
f.statusIn(['published']),
|
|
2183
2174
|
f.publishedBefore(now),
|
|
2184
|
-
f.publishedAfter(fifteenDaysAgo)
|
|
2175
|
+
f.publishedAfter(fifteenDaysAgo),
|
|
2185
2176
|
)
|
|
2186
2177
|
|
|
2187
2178
|
const livestreamFilter = f.combine(
|
|
2188
2179
|
'show_in_new_feed == true',
|
|
2189
2180
|
f.combineOr(f.brand(brand), 'live_global_event == true'),
|
|
2190
2181
|
f.statusIn(['scheduled']),
|
|
2191
|
-
`live_event_start_time >= '${now}'
|
|
2182
|
+
`live_event_start_time >= '${now}'`,
|
|
2192
2183
|
)
|
|
2193
2184
|
|
|
2194
2185
|
const lessonQuery = query()
|
|
@@ -2349,7 +2340,7 @@ export async function fetchMethodV2StructureFromId(contentId) {
|
|
|
2349
2340
|
*/
|
|
2350
2341
|
export async function fetchOwnedContent(
|
|
2351
2342
|
brand,
|
|
2352
|
-
{ type = [], page = 1, limit = 10, sort = '-published_on' } = {}
|
|
2343
|
+
{ type = [], page = 1, limit = 10, sort = '-published_on' } = {},
|
|
2353
2344
|
) {
|
|
2354
2345
|
const start = (page - 1) * limit
|
|
2355
2346
|
const end = start + limit
|