musora-content-services 2.7.3 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/docs/ContentOrganization.html +2 -2
  3. package/docs/Gamification.html +2 -2
  4. package/docs/UserManagementSystem.html +2 -2
  5. package/docs/api_types.js.html +2 -2
  6. package/docs/config.js.html +2 -2
  7. package/docs/content-org_content-org.js.html +2 -2
  8. package/docs/content-org_playlists-types.js.html +2 -2
  9. package/docs/content-org_playlists.js.html +2 -4
  10. package/docs/content.js.html +2 -2
  11. package/docs/gamification_awards.js.html +2 -2
  12. package/docs/gamification_gamification.js.html +2 -2
  13. package/docs/gamification_types.js.html +2 -2
  14. package/docs/global.html +2 -2
  15. package/docs/index.html +2 -2
  16. package/docs/module-Awards.html +2 -2
  17. package/docs/module-Config.html +2 -2
  18. package/docs/module-Content-Services-V2.html +2 -2
  19. package/docs/module-Interests.html +2 -2
  20. package/docs/module-Permissions.html +2 -2
  21. package/docs/module-Playlists.html +13 -13
  22. package/docs/module-Railcontent-Services.html +2 -2
  23. package/docs/module-Sanity-Services.html +2 -2
  24. package/docs/module-Sessions.html +2 -2
  25. package/docs/module-User-Activity.html +7 -7
  26. package/docs/module-UserManagement.html +448 -23
  27. package/docs/module-UserProfile.html +2 -2
  28. package/docs/railcontent.js.html +2 -2
  29. package/docs/sanity.js.html +2 -2
  30. package/docs/userActivity.js.html +2 -12
  31. package/docs/user_interests.js.html +2 -2
  32. package/docs/user_management.js.html +85 -12
  33. package/docs/user_permissions.js.html +2 -2
  34. package/docs/user_profile.js.html +2 -2
  35. package/docs/user_sessions.js.html +2 -2
  36. package/docs/user_types.js.html +2 -2
  37. package/docs/user_user-management-system.js.html +2 -2
  38. package/link_mcs.sh +0 -0
  39. package/package.json +1 -1
  40. package/src/contentMetaData.js +2 -2
  41. package/src/contentTypeConfig.js +10 -5
  42. package/src/index.d.ts +9 -1
  43. package/src/index.js +9 -1
  44. package/src/lib/httpHelper.js +60 -20
  45. package/src/services/dateUtils.js +29 -0
  46. package/src/services/user/management.js +83 -10
  47. package/src/services/userActivity.js +194 -43
  48. package/test/userActivity.test.js +0 -0
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
- unblockUser
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
- unblockUser
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
  };
@@ -1,44 +1,84 @@
1
1
  import { globalConfig } from '../services/config.js'
2
2
 
3
- export async function fetchJSONHandler(url, token, baseUrl, method = 'get', dataVersion = null, body = null) {
4
- let headers = {
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
- headers['testNow'] = params.get('testNow')
63
+ reqHeaders['testNow'] = params.get('testNow')
14
64
  }
15
65
  if (params.get('timezone')) {
16
- headers['M-Client-Timezone'] = params.get('timezone')
66
+ reqHeaders['M-Client-Timezone'] = params.get('timezone')
17
67
  }
18
68
  }
19
69
 
20
- if (globalConfig.localTimezoneString) headers['M-Client-Timezone'] = globalConfig.localTimezoneString
21
- if (dataVersion) headers['Data-Version'] = dataVersion
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 = JSON.stringify(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
- const response = await fetch(url, options)
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
  }
@@ -53,3 +53,32 @@ export function isNextDay(prev, current) {
53
53
  );
54
54
  }
55
55
 
56
+ export function getTimeRemainingUntilLocal(targetUtcIsoString, {withTotalSeconds} = {}) {
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
+ if(withTotalSeconds) {
74
+ return {
75
+ totalSeconds,
76
+ formatted: `${hours}:${minutes}:${seconds}`
77
+ }
78
+ }
79
+
80
+ return `${hours}:${minutes}:${seconds}`;
81
+ }
82
+
83
+
84
+
@@ -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 fetchHandler(url, 'post')
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 fetchHandler(url, 'post')
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
  }