musora-content-services 1.3.19 → 2.0.2

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 (46) hide show
  1. package/.editorconfig +16 -0
  2. package/CHANGELOG.md +1 -3
  3. package/docs/config.js.html +14 -5
  4. package/docs/content.js.html +425 -0
  5. package/docs/global.html +3026 -0
  6. package/docs/index.html +2 -2
  7. package/docs/module-Config.html +60 -7
  8. package/docs/module-Content-Services-V2.html +2433 -0
  9. package/docs/module-Railcontent-Services.html +522 -2
  10. package/docs/module-Sanity-Services.html +57 -43
  11. package/docs/module-Session-Management.html +575 -0
  12. package/docs/module-User-Permissions.html +406 -0
  13. package/docs/railcontent.js.html +42 -5
  14. package/docs/sanity.js.html +290 -103
  15. package/docs/user_permissions.js.html +110 -0
  16. package/docs/user_sessions.js.html +139 -0
  17. package/docs/user_types.js.html +188 -0
  18. package/jsdoc.json +2 -0
  19. package/package.json +1 -1
  20. package/publish.sh +2 -2
  21. package/src/contentMetaData.js +307 -1088
  22. package/src/contentTypeConfig.js +108 -4
  23. package/src/filterBuilder.js +6 -6
  24. package/src/index.d.ts +61 -6
  25. package/src/index.js +61 -6
  26. package/src/{services → lib}/lastUpdated.js +17 -1
  27. package/src/services/config.js +0 -0
  28. package/src/services/content.js +371 -0
  29. package/src/services/dataContext.js +0 -0
  30. package/src/services/forum.js +57 -0
  31. package/src/services/railcontent.js +124 -11
  32. package/src/services/recommendations.js +19 -0
  33. package/src/services/sanity.js +278 -104
  34. package/src/services/{userPermissions.js → user/permissions.js} +16 -2
  35. package/src/services/user/sessions.js +67 -0
  36. package/src/services/user/types.js +116 -0
  37. package/src/services/userActivity.js +32 -0
  38. package/test/content.test.js +116 -0
  39. package/test/contentLikes.test.js +0 -0
  40. package/test/contentProgress.test.js +83 -5
  41. package/test/forum.test.js +18 -0
  42. package/test/initializeTests.js +6 -1
  43. package/test/{lastUpdated.test.js → lib/lastUpdated.test.js} +2 -5
  44. package/test/sanityQueryService.test.js +66 -18
  45. package/test/{userPermissions.test.js → user/permissions.test.js} +3 -3
  46. package/tools/generate-index.cjs +16 -3
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module Session-Management
3
+ */
4
+ import { globalConfig } from '../config'
5
+ import './types'
6
+
7
+ /**
8
+ * Exported functions that are excluded from index generation.
9
+ *
10
+ * @type {string[]}
11
+ */
12
+ const excludeFromGeneratedIndex = []
13
+
14
+ const baseUrl = `${globalConfig.railcontentConfig.baseUrl}/api/user-management-system`
15
+
16
+ /**
17
+ * Authenticates the User.
18
+ *
19
+ * @param {string} email - User's email
20
+ * @param {string} password - User's password
21
+ * @param {string|null} deviceName - Device name for the user
22
+ * @param {string|null} deviceToken - Firebase token for the device
23
+ * @param {string|null} platform - Device platform
24
+ *
25
+ * @returns {Promise<AuthResponse>} - User data and authentication token
26
+ *
27
+ * @example
28
+ * login('john@doe.com', 'music123')
29
+ * .then(content => console.log(content))
30
+ * .catch(error => console.error(error));
31
+ */
32
+ export async function login(email, password, deviceName, deviceToken, platform) {
33
+ return fetch(`${baseUrl}/v1/sessions`, {
34
+ method: 'POST',
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ Authorization: null,
38
+ },
39
+ body: JSON.stringify({
40
+ email: email,
41
+ password: password,
42
+ device_name: deviceName,
43
+ device_token: deviceToken,
44
+ platform: platform,
45
+ }),
46
+ })
47
+ }
48
+
49
+ /**
50
+ * Logs the user out of the current session.
51
+ *
52
+ * @returns {Promise<void>}
53
+ *
54
+ * @example
55
+ * logout()
56
+ * .then()
57
+ * .catch(error => console.error(error));
58
+ */
59
+ export async function logout() {
60
+ await fetch(`${baseUrl}/v1/sessions`, {
61
+ method: 'DELETE',
62
+ headers: {
63
+ Authorization: `Bearer ${globalConfig.railcontentConfig.authToken}`,
64
+ 'Content-Type': 'application/json',
65
+ },
66
+ })
67
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @typedef {object} BrandMethodLevels
3
+ * @property {string} drumeo
4
+ * @property {string} pianote
5
+ * @property {string} guitareo
6
+ * @property {string} singeo
7
+ */
8
+
9
+ /**
10
+ * @typedef {object} BrandTotalXp
11
+ * @property {string} drumeo
12
+ * @property {string} pianote
13
+ * @property {string} guitareo
14
+ * @property {string} singeo
15
+ */
16
+
17
+ /**
18
+ * @typedef {object} BrandTimePracticed
19
+ * @property {number} drumeo
20
+ * @property {number} pianote
21
+ * @property {number} guitareo
22
+ * @property {number} singeo
23
+ */
24
+
25
+ /**
26
+ * @typedef {Object} User
27
+ * @property {number} id
28
+ * @property {string} email
29
+ * @property {string} display_name
30
+ * @property {string} first_name
31
+ * @property {string} last_name
32
+ * @property {string|null} gender
33
+ * @property {string} country
34
+ * @property {string|null} region
35
+ * @property {string|null} city
36
+ * @property {string} birthday
37
+ * @property {string|null} phone_number
38
+ * @property {string} profile_picture_url
39
+ * @property {string} timezone
40
+ * @property {string} permission_level
41
+ * @property {string} last_used_brand
42
+ * @property {string} membership_level
43
+ * @property {string|null} membership_start_date
44
+ * @property {string} membership_expiration_date
45
+ * @property {number} is_lifetime_member
46
+ * @property {string|null} revenuecat_origin_app_user_id
47
+ * @property {number} is_drumeo_lifetime_member
48
+ * @property {string} access_level
49
+ * @property {number} total_xp
50
+ * @property {BrandMethodLevels} brand_method_levels
51
+ * @property {BrandTotalXp} brand_total_xp
52
+ * @property {BrandTimePracticed} brand_minutes_practiced
53
+ * @property {BrandTimePracticed} brand_seconds_practiced
54
+ * @property {number|null} guitar_playing_since_year
55
+ * @property {number} drumeo_onboarding_skip_setup
56
+ * @property {number} pianote_onboarding_skip_setup
57
+ * @property {number} guitareo_onboarding_skip_setup
58
+ * @property {number} singeo_onboarding_skip_setup
59
+ * @property {number} drumeo_trial_section_hide
60
+ * @property {number} pianote_trial_section_hide
61
+ * @property {number} guitareo_trial_section_hide
62
+ * @property {number} singeo_trial_section_hide
63
+ * @property {number} notify_on_lesson_comment_like
64
+ * @property {number|null} notifications_summary_frequency_minutes
65
+ * @property {number} notify_on_forum_post_reply
66
+ * @property {number} notify_on_forum_followed_thread_reply
67
+ * @property {number} notify_on_forum_post_like
68
+ * @property {number} notify_weekly_update
69
+ * @property {number} notify_on_lesson_comment_reply
70
+ * @property {number|null} challenges_enrollment_notifications
71
+ * @property {number|null} challenges_community_notifications
72
+ * @property {number|null} challenges_solo_notifications
73
+ * @property {number} send_mobile_app_push_notifications
74
+ * @property {number} send_email_notifications
75
+ * @property {number} use_legacy_video_player
76
+ * @property {number} drumeo_ship_magazine
77
+ * @property {string|null} magazine_shipping_address_id
78
+ * @property {string|null} ios_latest_review_display_date
79
+ * @property {number} ios_count_review_display
80
+ * @property {string|null} google_latest_review_display_date
81
+ * @property {number} google_count_review_display
82
+ * @property {string|null} biography
83
+ * @property {string|null} support_note
84
+ * @property {string} created_at
85
+ * @property {string} updated_at
86
+ * @property {number} is_pack_owner
87
+ * @property {number} has_recharge_subscription
88
+ * @property {string|null} recharge_interval
89
+ * @property {number} has_apple_subscription
90
+ * @property {number} has_google_subscription
91
+ * @property {number} requires_password_update
92
+ * @property {number} cio_synced_workspaces
93
+ * @property {string|null} recharge_renewal_date
94
+ * @property {string|null} trial_expiration_date
95
+ * @property {number} is_trial
96
+ * @property {string|null} legacy_expiration_date
97
+ * @property {boolean} needs_logout
98
+ * @property {string} primary_brand
99
+ * @property {string} first_access_at
100
+ * @property {number} is_challenge_owner
101
+ * @property {boolean} login_as_users
102
+ */
103
+
104
+ /**
105
+ * @typedef {Object} AuthResponse
106
+ * @property {string} token
107
+ * @property {User} user
108
+ */
109
+
110
+ /**
111
+ * @typedef {Object} UserPermissions
112
+ *
113
+ * @property {string[]} permissions
114
+ * @property {boolean} isAdmin
115
+ * @property {boolean} isABasicMember
116
+ */
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @module User-Activity
3
+ */
4
+
5
+ import {fetchHandler} from "./railcontent";
6
+ const userActivityStats = {
7
+ user: {
8
+ id: 1,
9
+ fullName: 'John Doe',
10
+ profilePictureUrl: 'https://i.pravatar.cc/300',
11
+ },
12
+ dailyActiveStats: [
13
+ { label: 'M', isActive: false, inStreak: false, type: 'none' },
14
+ { label: 'T', isActive: false, inStreak: false, type: 'none' },
15
+ { label: 'W', isActive: true, inStreak: true, type: 'tracked' },
16
+ { label: 'T', isActive: true, inStreak: true, type: 'tracked' },
17
+ { label: 'F', isActive: false, inStreak: false, type: 'none' },
18
+ { label: 'S', isActive: true, inStreak: false, type: 'active' },
19
+ { label: 'S', isActive: false, inStreak: false, type: 'none' }
20
+ ],
21
+ currentDailyStreak: 3,
22
+ currentWeeklyStreak: 2,
23
+ streakMessage: "That's 8 weeks in a row! Way to keep your streak going.",
24
+ };
25
+
26
+ export async function getUserActivityStats(brand) {
27
+ return userActivityStats;
28
+ //return await fetchHandler(`/api/user-activity/v1/stats`);
29
+ }
30
+
31
+
32
+
@@ -0,0 +1,116 @@
1
+ import { initializeTestService } from './initializeTests.js'
2
+ import {getLessonContentRows, getNewAndUpcoming, getScheduleContentRows, getTabResults} from '../src/services/content.js'
3
+
4
+ describe('content', function () {
5
+ beforeEach(() => {
6
+ initializeTestService()
7
+ })
8
+
9
+ // test('getLessonContentRows', async () => {
10
+ // const results = await getLessonContentRows()
11
+ // console.log(results)
12
+ // })
13
+
14
+ // test('getTabResults-For-You', async () => {
15
+ // const results = await getTabResults('drumeo','lessons','For You')
16
+ // console.log(results)
17
+ // expect(results.type).toBeDefined()
18
+ // expect(results.type).toBe('sections')
19
+ // expect(results.data).toBeDefined()
20
+ // expect(results.meta).toBeDefined()
21
+ // expect(results.meta.filters).toBeDefined()
22
+ // expect(results.meta.sort).toBeDefined()
23
+ // })
24
+
25
+ test('getTabResults-Singles', async () => {
26
+ const results = await getTabResults('drumeo','lessons','Individuals', {selectedFilters:['difficulty,All','difficulty,Beginner'], sort:'-published_on'})
27
+ console.log(results)
28
+ expect(results.type).toBeDefined()
29
+ expect(results.type).toBe('catalog')
30
+ expect(results.data).toBeDefined()
31
+ expect(results.meta).toBeDefined()
32
+ expect(results.meta.filters).toBeDefined()
33
+ expect(results.meta.sort).toBeDefined()
34
+ })
35
+
36
+ test('getTabResults-Courses', async () => {
37
+ const results = await getTabResults('pianote','lessons','Collections', {selectedFilters:['difficulty,Expert'], sort:'slug'})
38
+ console.log(results)
39
+ expect(results.type).toBeDefined()
40
+ expect(results.type).toBe('catalog')
41
+ expect(results.data).toBeDefined()
42
+ expect(results.meta).toBeDefined()
43
+ expect(results.meta.filters).toBeDefined()
44
+ expect(results.meta.sort).toBeDefined()
45
+ })
46
+
47
+ test('getTabResults-Filters', async () => {
48
+ const results = await getTabResults('pianote','lessons','Explore All', {selectedFilters:['difficulty,Expert'], sort:'slug'})
49
+ console.log(results)
50
+ expect(results.type).toBeDefined()
51
+ expect(results.data).toBeDefined()
52
+ expect(results.meta).toBeDefined()
53
+ expect(results.meta.filters).toBeDefined()
54
+ expect(results.meta.sort).toBeDefined()
55
+ })
56
+
57
+ test('getTabResults-Type-Filter', async () => {
58
+ const results = await getTabResults('drumeo','lessons','Explore All', {selectedFilters:['type,Courses', 'type,Documentaries'], sort:'slug'})
59
+ console.log(results)
60
+ expect(results.type).toBeDefined()
61
+ expect(results.data).toBeDefined()
62
+ expect(results.meta).toBeDefined()
63
+ expect(results.meta.filters).toBeDefined()
64
+ expect(results.meta.sort).toBeDefined()
65
+ })
66
+
67
+ test('getTabResults-Type-Explore-All', async () => {
68
+ const results = await getTabResults('drumeo','lessons','Explore All', {selectedFilters:[], sort:'slug'})
69
+ console.log(results)
70
+ expect(results.type).toBeDefined()
71
+ expect(results.data).toBeDefined()
72
+ expect(results.meta).toBeDefined()
73
+ expect(results.meta.filters).toBeDefined()
74
+ expect(results.meta.sort).toBeDefined()
75
+ })
76
+
77
+ // test('getContentRows', async () => {
78
+ // const results = await getLessonContentRows('songs')
79
+ // console.log(results)
80
+ // })
81
+
82
+ // test('getTabResults-Songs-For-You', async () => {
83
+ // const results = await getTabResults('drumeo','songs','For You')
84
+ // console.log(results)
85
+ // expect(results.type).toBeDefined()
86
+ // expect(results.type).toBe('sections')
87
+ // expect(results.data).toBeDefined()
88
+ // expect(results.meta).toBeDefined()
89
+ // expect(results.meta.filters).toBeDefined()
90
+ // expect(results.meta.sort).toBeDefined()
91
+ // })
92
+ test('getNewAndUpcoming', async () => {
93
+ const results = await getNewAndUpcoming('drumeo')
94
+ console.log(results)
95
+ //expect(results.data).toBeDefined()
96
+ })
97
+
98
+ test('getScheduleContentRows', async () => {
99
+ const results = await getScheduleContentRows('drumeo')
100
+ console.log(results.data[1])
101
+ expect(results.type).toBeDefined()
102
+ expect(results.type).toBe('sections')
103
+ expect(results.data).toBeDefined()
104
+ expect(results.meta).toBeDefined()
105
+ })
106
+
107
+ test('getSpecificScheduleContentRow', async () => {
108
+ const results = await getScheduleContentRows('drumeo', 'Leaving-Soon')
109
+ console.log(results)
110
+ expect(results.type).toBeDefined()
111
+ expect(results.type).toBe('catalog')
112
+ expect(results.data).toBeDefined()
113
+ expect(results.meta).toBeDefined()
114
+ })
115
+
116
+ })
File without changes
@@ -14,9 +14,13 @@ import {
14
14
  getAllStartedOrCompleted,
15
15
  } from '../src/services/contentProgress'
16
16
  import { initializeTestService } from './initializeTests'
17
- import { postContentCompleted } from '../src'
17
+ import {getLessonContentRows, postContentCompleted} from '../src'
18
+ import {fetchRecent} from "../src/services/sanity";
19
+ import {getRecent, getTabResults} from "../src/services/content";
20
+ import {individualLessonsTypes, playAlongLessonTypes, transcriptionsLessonTypes, tutorialsLessonTypes} from "../src/contentTypeConfig";
18
21
 
19
22
  const railContentModule = require('../src/services/railcontent.js')
23
+ const contentModule = require('../src/services/content.js')
20
24
 
21
25
  describe('contentProgressDataContext', function () {
22
26
  let mock = null
@@ -27,7 +31,9 @@ describe('contentProgressDataContext', function () {
27
31
  initializeTestService()
28
32
  mock = jest.spyOn(dataContext, 'fetchData')
29
33
  var json = JSON.parse(
30
- `{"version":${testVersion},"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"234191":{"s":"started","p":6,"t":20,"u":1731108082},"233955":{"s":"started","p":1,"u":1731108083},"259426":{"s":"completed","p":100,"u":1731108085}}}`
34
+ `{"version":${testVersion},"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"234191":{"s":"started","p":6,"t":20,"u":1731108082},"233955":{"s":"started","p":1,"u":1731108083},
35
+ "259426":{"s":"completed","p":100,"u":1731108085},"190417":{"s":"started","p":6,"t":20,"u":1731108082},
36
+ "407665":{"s":"started","p":6,"t":20,"u":1740120139},"412986":{"s":"completed","p":100,"u":1731108085}}}`
31
37
  )
32
38
  mock.mockImplementation(() => json)
33
39
 
@@ -39,6 +45,26 @@ describe('contentProgressDataContext', function () {
39
45
 
40
46
  let mock4 = jest.spyOn(railContentModule, 'postContentReset')
41
47
  mock4.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`))
48
+
49
+ let mock5 = jest.spyOn(contentModule, 'getContentRows')
50
+ let testData = [
51
+ {
52
+ id: 'recent',
53
+ title: 'Recent Lessons',
54
+ content: ['lesson1', 'lesson2', 'lesson3'],
55
+ },
56
+ {
57
+ id: 'popular',
58
+ title: 'Popular Lessons',
59
+ content: ['lesson4', 'lesson5', 'lesson6'],
60
+ },
61
+ {
62
+ id: 'new-arrivals',
63
+ title: 'New Arrivals',
64
+ content: ['lesson7', 'lesson8', 'lesson9'],
65
+ }
66
+ ];
67
+ mock5.mockImplementation(() => Promise.resolve(testData));
42
68
  })
43
69
 
44
70
  test('getProgressPercentage', async () => {
@@ -70,15 +96,15 @@ describe('contentProgressDataContext', function () {
70
96
 
71
97
  test('getAllStarted', async () => {
72
98
  let result = await getAllStarted()
73
- expect(result).toStrictEqual([233955, 234191])
99
+ expect(result).toStrictEqual([407665, 233955,190417, 234191])
74
100
 
75
101
  result = await getAllStarted(1)
76
- expect(result).toStrictEqual([233955])
102
+ expect(result).toStrictEqual([407665])
77
103
  })
78
104
 
79
105
  test('getAllStartedOrCompleted', async () => {
80
106
  let result = await getAllStartedOrCompleted()
81
- expect(result).toStrictEqual([259426, 233955, 234191])
107
+ expect(result).toStrictEqual([407665, 259426, 412986, 233955, 190417,234191])
82
108
  })
83
109
 
84
110
  // test('getAllStartedWithUpdate', async () => {
@@ -231,4 +257,56 @@ describe('contentProgressDataContext', function () {
231
257
  // expect(state).toBe("");
232
258
  //
233
259
  // });
260
+ test('getRecentLessons', async () => {
261
+ let result = await getRecent('drumeo','lessons', 'all',{page:1, limit:10})
262
+ console.log(result);
263
+ expect(result.data[0].id).toStrictEqual(412986)
264
+ expect(individualLessonsTypes).toContain(result.data[0].type)
265
+ })
266
+
267
+ test('getRecentLessons-Incomplete', async () => {
268
+ let result = await getRecent('drumeo','lessons','Incomplete')
269
+ console.log(result);
270
+ expect(result.data[0].id).toStrictEqual(407665)
271
+ expect(individualLessonsTypes).toContain(result.data[0].type)
272
+ })
273
+
274
+ test('getRecentLessons-Completed', async () => {
275
+ let result = await getRecent('drumeo','lessons','Completed')
276
+ console.log(result);
277
+ expect(result.data[0].id).toStrictEqual(412986)
278
+ expect(individualLessonsTypes).toContain(result.data[0].type)
279
+ })
280
+
281
+ test('get-Songs-For-You', async () => {
282
+ let result = await getTabResults('drumeo','songs','For You')
283
+ console.log(result);
284
+ expect(result.type).toStrictEqual('sections')
285
+ expect(result.data).toBeDefined()
286
+ expect(result.meta).toBeDefined()
287
+ })
288
+
289
+ test('get-Songs-Tutorials', async () => {
290
+ let result = await getTabResults('pianote','songs','Tutorials')
291
+ console.log(result);
292
+ expect(result.type).toStrictEqual('catalog')
293
+ expect(result.data).toBeDefined()
294
+ expect(tutorialsLessonTypes).toContain(result.data[0].type)
295
+ })
296
+
297
+ test('get-Songs-Transcriptions', async () => {
298
+ let result = await getTabResults('pianote','songs','Transcriptions')
299
+ console.log(result);
300
+ expect(result.type).toStrictEqual('catalog')
301
+ expect(result.data).toBeDefined()
302
+ expect(transcriptionsLessonTypes).toContain(result.data[0].type)
303
+ })
304
+
305
+ test('get-Songs-Play-Alongs', async () => {
306
+ let result = await getTabResults('drumeo','songs','Play-Alongs',{selectedFilters:['difficulty,Expert']})
307
+ console.log(result);
308
+ expect(playAlongLessonTypes).toContain(result.data[0].type)
309
+ expect(result.data[0].difficulty_string).toStrictEqual('Expert')
310
+ })
311
+
234
312
  })
@@ -0,0 +1,18 @@
1
+ import { initializeTestService } from './initializeTests.js'
2
+ import { getLessonContentRows, getTabResults } from '../src/services/content.js'
3
+ import {getActiveDiscussions} from "../src/services/forum";
4
+
5
+ describe('forum', function () {
6
+ beforeEach(() => {
7
+ initializeTestService()
8
+ })
9
+
10
+ test('getActiveDiscussions', async () => {
11
+ const results = await getActiveDiscussions('drumeo')
12
+ console.log(results)
13
+ expect(results.data).toBeDefined()
14
+ expect(results.meta).toBeDefined()
15
+ })
16
+
17
+
18
+ })
@@ -3,7 +3,7 @@ import { LocalStorageMock } from './localStorageMock'
3
3
 
4
4
  const railContentModule = require('../src/services/railcontent.js')
5
5
  let token = null
6
- let userId = null
6
+ let userId = process.env.RAILCONTENT_USER_ID ?? null
7
7
 
8
8
  export async function initializeTestService(useLive = false) {
9
9
  if (useLive && !token && process.env.RAILCONTENT_BASE_URL) {
@@ -30,6 +30,11 @@ export async function initializeTestService(useLive = false) {
30
30
  authToken: token,
31
31
  },
32
32
  localStorage: new LocalStorageMock(),
33
+ isMA: true,
34
+ recommendationsConfig: {
35
+ token: process.env.HUGGINGFACE_TOKEN,
36
+ baseUrl: process.env.HUGGINGFACE_URL
37
+ }
33
38
  }
34
39
  initializeService(config)
35
40
 
@@ -1,8 +1,5 @@
1
- const {
2
- setLastUpdatedTime,
3
- wasLastUpdateOlderThanXSeconds,
4
- } = require('../src/services/lastUpdated')
5
- const { initializeTestService } = require('./initializeTests')
1
+ const { setLastUpdatedTime, wasLastUpdateOlderThanXSeconds } = require('../../src/lib/lastUpdated')
2
+ const { initializeTestService } = require('../initializeTests')
6
3
 
7
4
  describe('lastUpdated', function () {
8
5
  beforeEach(() => {
@@ -1,4 +1,4 @@
1
- import { getFieldsForContentType } from '../src/contentTypeConfig'
1
+ import { getFieldsForContentType} from '../src/contentTypeConfig'
2
2
  const railContentModule = require('../src/services/railcontent.js')
3
3
 
4
4
  import {
@@ -9,7 +9,7 @@ import {
9
9
  import { log } from './log.js'
10
10
  import { initializeTestService } from './initializeTests'
11
11
  import { dataContext } from '../src/services/contentProgress'
12
- import { fetchOwnedChallenges } from '../src'
12
+ import {fetchOwnedChallenges, getRecommendedForYou, globalConfig, recommendations} from '../src'
13
13
 
14
14
  const {
15
15
  fetchSongById,
@@ -869,25 +869,73 @@ describe('MetaData', function () {
869
869
  drumeoMetaData.url = ''
870
870
  expect(guitareoMetaData).toStrictEqual(drumeoMetaData)
871
871
  })
872
+ })
872
873
 
873
- test('withWithoutFilters', async () => {
874
- let metaData = processMetadata('singeo', 'student-review', true)
875
- expect(metaData.type).toBeDefined()
876
- expect(metaData.name).toBeDefined()
877
- expect(metaData.description).toBeDefined()
878
- expect(metaData.thumbnailUrl).toBeDefined()
874
+ describe('v2', function () {
875
+ beforeEach(() => {
876
+ initializeTestService()
877
+ })
878
+ test('metaDataForLessons', async () => {
879
+ const metaData = await fetchMetadata('drumeo', 'lessons')
880
+ log(metaData)
881
+ expect(metaData.filters).toBeDefined()
882
+ expect(metaData.sort).toBeDefined()
879
883
  expect(metaData.tabs).toBeDefined()
880
- metaData = processMetadata('singeo', 'student-review', false)
881
- expect(metaData.type).toBeDefined()
882
- expect(metaData.name).toBeDefined()
883
- expect(metaData.description).toBeDefined()
884
- expect(metaData.tabs).not.toBeDefined()
885
884
  })
886
885
 
887
- test('nulled', async () => {
888
- let metaData = processMetadata('drumeo', 'student-review')
889
- expect(metaData).toBeNull()
890
- metaData = processMetadata('singeo', 'student-review')
891
- expect(metaData).not.toBeNull()
886
+ test('metaDataForSongs', async () => {
887
+ const metaData = await fetchMetadata('drumeo', 'songs')
888
+ log(metaData)
889
+ expect(metaData.filters).toBeDefined()
890
+ expect(metaData.sort).toBeDefined()
891
+ expect(metaData.tabs).toBeDefined()
892
+ })
893
+
894
+ test('fetchAllFilterOptionsLessons', async () => {
895
+ const response = await fetchAllFilterOptions(
896
+ 'pianote',
897
+ [],null,null,'lessons'
898
+ )
899
+ log(response)
900
+ expect(response.meta.filters).toBeDefined()
901
+ })
902
+
903
+ test('fetchAllFilterOptionsSongs', async () => {
904
+ const response = await fetchAllFilterOptions(
905
+ 'pianote',
906
+ [],null,null,'songs'
907
+ )
908
+ log(response)
909
+ expect(response.meta.filters).toBeDefined()
910
+ })
911
+
912
+ test('fetchLiveEvent', async () => {
913
+ const liveEvent = await fetchLiveEvent('drumeo', 410881)
914
+ log(liveEvent)
915
+ //expect(metaData).toBeNull()
916
+ })
917
+ })
918
+
919
+ describe('Recommended System', function () {
920
+ beforeEach(() => {
921
+ initializeTestService()
922
+ })
923
+
924
+ test('getRecommendedForYou', async () => {
925
+ const results = await getRecommendedForYou('drumeo')
926
+ log(results)
927
+ expect(results.id).toBeDefined()
928
+ expect(results.title).toBeDefined()
929
+ expect(results.items).toBeDefined()
930
+ expect(results.items.length).toBeGreaterThanOrEqual(1)
931
+ })
932
+
933
+ test('getRecommendedForYou-SeeAll', async () => {
934
+ const results = await getRecommendedForYou('drumeo', 'recommended', {page: 1, limit:20})
935
+ log(results)
936
+ expect(results.type).toBeDefined()
937
+ expect(results.data).toBeDefined()
938
+ expect(results.meta).toBeDefined()
939
+ expect(results.data.length).toBeGreaterThanOrEqual(1)
892
940
  })
893
941
  })
@@ -1,7 +1,7 @@
1
- const { fetchUserPermissions } = require('../src/services/userPermissions')
2
- const { initializeTestService } = require('./initializeTests')
1
+ const { fetchUserPermissions } = require('../../src/services/user/permissions')
2
+ const { initializeTestService } = require('../initializeTests')
3
3
 
4
- describe('userPermissions', function () {
4
+ describe('user.permissions', function () {
5
5
  beforeEach(() => {
6
6
  initializeTestService()
7
7
  })
@@ -57,15 +57,28 @@ function getExclusionList(fileContent) {
57
57
 
58
58
  // get all files in the services directory
59
59
  const servicesDir = path.join(__dirname, '../src/services')
60
- const files = fs.readdirSync(servicesDir)
60
+ const treeElements = fs.readdirSync(servicesDir)
61
61
 
62
- files.forEach((file) => {
63
- const filePath = path.join(servicesDir, file)
62
+ function addFunctionsToFileExports(filePath, file) {
64
63
  const functionNames = extractExportedFunctions(filePath)
65
64
 
66
65
  if (functionNames.length > 0) {
67
66
  fileExports[file] = functionNames
68
67
  }
68
+ }
69
+
70
+ treeElements.forEach((treeNode) => {
71
+ const filePath = path.join(servicesDir, treeNode)
72
+
73
+ if (fs.lstatSync(filePath).isFile()) {
74
+ addFunctionsToFileExports(filePath, treeNode)
75
+ } else if (fs.lstatSync(filePath).isDirectory()) {
76
+ const subDir = fs.readdirSync(filePath)
77
+ subDir.forEach((subFile) => {
78
+ const filePath = path.join(servicesDir, treeNode, subFile)
79
+ addFunctionsToFileExports(filePath, treeNode + '/' + subFile)
80
+ })
81
+ }
69
82
  })
70
83
 
71
84
  // populate the index.js content string with the import/export of all functions