musora-content-services 1.0.156 → 1.0.158

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 (57) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +4 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  6. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  7. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  8. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  9. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  13. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  14. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  15. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  16. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  23. package/docs/scripts/collapse.js +0 -0
  24. package/docs/scripts/commonNav.js +0 -0
  25. package/docs/scripts/linenumber.js +0 -0
  26. package/docs/scripts/nav.js +0 -0
  27. package/docs/scripts/polyfill.js +0 -0
  28. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  29. package/docs/scripts/prettify/lang-css.js +0 -0
  30. package/docs/scripts/prettify/prettify.js +0 -0
  31. package/docs/scripts/search.js +0 -0
  32. package/docs/styles/jsdoc.css +0 -0
  33. package/docs/styles/prettify.css +0 -0
  34. package/jest.config.js +0 -0
  35. package/jsdoc.json +0 -0
  36. package/link_mcs.sh +0 -0
  37. package/package.json +1 -1
  38. package/src/contentMetaData.js +0 -0
  39. package/src/filterBuilder.js +22 -26
  40. package/src/index.d.ts +8 -1
  41. package/src/index.js +8 -1
  42. package/src/services/config.js +0 -0
  43. package/src/services/contentLikes.js +0 -0
  44. package/src/services/contentProgress.js +29 -23
  45. package/src/services/lastUpdated.js +18 -0
  46. package/src/services/railcontent.js +13 -23
  47. package/src/services/sanity.js +558 -555
  48. package/src/services/userPermissions.js +26 -0
  49. package/test/contentLikes.test.js +2 -3
  50. package/test/contentProgress.test.js +7 -7
  51. package/test/initializeTests.js +23 -0
  52. package/test/lastUpdated.test.js +22 -0
  53. package/test/localStorageMock.js +0 -0
  54. package/test/log.js +0 -0
  55. package/test/sanityQueryService.test.js +29 -58
  56. package/test/userPermissions.test.js +19 -0
  57. package/tools/generate-index.js +0 -0
File without changes
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
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
+ ### [1.0.158](https://github.com/railroadmedia/musora-content-services/compare/v1.0.157...v1.0.158) (2024-11-08)
6
+
7
+ ### [1.0.157](https://github.com/railroadmedia/musora-content-services/compare/v1.0.156...v1.0.157) (2024-11-08)
8
+
5
9
  ### [1.0.156](https://github.com/railroadmedia/musora-content-services/compare/v1.0.155...v1.0.156) (2024-11-06)
6
10
 
7
11
  ### [1.0.155](https://github.com/railroadmedia/musora-content-services/compare/v1.0.154...v1.0.155) (2024-11-05)
package/README.md CHANGED
File without changes
package/babel.config.js 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
File without changes
package/jest.config.js CHANGED
File without changes
package/jsdoc.json CHANGED
File without changes
package/link_mcs.sh CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.156",
3
+ "version": "1.0.158",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
File without changes
@@ -1,3 +1,4 @@
1
+ import {fetchUserPermissions} from "./services/userPermissions";
1
2
 
2
3
 
3
4
  export class FilterBuilder {
@@ -5,17 +6,15 @@ export class FilterBuilder {
5
6
  STATUS_SCHEDULED = 'scheduled';
6
7
 
7
8
  constructor(
8
- filter = '',
9
- {
10
- user = undefined,
11
- availableContentStatuses = [],
12
- bypassPermissions = false,
13
- pullFutureContent = false,
14
- getFutureContentOnly = false,
15
- getFutureScheduledContentsOnly = false,
16
-
17
- }={}) {
18
- this.user = user;
9
+ filter = '',
10
+ {
11
+ availableContentStatuses = [],
12
+ bypassPermissions = false,
13
+ pullFutureContent = false,
14
+ getFutureContentOnly = false,
15
+ getFutureScheduledContentsOnly = false,
16
+
17
+ } = {}) {
19
18
  this.availableContentStatuses = availableContentStatuses;
20
19
  this.bypassPermissions = bypassPermissions;
21
20
  this.pullFutureContent = pullFutureContent;
@@ -27,13 +26,15 @@ export class FilterBuilder {
27
26
  }
28
27
 
29
28
 
30
- static withOnlyFilterAvailableStatuses(filter, availableContentStatuses) {
31
- return new FilterBuilder(filter,{
32
- availableContentStatuses,
33
- });
29
+ static withOnlyFilterAvailableStatuses(filter, availableContentStatuses, bypassPermissions) {
30
+ return new FilterBuilder(filter, {
31
+ availableContentStatuses,
32
+ bypassPermissions,
33
+ });
34
34
  }
35
35
 
36
- buildFilter() {
36
+ async buildFilter() {
37
+ this.userData = await fetchUserPermissions();
37
38
  if (this.debug) console.log('baseFilter', this.filter);
38
39
  const filter = this
39
40
  ._applyContentStatuses()
@@ -64,20 +65,15 @@ export class FilterBuilder {
64
65
  }
65
66
 
66
67
  _applyPermissions() {
67
- if (this.bypassPermissions) return this;
68
- // TODO these need to be pulled from the user and reference either ID, or railcontent_id
68
+ if (this.bypassPermissions || this.userData.isAdmin) return this;
69
69
  const requiredPermissions = this._getUserPermissions();
70
70
  if (requiredPermissions.length === 0) return this;
71
- // handle pullSongsContent, I think the flagging on this needs to be backwards compared to BE
72
- // if using id, switch railcontent_id to _id in the below query
73
71
  this._andWhere(`references(*[_type == 'permission' && railcontent_id in ${arrayToRawRepresentation(requiredPermissions)}]._id)`);
74
72
  return this;
75
-
76
73
  }
77
74
 
78
75
  _getUserPermissions() {
79
- // TODO need user store up and running to complete this, until then just null check
80
- return this?.user?.permissions ?? [];
76
+ return this.userData.permissions;
81
77
  }
82
78
 
83
79
  _applyPublishingDateRestrictions() {
@@ -88,7 +84,7 @@ export class FilterBuilder {
88
84
  this._andWhere(`published_on <= '${now}'`);
89
85
  } else {
90
86
  const date = new Date();
91
- const theFuture = new Date(date.setMonth(date.getMonth() + 18));
87
+ const theFuture = new Date(date.setMonth(date.getMonth() + 18));
92
88
  this._andWhere(`published_on <= '${theFuture}'`);
93
89
  }
94
90
  return this;
@@ -106,8 +102,8 @@ export class FilterBuilder {
106
102
 
107
103
  _trimAmpersands() {
108
104
  this.filter = this.filter.trim();
109
- while( this.filter.charAt(0) === '&' || this.filter.charAt(0) === ' ' ) this.filter = this.filter.substring(1);
110
- while( this.filter.charAt(this.filter.length) === '&' || this.filter.charAt(this.filter.length) === ' ' ) this.filter = this.filter.slice(-1);
105
+ while (this.filter.charAt(0) === '&' || this.filter.charAt(0) === ' ') this.filter = this.filter.substring(1);
106
+ while (this.filter.charAt(this.filter.length) === '&' || this.filter.charAt(this.filter.length) === ' ') this.filter = this.filter.slice(-1);
111
107
  return this;
112
108
  }
113
109
 
package/src/index.d.ts CHANGED
@@ -46,7 +46,7 @@ import {
46
46
  fetchUserBadges,
47
47
  fetchUserChallengeProgress,
48
48
  fetchUserLikes,
49
- fetchUserPermissions,
49
+ fetchUserPermissionsData,
50
50
  fetchUserPlaylists,
51
51
  likePlaylist,
52
52
  postChallengesCommunityNotification,
@@ -115,6 +115,11 @@ import {
115
115
  getSortOrder
116
116
  } from './services/sanity.js';
117
117
 
118
+ import {
119
+ fetchUserPermissions,
120
+ reset
121
+ } from './services/userPermissions.js';
122
+
118
123
  declare module 'musora-content-services' {
119
124
  export {
120
125
  contentStatusCompleted,
@@ -188,6 +193,7 @@ declare module 'musora-content-services' {
188
193
  fetchUserChallengeProgress,
189
194
  fetchUserLikes,
190
195
  fetchUserPermissions,
196
+ fetchUserPermissionsData,
191
197
  fetchUserPlaylists,
192
198
  fetchWorkouts,
193
199
  getProgressPercentage,
@@ -214,6 +220,7 @@ declare module 'musora-content-services' {
214
220
  postContentUnliked,
215
221
  postRecordWatchSession,
216
222
  recordWatchSession,
223
+ reset,
217
224
  unlikeContent,
218
225
  updatePlaylist,
219
226
  updatePlaylistItem,
package/src/index.js CHANGED
@@ -46,7 +46,7 @@ import {
46
46
  fetchUserBadges,
47
47
  fetchUserChallengeProgress,
48
48
  fetchUserLikes,
49
- fetchUserPermissions,
49
+ fetchUserPermissionsData,
50
50
  fetchUserPlaylists,
51
51
  likePlaylist,
52
52
  postChallengesCommunityNotification,
@@ -115,6 +115,11 @@ import {
115
115
  getSortOrder
116
116
  } from './services/sanity.js';
117
117
 
118
+ import {
119
+ fetchUserPermissions,
120
+ reset
121
+ } from './services/userPermissions.js';
122
+
118
123
  export {
119
124
  contentStatusCompleted,
120
125
  contentStatusReset,
@@ -187,6 +192,7 @@ export {
187
192
  fetchUserChallengeProgress,
188
193
  fetchUserLikes,
189
194
  fetchUserPermissions,
195
+ fetchUserPermissionsData,
190
196
  fetchUserPlaylists,
191
197
  fetchWorkouts,
192
198
  getProgressPercentage,
@@ -213,6 +219,7 @@ export {
213
219
  postContentUnliked,
214
220
  postRecordWatchSession,
215
221
  recordWatchSession,
222
+ reset,
216
223
  unlikeContent,
217
224
  updatePlaylist,
218
225
  updatePlaylistItem,
File without changes
File without changes
@@ -86,31 +86,24 @@ export async function contentStatusReset(contentId) {
86
86
  }
87
87
 
88
88
 
89
- export async function recordWatchSession({
90
- mediaId,
91
- mediaType,
92
- mediaCategory,
93
- watchPositionSeconds,
94
- totalDurationSeconds,
95
- sessionToken,
96
- brand,
97
- contentId = null
98
- }) {
89
+ export async function recordWatchSession(contentId, mediaType, mediaCategory, mediaLengthSeconds, currentSeconds, secondsPlayed, sessionId = null) {
90
+ let mediaTypeId = getMediaTypeId(mediaType, mediaCategory);
91
+ let updateLocalProgress = mediaTypeId === 1 || mediaTypeId === 2; //only update for video playback
99
92
  await dataContext.update(
100
93
  async function (localContext) {
101
- if (contentId) {
94
+ if (contentId && updateLocalProgress ) {
102
95
  let data = localContext.data[contentId] ?? [];
103
96
  let progress = data?.[DATA_KEY_PROGRESS] ?? 0;
104
97
  let status = data?.[DATA_KEY_STATUS] ?? 0;
105
98
 
106
99
  if (status !== STATE_COMPLETED && progress !== 100) {
107
100
  status = STATE_STARTED;
108
- progress = Math.min(99, Math.round(watchPositionSeconds ?? 0 / Math.max(1, totalDurationSeconds ?? 0) * 100));
101
+ progress = Math.min(99, Math.round(currentSeconds ?? 0 / Math.max(1, mediaLengthSeconds ?? 0) * 100));
109
102
  }
110
103
 
111
104
  data[DATA_KEY_PROGRESS] = progress;
112
105
  data[DATA_KEY_STATUS] = status;
113
- data[DATA_KEY_RESUME_TIME] = watchPositionSeconds;
106
+ data[DATA_KEY_RESUME_TIME] = currentSeconds;
114
107
  localContext.data[contentId] = data;
115
108
 
116
109
  let hierarchy = await fetchHierarchy(contentId);
@@ -118,18 +111,31 @@ export async function recordWatchSession({
118
111
  }
119
112
  },
120
113
  async function () {
121
- return postRecordWatchSession({
122
- mediaId,
123
- mediaType,
124
- mediaCategory,
125
- watchPositionSeconds,
126
- totalDurationSeconds,
127
- sessionToken,
128
- brand,
129
- contentId
130
- });
114
+ return postRecordWatchSession(contentId, mediaTypeId, mediaLengthSeconds, currentSeconds, secondsPlayed, sessionId);
131
115
  }
132
116
  );
117
+ return sessionId;
118
+ }
119
+
120
+ function getMediaTypeId(mediaType, mediaCategory) {
121
+ switch (`${mediaType}_${mediaCategory}`) {
122
+ case "video_youtube":
123
+ return 1;
124
+ case "video_vimeo":
125
+ return 2;
126
+ case "assignment_soundslice":
127
+ return 3;
128
+ case "practice_play-alongs":
129
+ return 4;
130
+ default:
131
+ throw Error(`Unsupported media type: ${mediaType}_${mediaCategory}`);
132
+ }
133
+ }
134
+
135
+ function uuidv4() {
136
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
137
+ (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
138
+ );
133
139
  }
134
140
 
135
141
  function bubbleProgress(hierarchy, contentId, localContext) {
@@ -0,0 +1,18 @@
1
+ import {globalConfig} from "./config";
2
+
3
+ /**
4
+ * Exported functions that are excluded from index generation.
5
+ *
6
+ * @type {string[]}
7
+ */
8
+ const excludeFromGeneratedIndex = ['wasLastUpdateOlderThanXSeconds', 'setLastUpdatedTime'];
9
+ export function wasLastUpdateOlderThanXSeconds(seconds, key) {
10
+ let lastUpdated = globalConfig.localStorage.getItem(key);
11
+ if (!lastUpdated) return false;
12
+ const verifyServerTime = seconds * 1000;
13
+ return (new Date().getTime() - lastUpdated) > verifyServerTime;
14
+ }
15
+
16
+ export function setLastUpdatedTime(key) {
17
+ globalConfig.localStorage.setItem(key, new Date().getTime()?.toString());
18
+ }
@@ -16,7 +16,8 @@ const excludeFromGeneratedIndex = [
16
16
  'postRecordWatchSession',
17
17
  'postContentStarted',
18
18
  'postContentCompleted',
19
- 'postContentReset'
19
+ 'postContentReset',
20
+ 'fetchUserPermissionsData'
20
21
  ];
21
22
 
22
23
 
@@ -236,10 +237,10 @@ export async function fetchContentPageUserData(contentId) {
236
237
  }
237
238
  }
238
239
 
239
- export async function fetchUserPermissions() {
240
- let url = `/content/user_data_permissions`;
240
+ export async function fetchUserPermissionsData() {
241
+ let url = `/content/user/permissions`;
241
242
  // in the case of an unauthorized user, we return empty permissions
242
- return fetchHandler(url, 'get') ?? [];
243
+ return await fetchHandler(url, 'get') ?? [];
243
244
  }
244
245
 
245
246
  async function fetchDataHandler(url, dataVersion, method = "get") {
@@ -297,26 +298,15 @@ export async function fetchContentProgress(currentVersion) {
297
298
  return fetchDataHandler(url, currentVersion);
298
299
  }
299
300
 
300
- export async function postRecordWatchSession({
301
- mediaId,
302
- mediaType,
303
- mediaCategory,
304
- watchPosition,
305
- totalDuration,
306
- sessionToken,
307
- brand,
308
- contentId = null
309
- }) {
310
- let url = `/railtracker/media-playback-session`;
301
+ export async function postRecordWatchSession(contentId, mediaTypeId, mediaLengthSeconds, currentSeconds, secondsPlayed, sessionId) {
302
+ let url = `/railtracker/v2/media-playback-session`;
311
303
  return postDataHandler(url, {
312
- mediaId,
313
- mediaType,
314
- mediaCategory,
315
- watchPosition,
316
- totalDuration,
317
- sessionToken,
318
- brand,
319
- contentId
304
+ "content_id": contentId,
305
+ "media_type_id": mediaTypeId,
306
+ "media_length_seconds": mediaLengthSeconds,
307
+ "current_second": currentSeconds,
308
+ "seconds_played": secondsPlayed,
309
+ "session_id": sessionId
320
310
  });
321
311
  }
322
312