musora-content-services 1.3.18 → 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.
- package/.editorconfig +16 -0
- package/CHANGELOG.md +1 -1
- package/docs/config.js.html +14 -5
- package/docs/content.js.html +425 -0
- package/docs/global.html +3026 -0
- package/docs/index.html +2 -2
- package/docs/module-Config.html +60 -7
- package/docs/module-Content-Services-V2.html +2433 -0
- package/docs/module-Railcontent-Services.html +522 -2
- package/docs/module-Sanity-Services.html +57 -43
- package/docs/module-Session-Management.html +575 -0
- package/docs/module-User-Permissions.html +406 -0
- package/docs/railcontent.js.html +42 -5
- package/docs/sanity.js.html +290 -103
- package/docs/user_permissions.js.html +110 -0
- package/docs/user_sessions.js.html +139 -0
- package/docs/user_types.js.html +188 -0
- package/jsdoc.json +2 -0
- package/package.json +1 -1
- package/publish.sh +2 -2
- package/src/contentMetaData.js +307 -1088
- package/src/contentTypeConfig.js +108 -4
- package/src/filterBuilder.js +6 -6
- package/src/index.d.ts +41 -6
- package/src/index.js +41 -6
- package/src/{services → lib}/lastUpdated.js +17 -1
- package/src/services/config.js +0 -0
- package/src/services/content.js +371 -0
- package/src/services/dataContext.js +0 -0
- package/src/services/forum.js +57 -0
- package/src/services/railcontent.js +3 -3
- package/src/services/recommendations.js +19 -0
- package/src/services/sanity.js +278 -104
- package/src/services/{userPermissions.js → user/permissions.js} +16 -2
- package/src/services/user/sessions.js +67 -0
- package/src/services/user/types.js +116 -0
- package/src/services/userActivity.js +32 -0
- package/test/content.test.js +116 -0
- package/test/contentLikes.test.js +0 -0
- package/test/contentProgress.test.js +83 -5
- package/test/forum.test.js +18 -0
- package/test/initializeTests.js +6 -1
- package/test/{lastUpdated.test.js → lib/lastUpdated.test.js} +2 -5
- package/test/sanityQueryService.test.js +66 -18
- package/test/{userPermissions.test.js → user/permissions.test.js} +3 -3
- 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
|
|
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},
|
|
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([
|
|
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
|
+
})
|
package/test/initializeTests.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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('
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
metaData
|
|
891
|
-
expect(metaData).
|
|
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('
|
|
2
|
-
const { initializeTestService } = require('
|
|
1
|
+
const { fetchUserPermissions } = require('../../src/services/user/permissions')
|
|
2
|
+
const { initializeTestService } = require('../initializeTests')
|
|
3
3
|
|
|
4
|
-
describe('
|
|
4
|
+
describe('user.permissions', function () {
|
|
5
5
|
beforeEach(() => {
|
|
6
6
|
initializeTestService()
|
|
7
7
|
})
|
package/tools/generate-index.cjs
CHANGED
|
@@ -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
|
|
60
|
+
const treeElements = fs.readdirSync(servicesDir)
|
|
61
61
|
|
|
62
|
-
|
|
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
|