musora-content-services 2.7.2 → 2.8.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/CHANGELOG.md +9 -0
- package/docs/ContentOrganization.html +2 -2
- package/docs/Gamification.html +2 -2
- package/docs/UserManagementSystem.html +2 -2
- package/docs/api_types.js.html +2 -2
- package/docs/config.js.html +2 -2
- package/docs/content-org_content-org.js.html +2 -2
- package/docs/content-org_playlists-types.js.html +2 -2
- package/docs/content-org_playlists.js.html +2 -4
- package/docs/content.js.html +2 -2
- package/docs/gamification_awards.js.html +2 -2
- package/docs/gamification_gamification.js.html +2 -2
- package/docs/gamification_types.js.html +2 -2
- package/docs/global.html +2 -2
- package/docs/index.html +2 -2
- package/docs/module-Awards.html +2 -2
- package/docs/module-Config.html +2 -2
- package/docs/module-Content-Services-V2.html +2 -2
- package/docs/module-Interests.html +2 -2
- package/docs/module-Permissions.html +2 -2
- package/docs/module-Playlists.html +13 -13
- package/docs/module-Railcontent-Services.html +2 -2
- package/docs/module-Sanity-Services.html +2 -2
- package/docs/module-Sessions.html +2 -2
- package/docs/module-User-Activity.html +7 -7
- package/docs/module-UserManagement.html +448 -23
- package/docs/module-UserProfile.html +2 -2
- package/docs/railcontent.js.html +2 -2
- package/docs/sanity.js.html +2 -2
- package/docs/userActivity.js.html +2 -12
- package/docs/user_interests.js.html +2 -2
- package/docs/user_management.js.html +85 -12
- package/docs/user_permissions.js.html +2 -2
- package/docs/user_profile.js.html +2 -2
- package/docs/user_sessions.js.html +2 -2
- package/docs/user_types.js.html +2 -2
- package/docs/user_user-management-system.js.html +2 -2
- package/link_mcs.sh +8 -6
- package/package.json +1 -1
- package/src/contentMetaData.js +2 -2
- package/src/contentTypeConfig.js +12 -7
- package/src/index.d.ts +9 -1
- package/src/index.js +9 -1
- package/src/lib/httpHelper.js +60 -20
- package/src/services/content.js +0 -0
- package/src/services/contentProgress.js +0 -0
- package/src/services/dateUtils.js +23 -0
- package/src/services/user/management.js +83 -10
- package/src/services/userActivity.js +183 -37
- package/test/mockData/mockData_progress_content.json +0 -0
- package/test/mockData/mockData_sanity_progress_content.json +0 -0
- package/test/progressRows.test.js +0 -0
- package/test/userActivity.test.js +4 -4
package/src/contentTypeConfig.js
CHANGED
|
@@ -139,8 +139,8 @@ export const singleLessonTypes = ['quick-tips', 'rudiment', 'coach-lessons'];
|
|
|
139
139
|
export const practiceAlongsLessonTypes = ['workout', 'boot-camp','challenges'];
|
|
140
140
|
export const performancesLessonTypes = ['performance','solo','drum-fest-international-2022'];
|
|
141
141
|
export const documentariesLessonTypes = ['tama','sonor','history-of-electronic-drums','paiste-cymbals'];
|
|
142
|
-
export const liveArchivesLessonTypes = ['podcast', 'coach-stream', 'live-streams'];
|
|
143
|
-
export const studentArchivesLessonTypes = ['student-review', '
|
|
142
|
+
export const liveArchivesLessonTypes = ['podcast', 'coach-stream', 'question-and-answer', 'live-streams'];
|
|
143
|
+
export const studentArchivesLessonTypes = ['student-review', 'student-focus','student-collaboration'];
|
|
144
144
|
export const tutorialsLessonTypes = ['song-tutorial'];
|
|
145
145
|
export const transcriptionsLessonTypes = ['song'];
|
|
146
146
|
export const playAlongLessonTypes = ['play-along'];
|
|
@@ -181,19 +181,24 @@ export const lessonTypesMapping = {
|
|
|
181
181
|
};
|
|
182
182
|
|
|
183
183
|
export const progressTypesMapping = {
|
|
184
|
-
'lesson': [...singleLessonTypes,...practiceAlongsLessonTypes, ...liveArchivesLessonTypes, ...performancesLessonTypes, ...studentArchivesLessonTypes, ...documentariesLessonTypes],
|
|
184
|
+
'lesson': [...singleLessonTypes,...practiceAlongsLessonTypes, ...liveArchivesLessonTypes, ...performancesLessonTypes, ...studentArchivesLessonTypes, ...documentariesLessonTypes, 'live'],
|
|
185
185
|
'course': ['course'],
|
|
186
186
|
'show': showsLessonTypes,
|
|
187
187
|
'song tutorial': tutorialsLessonTypes,
|
|
188
|
-
'
|
|
189
|
-
'tabs': transcriptionsLessonTypes,
|
|
190
|
-
'sheet music': transcriptionsLessonTypes,
|
|
188
|
+
'songs': transcriptionsLessonTypes,
|
|
191
189
|
'play-along': playAlongLessonTypes,
|
|
192
190
|
'guided course': ['challenge'],
|
|
193
191
|
'pack': ['pack', 'semester-pack'],
|
|
194
192
|
'method': ['learning-path']
|
|
195
193
|
};
|
|
196
194
|
|
|
195
|
+
export const songs = {
|
|
196
|
+
drumeo: 'transcription',
|
|
197
|
+
guitareo: 'tab',
|
|
198
|
+
pianote: 'sheet music',
|
|
199
|
+
singeo: 'sheet music',
|
|
200
|
+
}
|
|
201
|
+
|
|
197
202
|
export const filterTypes = {
|
|
198
203
|
lessons: [...individualLessonsTypes, ...collectionLessonTypes],
|
|
199
204
|
songs: [...tutorialsLessonTypes, ...transcriptionsLessonTypes, ...playAlongLessonTypes, 'jam-track'],
|
|
@@ -207,7 +212,7 @@ export const recentTypes = {
|
|
|
207
212
|
|
|
208
213
|
export let contentTypeConfig = {
|
|
209
214
|
'progress-tracker': {
|
|
210
|
-
fields: ['"parent_content_data": parent_content_data[].id','"lessons": child[]->{"id": railcontent_id, "slug":slug.current, "brand":brand, "type": _type, "lessons": child[]->{"id":railcontent_id, "slug":slug.current, "type": _type,"brand":brand}}'],
|
|
215
|
+
fields: ['"parent_content_data": parent_content_data[].id','"badge" : badge.asset->url','"lessons": child[]->{"id": railcontent_id, "slug":slug.current, "brand":brand, "type": _type, "lessons": child[]->{"id":railcontent_id, "slug":slug.current, "type": _type,"brand":brand}}'],
|
|
211
216
|
},
|
|
212
217
|
song: {
|
|
213
218
|
fields: ['album', 'soundslice', 'instrumentless', `"resources": ${resourcesField}`],
|
package/src/index.d.ts
CHANGED
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
import {
|
|
69
69
|
convertToTimeZone,
|
|
70
70
|
getMonday,
|
|
71
|
+
getTimeRemainingUntilLocal,
|
|
71
72
|
getWeekNumber,
|
|
72
73
|
isNextDay,
|
|
73
74
|
isSameDate
|
|
@@ -221,7 +222,10 @@ import {
|
|
|
221
222
|
|
|
222
223
|
import {
|
|
223
224
|
blockUser,
|
|
224
|
-
|
|
225
|
+
deletePicture,
|
|
226
|
+
unblockUser,
|
|
227
|
+
uploadPicture,
|
|
228
|
+
uploadPictureFromS3
|
|
225
229
|
} from './services/user/management.js';
|
|
226
230
|
|
|
227
231
|
import {
|
|
@@ -282,6 +286,7 @@ declare module 'musora-content-services' {
|
|
|
282
286
|
createPracticeNotes,
|
|
283
287
|
deleteComment,
|
|
284
288
|
deleteItemsFromPlaylist,
|
|
289
|
+
deletePicture,
|
|
285
290
|
deletePlaylist,
|
|
286
291
|
deletePracticeSession,
|
|
287
292
|
deleteUserActivity,
|
|
@@ -396,6 +401,7 @@ declare module 'musora-content-services' {
|
|
|
396
401
|
getScheduleContentRows,
|
|
397
402
|
getSortOrder,
|
|
398
403
|
getTabResults,
|
|
404
|
+
getTimeRemainingUntilLocal,
|
|
399
405
|
getUserMonthlyStats,
|
|
400
406
|
getUserPractices,
|
|
401
407
|
getUserWeeklyStats,
|
|
@@ -459,6 +465,8 @@ declare module 'musora-content-services' {
|
|
|
459
465
|
updatePlaylist,
|
|
460
466
|
updatePracticeNotes,
|
|
461
467
|
updateUserPractice,
|
|
468
|
+
uploadPicture,
|
|
469
|
+
uploadPictureFromS3,
|
|
462
470
|
verifyImageSRC,
|
|
463
471
|
verifyLocalDataContext,
|
|
464
472
|
}
|
package/src/index.js
CHANGED
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
import {
|
|
69
69
|
convertToTimeZone,
|
|
70
70
|
getMonday,
|
|
71
|
+
getTimeRemainingUntilLocal,
|
|
71
72
|
getWeekNumber,
|
|
72
73
|
isNextDay,
|
|
73
74
|
isSameDate
|
|
@@ -221,7 +222,10 @@ import {
|
|
|
221
222
|
|
|
222
223
|
import {
|
|
223
224
|
blockUser,
|
|
224
|
-
|
|
225
|
+
deletePicture,
|
|
226
|
+
unblockUser,
|
|
227
|
+
uploadPicture,
|
|
228
|
+
uploadPictureFromS3
|
|
225
229
|
} from './services/user/management.js';
|
|
226
230
|
|
|
227
231
|
import {
|
|
@@ -281,6 +285,7 @@ export {
|
|
|
281
285
|
createPracticeNotes,
|
|
282
286
|
deleteComment,
|
|
283
287
|
deleteItemsFromPlaylist,
|
|
288
|
+
deletePicture,
|
|
284
289
|
deletePlaylist,
|
|
285
290
|
deletePracticeSession,
|
|
286
291
|
deleteUserActivity,
|
|
@@ -395,6 +400,7 @@ export {
|
|
|
395
400
|
getScheduleContentRows,
|
|
396
401
|
getSortOrder,
|
|
397
402
|
getTabResults,
|
|
403
|
+
getTimeRemainingUntilLocal,
|
|
398
404
|
getUserMonthlyStats,
|
|
399
405
|
getUserPractices,
|
|
400
406
|
getUserWeeklyStats,
|
|
@@ -458,6 +464,8 @@ export {
|
|
|
458
464
|
updatePlaylist,
|
|
459
465
|
updatePracticeNotes,
|
|
460
466
|
updateUserPractice,
|
|
467
|
+
uploadPicture,
|
|
468
|
+
uploadPictureFromS3,
|
|
461
469
|
verifyImageSRC,
|
|
462
470
|
verifyLocalDataContext,
|
|
463
471
|
};
|
package/src/lib/httpHelper.js
CHANGED
|
@@ -1,44 +1,84 @@
|
|
|
1
1
|
import { globalConfig } from '../services/config.js'
|
|
2
2
|
|
|
3
|
-
export async function fetchJSONHandler(
|
|
4
|
-
|
|
3
|
+
export async function fetchJSONHandler(
|
|
4
|
+
url,
|
|
5
|
+
token,
|
|
6
|
+
baseUrl,
|
|
7
|
+
method = 'get',
|
|
8
|
+
dataVersion = null,
|
|
9
|
+
body = null
|
|
10
|
+
) {
|
|
11
|
+
const headers = {
|
|
5
12
|
'Content-Type': 'application/json',
|
|
6
13
|
Accept: 'application/json',
|
|
7
14
|
'X-CSRF-TOKEN': token,
|
|
8
15
|
}
|
|
9
16
|
|
|
17
|
+
if (body) {
|
|
18
|
+
body = JSON.stringify(body)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetchHandler(url, token, baseUrl, method, headers, dataVersion, body)
|
|
23
|
+
|
|
24
|
+
if (response.ok) {
|
|
25
|
+
const contentType = response.headers.get('content-type')
|
|
26
|
+
if (
|
|
27
|
+
contentType &&
|
|
28
|
+
contentType.indexOf('application/json') !== -1 &&
|
|
29
|
+
response.status !== 204
|
|
30
|
+
) {
|
|
31
|
+
return await response.json()
|
|
32
|
+
} else {
|
|
33
|
+
return await response.text()
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
console.error(`Fetch error: ${method} ${url} ${response.status} ${response.statusText}`)
|
|
37
|
+
console.log(response)
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Fetch error:', error)
|
|
41
|
+
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function fetchHandler(
|
|
46
|
+
url,
|
|
47
|
+
token,
|
|
48
|
+
baseUrl,
|
|
49
|
+
method = 'get',
|
|
50
|
+
headers = {},
|
|
51
|
+
dataVersion = null,
|
|
52
|
+
body = null
|
|
53
|
+
) {
|
|
54
|
+
let reqHeaders = {
|
|
55
|
+
...headers,
|
|
56
|
+
Accept: 'application/json',
|
|
57
|
+
'X-CSRF-TOKEN': token,
|
|
58
|
+
}
|
|
59
|
+
|
|
10
60
|
if (!globalConfig.isMA) {
|
|
11
61
|
const params = new URLSearchParams(window.location.search)
|
|
12
62
|
if (params.get('testNow')) {
|
|
13
|
-
|
|
63
|
+
reqHeaders['testNow'] = params.get('testNow')
|
|
14
64
|
}
|
|
15
65
|
if (params.get('timezone')) {
|
|
16
|
-
|
|
66
|
+
reqHeaders['M-Client-Timezone'] = params.get('timezone')
|
|
17
67
|
}
|
|
18
68
|
}
|
|
19
69
|
|
|
20
|
-
if (globalConfig.localTimezoneString)
|
|
21
|
-
|
|
70
|
+
if (globalConfig.localTimezoneString)
|
|
71
|
+
reqHeaders['M-Client-Timezone'] = globalConfig.localTimezoneString
|
|
72
|
+
if (dataVersion) reqHeaders['Data-Version'] = dataVersion
|
|
22
73
|
const options = {
|
|
23
74
|
method,
|
|
24
|
-
headers,
|
|
75
|
+
headers: reqHeaders,
|
|
25
76
|
}
|
|
26
|
-
if (body) options.body =
|
|
77
|
+
if (body) options.body = body
|
|
27
78
|
if (token) options.headers['Authorization'] = `Bearer ${token}`
|
|
28
79
|
if (baseUrl && url.startsWith('/')) url = baseUrl + url
|
|
29
80
|
try {
|
|
30
|
-
|
|
31
|
-
if (response.ok) {
|
|
32
|
-
const contentType = response.headers.get("content-type");
|
|
33
|
-
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
34
|
-
return await response.json()
|
|
35
|
-
} else {
|
|
36
|
-
return await response.text()
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
console.error(`Fetch error: ${method} ${url} ${response.status} ${response.statusText}`)
|
|
40
|
-
console.log(response)
|
|
41
|
-
}
|
|
81
|
+
return fetch(url, options)
|
|
42
82
|
} catch (error) {
|
|
43
83
|
console.error('Fetch error:', error)
|
|
44
84
|
}
|
package/src/services/content.js
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -53,3 +53,26 @@ export function isNextDay(prev, current) {
|
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export function getTimeRemainingUntilLocal(targetUtcIsoString) {
|
|
57
|
+
const targetUTC = new Date(targetUtcIsoString);
|
|
58
|
+
if (isNaN(targetUTC.getTime())) {
|
|
59
|
+
return "00:00:00";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const now = new Date();
|
|
63
|
+
const diff = targetUTC.getTime() - now.getTime();
|
|
64
|
+
|
|
65
|
+
if (diff <= 0) {
|
|
66
|
+
return "00:00:00";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const totalSeconds = Math.floor(diff / 1000);
|
|
70
|
+
const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
|
|
71
|
+
const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
|
|
72
|
+
const seconds = String(totalSeconds % 60).padStart(2, '0');
|
|
73
|
+
|
|
74
|
+
return `${hours}:${minutes}:${seconds}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module UserManagement
|
|
3
3
|
*/
|
|
4
|
-
import { fetchHandler } from '../railcontent.js'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Exported functions that are excluded from index generation.
|
|
8
|
-
*
|
|
9
|
-
* @type {string[]}
|
|
10
|
-
*/
|
|
11
|
-
const excludeFromGeneratedIndex = []
|
|
4
|
+
import { fetchHandler as railcontentFetchHandler } from '../railcontent.js'
|
|
5
|
+
import { fetchHandler, fetchJSONHandler } from '../../lib/httpHelper.js'
|
|
6
|
+
import { globalConfig } from '../config.js'
|
|
12
7
|
|
|
13
8
|
const baseUrl = `/api/user-management-system`
|
|
14
9
|
|
|
@@ -19,7 +14,7 @@ const baseUrl = `/api/user-management-system`
|
|
|
19
14
|
*/
|
|
20
15
|
export async function blockUser(userId) {
|
|
21
16
|
const url = `${baseUrl}/v1/block/${userId}`
|
|
22
|
-
return
|
|
17
|
+
return railcontentFetchHandler(url, 'post')
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -29,5 +24,83 @@ export async function blockUser(userId) {
|
|
|
29
24
|
*/
|
|
30
25
|
export async function unblockUser(userId) {
|
|
31
26
|
const url = `${baseUrl}/v1/unblock/${userId}`
|
|
32
|
-
return
|
|
27
|
+
return railcontentFetchHandler(url, 'post')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Upload a picture to the server
|
|
32
|
+
* @param {string} fieldKey
|
|
33
|
+
* @param {File} file
|
|
34
|
+
* @returns {Promise<any|string|null>}
|
|
35
|
+
*/
|
|
36
|
+
export async function uploadPicture(fieldKey, file) {
|
|
37
|
+
const formData = new FormData()
|
|
38
|
+
formData.append('file', file)
|
|
39
|
+
formData.append('fieldKey', fieldKey)
|
|
40
|
+
const apiUrl = `${baseUrl}/v1/picture`
|
|
41
|
+
|
|
42
|
+
const response = await fetchHandler(
|
|
43
|
+
apiUrl,
|
|
44
|
+
globalConfig.sessionConfig.token,
|
|
45
|
+
globalConfig.baseUrl,
|
|
46
|
+
'POST',
|
|
47
|
+
null,
|
|
48
|
+
null,
|
|
49
|
+
formData
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const problemDetails = await response.json()
|
|
54
|
+
console.log('Error uploading picture:', problemDetails.detail)
|
|
55
|
+
throw new Error(`Upload failed: ${problemDetails.detail}`)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { url } = await response.json()
|
|
59
|
+
console.log('Picture uploaded successfully:', url)
|
|
60
|
+
|
|
61
|
+
return url
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Saves a picture uploaded to S3
|
|
66
|
+
* @param {string} fieldKey
|
|
67
|
+
* @param {string} s3_bucket_path
|
|
68
|
+
* @returns {Promise<any|string|null>}
|
|
69
|
+
*/
|
|
70
|
+
export async function uploadPictureFromS3(fieldKey, s3_bucket_path) {
|
|
71
|
+
const apiUrl = `${baseUrl}/v1/picture/s3`
|
|
72
|
+
|
|
73
|
+
const response = await fetchJSONHandler(
|
|
74
|
+
apiUrl,
|
|
75
|
+
globalConfig.sessionConfig.token,
|
|
76
|
+
globalConfig.baseUrl,
|
|
77
|
+
'POST',
|
|
78
|
+
null,
|
|
79
|
+
{
|
|
80
|
+
fieldKey,
|
|
81
|
+
s3_bucket_path,
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
const problemDetails = await response.json()
|
|
87
|
+
console.log('Error uploading picture:', problemDetails.detail)
|
|
88
|
+
throw new Error(`Upload failed: ${problemDetails.detail}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const { url } = await response.json()
|
|
92
|
+
|
|
93
|
+
return url
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} pictureUrl
|
|
98
|
+
* @returns {Promise<any>}
|
|
99
|
+
*/
|
|
100
|
+
export async function deletePicture(pictureUrl) {
|
|
101
|
+
const apiUrl = `${baseUrl}/v1/picture`
|
|
102
|
+
|
|
103
|
+
fetchJSONHandler(apiUrl, globalConfig.sessionConfig.token, globalConfig.baseUrl, 'DELETE', null, {
|
|
104
|
+
picture_url: pictureUrl,
|
|
105
|
+
})
|
|
33
106
|
}
|