musora-content-services 2.169.4 → 2.171.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/.claude/settings.local.json +4 -14
- package/CHANGELOG.md +17 -0
- package/package.json +1 -1
- package/src/filterBuilder.js +2 -2
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/lib/sanity/decorators/examples.ts +3 -0
- package/src/lib/sanity/decorators/need-lifetime-upgrade.ts +1 -1
- package/src/lib/sanity/filter.ts +4 -4
- package/src/services/endScreen/endScreen.ts +2 -1
- package/src/services/forums/types.ts +2 -0
- package/src/services/permissions/PermissionsAdapter.ts +24 -0
- package/src/services/permissions/PermissionsV1Adapter.ts +2 -2
- package/src/services/permissions/PermissionsV2Adapter.ts +2 -2
- package/src/services/permissions/permissions.ts +2 -2
- package/src/services/permissions/types.d.ts +3 -0
- package/src/services/sanity.js +5 -5
- package/src/services/user/account.ts +24 -0
- package/src/services/user/types.d.ts +1 -0
- package/src/version-info.js +1 -1
- package/.yarn/install-state.gz +0 -0
- package/dist/services/api/types.js +0 -2
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(rg:*)",
|
|
5
|
-
"Bash(npm run lint:*)",
|
|
6
|
-
"Bash(ls:*)",
|
|
7
|
-
"Bash(npm test *)",
|
|
8
|
-
"Bash(npx jest *)"
|
|
9
|
-
],
|
|
10
|
-
"deny": []
|
|
11
|
-
},
|
|
12
2
|
"enabledMcpjsonServers": [
|
|
13
3
|
"1password",
|
|
14
4
|
"atlassian",
|
|
@@ -19,15 +9,15 @@
|
|
|
19
9
|
"hex",
|
|
20
10
|
"sanity",
|
|
21
11
|
"mysql",
|
|
12
|
+
"mysql-staging",
|
|
13
|
+
"mysql-local",
|
|
22
14
|
"slack",
|
|
23
15
|
"langfuse",
|
|
24
16
|
"chrome-devtools",
|
|
17
|
+
"mobile",
|
|
25
18
|
"railway",
|
|
26
19
|
"github",
|
|
27
20
|
"asana",
|
|
28
|
-
"nightwatch"
|
|
29
|
-
"mysql-staging",
|
|
30
|
-
"mysql-local",
|
|
31
|
-
"mobile"
|
|
21
|
+
"nightwatch"
|
|
32
22
|
]
|
|
33
23
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
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
|
+
## [2.171.0](https://github.com/railroadmedia/musora-content-services/compare/v2.170.0...v2.171.0) (2026-08-12)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* adds create pending user fn ([#1025](https://github.com/railroadmedia/musora-content-services/issues/1025)) ([c4ba8ef](https://github.com/railroadmedia/musora-content-services/commit/c4ba8ef3a118718236d177885372781714a08c9a))
|
|
11
|
+
|
|
12
|
+
## [2.170.0](https://github.com/railroadmedia/musora-content-services/compare/v2.169.4...v2.170.0) (2026-08-10)
|
|
13
|
+
|
|
14
|
+
## [2.169.0-0](https://github.com/railroadmedia/musora-content-services/compare/v2.168.0...v2.169.0-0) (2026-07-31)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **TP-1300:** add badge field to Liker, ForumUser, and User interfaces ([8a3ee80](https://github.com/railroadmedia/musora-content-services/commit/8a3ee802722a0d9dcd41a6a3998ff2a7a3352aeb))
|
|
20
|
+
|
|
5
21
|
### [2.169.4](https://github.com/railroadmedia/musora-content-services/compare/v2.169.3...v2.169.4) (2026-08-07)
|
|
6
22
|
|
|
7
23
|
|
|
@@ -30,6 +46,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
30
46
|
|
|
31
47
|
### Features
|
|
32
48
|
|
|
49
|
+
* **TP-1300:** add badge field to Liker, ForumUser, and User interfaces ([8a3ee80](https://github.com/railroadmedia/musora-content-services/commit/8a3ee802722a0d9dcd41a6a3998ff2a7a3352aeb))
|
|
33
50
|
* **BEHSTP-415:** MCS public announcement fetch fn's ([#1010](https://github.com/railroadmedia/musora-content-services/issues/1010)) ([d504fb1](https://github.com/railroadmedia/musora-content-services/commit/d504fb105ba5303bfe7327ddef24fe468bdec374))
|
|
34
51
|
|
|
35
52
|
## [2.168.0](https://github.com/railroadmedia/musora-content-services/compare/v2.167.6...v2.168.0) (2026-07-30)
|
package/package.json
CHANGED
package/src/filterBuilder.js
CHANGED
|
@@ -95,7 +95,7 @@ export class FilterBuilder {
|
|
|
95
95
|
// This must be run before _applyPublishDateRestrictions()
|
|
96
96
|
if (this.bypassStatuses) return this
|
|
97
97
|
if (this.availableContentStatuses.length === 0) {
|
|
98
|
-
if (this.userData.
|
|
98
|
+
if (this.userData.hasAllContentAccess) {
|
|
99
99
|
this.availableContentStatuses = [
|
|
100
100
|
this.STATUS_DRAFT,
|
|
101
101
|
this.STATUS_SCHEDULED,
|
|
@@ -136,7 +136,7 @@ export class FilterBuilder {
|
|
|
136
136
|
if (this.bypassPermissions && !this.showOnlyOwnedContent) return this
|
|
137
137
|
const adapter = getPermissionsAdapter()
|
|
138
138
|
// Check if admin (admins bypass permissions)
|
|
139
|
-
if (adapter.
|
|
139
|
+
if (adapter.hasAllContentAccess(this.userData) && !this.showOnlyOwnedContent) return this
|
|
140
140
|
|
|
141
141
|
// Generate permissions filter using adapter
|
|
142
142
|
const permissionsFilter = adapter.generatePermissionsFilter(this.userData, {
|
package/src/index.d.ts
CHANGED
|
@@ -410,6 +410,7 @@ import {
|
|
|
410
410
|
|
|
411
411
|
import {
|
|
412
412
|
confirmEmailChange,
|
|
413
|
+
createPendingAccount,
|
|
413
414
|
deleteAccount,
|
|
414
415
|
numberOfActiveUsers,
|
|
415
416
|
requestEmailChange,
|
|
@@ -569,6 +570,7 @@ declare module 'musora-content-services' {
|
|
|
569
570
|
createComment,
|
|
570
571
|
createForumCategory,
|
|
571
572
|
createInvites,
|
|
573
|
+
createPendingAccount,
|
|
572
574
|
createPlaylist,
|
|
573
575
|
createPost,
|
|
574
576
|
createPracticeNotes,
|
package/src/index.js
CHANGED
|
@@ -414,6 +414,7 @@ import {
|
|
|
414
414
|
|
|
415
415
|
import {
|
|
416
416
|
confirmEmailChange,
|
|
417
|
+
createPendingAccount,
|
|
417
418
|
deleteAccount,
|
|
418
419
|
numberOfActiveUsers,
|
|
419
420
|
requestEmailChange,
|
|
@@ -568,6 +569,7 @@ export {
|
|
|
568
569
|
createComment,
|
|
569
570
|
createForumCategory,
|
|
570
571
|
createInvites,
|
|
572
|
+
createPendingAccount,
|
|
571
573
|
createPlaylist,
|
|
572
574
|
createPost,
|
|
573
575
|
createPracticeNotes,
|
|
@@ -22,7 +22,7 @@ export function lifetimeUpgradeDecorator(
|
|
|
22
22
|
return {
|
|
23
23
|
field: NEED_LIFETIME_UPGRADE_FIELD,
|
|
24
24
|
compute: (item) => {
|
|
25
|
-
if (userPermissions?.
|
|
25
|
+
if (userPermissions?.hasAllContentAccess || !hasLifetime || hasPlus) return false
|
|
26
26
|
if (!item.need_access) return false
|
|
27
27
|
return item.membership_tier === 'plus'
|
|
28
28
|
},
|
package/src/lib/sanity/filter.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface StatusConfig {
|
|
|
23
23
|
statuses?: string[]
|
|
24
24
|
bypassStatuses?: boolean
|
|
25
25
|
isSingle?: boolean
|
|
26
|
-
|
|
26
|
+
hasAllContentAccess?: boolean
|
|
27
27
|
prefix?: Prefix
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -349,7 +349,7 @@ export class Filters {
|
|
|
349
349
|
const adapter = getPermissionsAdapter()
|
|
350
350
|
const userData = config.userData || (await adapter.fetchUserPermissions())
|
|
351
351
|
|
|
352
|
-
if (adapter.
|
|
352
|
+
if (adapter.hasAllContentAccess(userData)) return ''
|
|
353
353
|
|
|
354
354
|
const permissionsFilter = adapter.generatePermissionsFilter(userData, {
|
|
355
355
|
prefix: config.prefix || '',
|
|
@@ -373,9 +373,9 @@ export class Filters {
|
|
|
373
373
|
// Auto-determine statuses if not provided
|
|
374
374
|
if (statuses.length === 0) {
|
|
375
375
|
const userData = await getPermissionsAdapter().fetchUserPermissions()
|
|
376
|
-
const
|
|
376
|
+
const hasAllContentAccess = getPermissionsAdapter().hasAllContentAccess(userData)
|
|
377
377
|
|
|
378
|
-
if (config.
|
|
378
|
+
if (config.hasAllContentAccess || hasAllContentAccess) {
|
|
379
379
|
statuses = [
|
|
380
380
|
STATUS_DRAFT,
|
|
381
381
|
STATUS_SCHEDULED,
|
|
@@ -34,7 +34,8 @@ export async function getEndScreen({
|
|
|
34
34
|
brand
|
|
35
35
|
}: GetEndScreenParams): Promise<EndScreenResult> {
|
|
36
36
|
const userData = await getUserData()
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
const isAdmin = userData?.has_all_content_access ?? false
|
|
38
39
|
|
|
39
40
|
if (playlist) {
|
|
40
41
|
const nextItem = next_item ??
|
|
@@ -10,6 +10,7 @@ export interface Liker {
|
|
|
10
10
|
access_level: string
|
|
11
11
|
liked_at: string
|
|
12
12
|
liked_at_diff: string | null
|
|
13
|
+
badge: string | null
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface WhoLikedResponse {
|
|
@@ -27,6 +28,7 @@ export interface ForumUser {
|
|
|
27
28
|
profile_picture_url: string | null
|
|
28
29
|
access_level: string
|
|
29
30
|
signature: string | null
|
|
31
|
+
badge: string | null
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export interface ForumPost {
|
|
@@ -106,4 +106,28 @@ export abstract class PermissionsAdapter {
|
|
|
106
106
|
isModerator(userPermissions: UserPermissions): boolean {
|
|
107
107
|
return userPermissions?.isModerator ?? false
|
|
108
108
|
}
|
|
109
|
+
|
|
110
|
+
hasAllContentAccess(userPermissions: UserPermissions): boolean {
|
|
111
|
+
return userPermissions?.hasAllContentAccess ?? false
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if user is a forum moderator.
|
|
116
|
+
*
|
|
117
|
+
* @param userPermissions - The user's permissions
|
|
118
|
+
* @returns True if user is a forum moderator
|
|
119
|
+
*/
|
|
120
|
+
isForumModerator(userPermissions: UserPermissions): boolean {
|
|
121
|
+
return userPermissions?.isForumModerator ?? false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Check if user is a comment moderator.
|
|
126
|
+
*
|
|
127
|
+
* @param userPermissions - The user's permissions
|
|
128
|
+
* @returns True if user is a comment moderator
|
|
129
|
+
*/
|
|
130
|
+
isCommentModerator(userPermissions: UserPermissions): boolean {
|
|
131
|
+
return userPermissions?.isCommentModerator ?? false
|
|
132
|
+
}
|
|
109
133
|
}
|
|
@@ -52,7 +52,7 @@ export class PermissionsV1Adapter extends PermissionsAdapter {
|
|
|
52
52
|
*/
|
|
53
53
|
doesUserNeedAccess(content: ContentItem, userPermissions: UserPermissions): boolean {
|
|
54
54
|
// Admins always have access
|
|
55
|
-
if (this.
|
|
55
|
+
if (this.hasAllContentAccess(userPermissions)) {
|
|
56
56
|
return false
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -102,7 +102,7 @@ export class PermissionsV1Adapter extends PermissionsAdapter {
|
|
|
102
102
|
} = options
|
|
103
103
|
|
|
104
104
|
// Admins bypass permission filter
|
|
105
|
-
if (this.
|
|
105
|
+
if (this.hasAllContentAccess(userPermissions)) {
|
|
106
106
|
return null
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -47,7 +47,7 @@ export class PermissionsV2Adapter extends PermissionsAdapter {
|
|
|
47
47
|
*/
|
|
48
48
|
doesUserNeedAccess(content: ContentItem, userPermissions: UserPermissions): boolean {
|
|
49
49
|
// Admins always have access
|
|
50
|
-
if (this.
|
|
50
|
+
if (this.hasAllContentAccess(userPermissions)) {
|
|
51
51
|
return false
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -108,7 +108,7 @@ export class PermissionsV2Adapter extends PermissionsAdapter {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// Admins bypass permission filter
|
|
111
|
-
if (this.
|
|
111
|
+
if (this.hasAllContentAccess(userPermissions)) {
|
|
112
112
|
return null
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -38,7 +38,7 @@ export async function reset(): Promise<void> {
|
|
|
38
38
|
export function isUserFreeTier(userPermissions: UserPermissions): boolean {
|
|
39
39
|
const permissions = userPermissions.permissions
|
|
40
40
|
|
|
41
|
-
if (userPermissions.
|
|
41
|
+
if (userPermissions.hasAllContentAccess) return false
|
|
42
42
|
|
|
43
43
|
return permissions.includes(MEMBERSHIP_PERMISSIONS.free)
|
|
44
44
|
&& !permissions.some(p => [MEMBERSHIP_PERMISSIONS.base, MEMBERSHIP_PERMISSIONS.plus].includes(p))
|
|
@@ -46,7 +46,7 @@ export function isUserFreeTier(userPermissions: UserPermissions): boolean {
|
|
|
46
46
|
|
|
47
47
|
export function doesUserHaveMembership(userPermissions: UserPermissions): boolean {
|
|
48
48
|
const permissions = userPermissions.permissions
|
|
49
|
-
return userPermissions.
|
|
49
|
+
return userPermissions.hasAllContentAccess
|
|
50
50
|
|| permissions.includes(MEMBERSHIP_PERMISSIONS.base)
|
|
51
51
|
|| permissions.includes(MEMBERSHIP_PERMISSIONS.plus)
|
|
52
52
|
}
|
|
@@ -3,4 +3,7 @@ export interface UserPermissions {
|
|
|
3
3
|
isAdmin: boolean // Whether the user is an admin
|
|
4
4
|
isModerator: boolean // Whether the user is a moderator
|
|
5
5
|
isABasicMember: boolean // Whether the user has basic membership
|
|
6
|
+
hasAllContentAccess: boolean
|
|
7
|
+
isForumModerator: boolean
|
|
8
|
+
isCommentModerator: boolean
|
|
6
9
|
}
|
package/src/services/sanity.js
CHANGED
|
@@ -899,14 +899,14 @@ export async function fetchAllFilterOptions(
|
|
|
899
899
|
const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : ''
|
|
900
900
|
const adapter = getPermissionsAdapter()
|
|
901
901
|
const userPermissionsData = await adapter.fetchUserPermissions()
|
|
902
|
-
const
|
|
902
|
+
const hasAllContentAccess = adapter.hasAllContentAccess(userPermissionsData)
|
|
903
903
|
|
|
904
904
|
const constructCommonFilter = (excludeFilter) => {
|
|
905
905
|
const filterWithoutOption = excludeFilter
|
|
906
906
|
? filtersToGroq(filters, excludeFilter)
|
|
907
907
|
: includedFieldsFilter
|
|
908
908
|
const statusFilter = ' && status == "published"'
|
|
909
|
-
const includeStatusFilter = !
|
|
909
|
+
const includeStatusFilter = !hasAllContentAccess && !['instructor', 'artist', 'genre'].includes(contentType)
|
|
910
910
|
|
|
911
911
|
return coachId
|
|
912
912
|
? `brand == '${brand}' && status == "published" && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''} ${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}`
|
|
@@ -2117,14 +2117,14 @@ export async function fetchTabData(
|
|
|
2117
2117
|
// Check if user is admin to determine available content statuses
|
|
2118
2118
|
const adapter = getPermissionsAdapter()
|
|
2119
2119
|
const userData = await adapter.fetchUserPermissions()
|
|
2120
|
-
const
|
|
2120
|
+
const hasAllContentAccess = adapter.hasAllContentAccess(userData)
|
|
2121
2121
|
|
|
2122
2122
|
const filterWithRestrictions = await new FilterBuilder(filter, {
|
|
2123
2123
|
showMembershipRestrictedContent: true,
|
|
2124
|
-
availableContentStatuses:
|
|
2124
|
+
availableContentStatuses: hasAllContentAccess
|
|
2125
2125
|
? CONTENT_STATUSES.ADMIN_ALL
|
|
2126
2126
|
: CONTENT_STATUSES.PUBLISHED_ONLY,
|
|
2127
|
-
pullFutureContent:
|
|
2127
|
+
pullFutureContent: hasAllContentAccess
|
|
2128
2128
|
}).buildFilter()
|
|
2129
2129
|
query = buildEntityAndTotalQuery(filterWithRestrictions, entityFieldsString, {
|
|
2130
2130
|
sortOrder: sortOrder,
|
|
@@ -109,6 +109,30 @@ export async function setupAccount(props: AccountSetupProps): Promise<AccountSet
|
|
|
109
109
|
return res
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
export interface PendingAccountProps {
|
|
113
|
+
email: string
|
|
114
|
+
revenuecatAppUserId?: string
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {Object} props - The parameters for creating the pending account.
|
|
119
|
+
* @property {string} email - The email address for the account.
|
|
120
|
+
* @property {string} [revenuecatAppUserId] - The RevenueCat App User ID for MA environments.
|
|
121
|
+
*
|
|
122
|
+
* @returns {Promise<AccountSetupResponse>} - A promise that resolves when the pending account is created or an HttpError if the request fails.
|
|
123
|
+
* @throws {HttpError} - Throws an HttpError if the HTTP request fails.
|
|
124
|
+
*/
|
|
125
|
+
export async function createPendingAccount(props: PendingAccountProps): Promise<AccountSetupResponse> {
|
|
126
|
+
const httpClient = new HttpClient(globalConfig.baseUrl)
|
|
127
|
+
return await httpClient.post<AccountSetupResponse>(
|
|
128
|
+
`/api/user-management-system/v1/accounts/pending`,
|
|
129
|
+
{
|
|
130
|
+
email: props.email,
|
|
131
|
+
mobile_app_id: props.revenuecatAppUserId,
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
112
136
|
/**
|
|
113
137
|
* @param {string} email - The email address to send the password reset email to.
|
|
114
138
|
* @returns {Promise<void>} - A promise that resolves when the email change request is made.
|
package/src/version-info.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const MCS_VERSION = '2.
|
|
1
|
+
export const MCS_VERSION = '2.171.0'
|
package/.yarn/install-state.gz
DELETED
|
Binary file
|