musora-content-services 2.107.2 → 2.107.4
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 +6 -9
- package/.yarnrc.yml +1 -0
- package/CHANGELOG.md +18 -0
- package/check_content.js +30 -0
- package/check_content.mjs +32 -0
- package/package.json +1 -1
- package/src/filterBuilder.js +0 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +17 -0
- package/src/infrastructure/http/HttpClient.ts +0 -0
- package/src/lib/ads/monoid.ts +0 -0
- package/src/lib/ads/semigroup.ts +0 -0
- package/src/lib/sanity/filter.ts +0 -0
- package/src/lib/sanity/query.ts +0 -0
- package/src/services/awards/award-callbacks.js +0 -0
- package/src/services/awards/award-query.js +0 -0
- package/src/services/awards/internal/award-definitions.js +0 -0
- package/src/services/awards/internal/award-manager.js +0 -0
- package/src/services/awards/internal/certificate-builder.js +0 -0
- package/src/services/awards/types.d.ts +0 -0
- package/src/services/awards/types.js +0 -0
- package/src/services/content/artist.ts +5 -5
- package/src/services/content/genre.ts +5 -5
- package/src/services/content/instructor.ts +7 -6
- package/src/services/content-org/guided-courses.ts +0 -0
- package/src/services/content-org/learning-paths.ts +0 -0
- package/src/services/content-org/playlists.js +0 -0
- package/src/services/content.js +0 -0
- package/src/services/contentAggregator.js +0 -0
- package/src/services/contentProgress.js +0 -0
- package/src/services/forums/forums.ts +0 -0
- package/src/services/forums/posts.ts +50 -2
- package/src/services/forums/threads.ts +13 -0
- package/src/services/permissions/PermissionsV2Adapter.ts +0 -0
- package/src/services/progress-events.js +0 -0
- package/src/services/progress-row/method-card.js +0 -0
- package/src/services/railcontent.js +80 -3
- package/src/services/recommendations.js +0 -0
- package/src/services/reporting/reporting.ts +71 -3
- package/src/services/sync/errors/index.ts +0 -0
- package/src/services/sync/errors/validators.ts +0 -0
- package/src/services/sync/fetch.ts +0 -0
- package/src/services/sync/manager.ts +0 -0
- package/src/services/sync/models/ContentLike.ts +0 -0
- package/src/services/sync/models/ContentProgress.ts +0 -0
- package/src/services/sync/models/Practice.ts +0 -0
- package/src/services/sync/models/PracticeDayNote.ts +0 -0
- package/src/services/sync/models/UserAwardProgress.ts +0 -0
- package/src/services/sync/repositories/content-progress.ts +0 -0
- package/src/services/sync/repositories/user-award-progress.ts +0 -0
- package/src/services/sync/retry.ts +0 -0
- package/src/services/sync/schema/index.ts +0 -0
- package/src/services/sync/store/index.ts +0 -0
- package/src/services/urlBuilder.ts +297 -0
- package/src/services/user/chat.js +0 -0
- package/src/services/user/interests.js +0 -0
- package/src/services/user/management.js +0 -0
- package/src/services/user/memberships.ts +0 -0
- package/src/services/user/notifications.js +0 -0
- package/src/services/user/onboarding.ts +12 -122
- package/src/services/user/profile.js +0 -0
- package/src/services/user/sessions.js +0 -0
- package/src/services/user/types.d.ts +0 -0
- package/src/services/user/types.js +0 -0
- package/src/services/userActivity.js +0 -0
- package/test/awards/award-completion-flow.test.js +0 -0
- package/test/initializeTests.js +0 -0
- package/test/learningPaths.test.js +0 -0
- package/test/lib/__snapshots__/filter.test.ts.snap +0 -0
- package/test/lib/filter.test.ts +0 -0
- package/test/lib/query.test.ts +0 -0
- package/test/reporting.test.js +132 -0
- package/test/sanityQueryService.test.js +0 -0
- package/test/sync/adapter.ts +0 -0
- package/test/sync/initialize-sync-manager.js +0 -0
- package/test_owned_navigate.js +74 -0
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
|
+
"Read(//app/musora-platform-backend/**)",
|
|
5
|
+
"Read(//app/musora-platform-frontend/**)",
|
|
4
6
|
"Bash(find:*)",
|
|
5
|
-
"Bash(
|
|
6
|
-
"
|
|
7
|
-
"WebSearch",
|
|
8
|
-
"WebFetch(domain:watermelondb.dev)",
|
|
9
|
-
"WebFetch(domain:github.com)",
|
|
10
|
-
"Bash(git checkout:*)",
|
|
11
|
-
"Bash(npm run doc:*)",
|
|
7
|
+
"Bash(sed:*)",
|
|
8
|
+
"Read(//app/**)",
|
|
12
9
|
"Bash(cat:*)",
|
|
13
|
-
"Bash(
|
|
14
|
-
"Bash(npm
|
|
10
|
+
"Bash(docker exec:*)",
|
|
11
|
+
"Bash(npm config:*)"
|
|
15
12
|
],
|
|
16
13
|
"deny": [],
|
|
17
14
|
"ask": []
|
package/.yarnrc.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodeLinker: node-modules
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
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.107.4](https://github.com/railroadmedia/musora-content-services/compare/v2.107.1...v2.107.4) (2025-12-22)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **AGI:** contentType optional ([deae293](https://github.com/railroadmedia/musora-content-services/commit/deae2934c26ea0b9ee4d68c736fbb5753616a5e9))
|
|
11
|
+
* **AGI:** return children on AGI lessons functions ([#671](https://github.com/railroadmedia/musora-content-services/issues/671)) ([92ed791](https://github.com/railroadmedia/musora-content-services/commit/92ed791ce563aa4f1bf16cb41d2b6fe421504064))
|
|
12
|
+
* **onboarding:** call BE for recommendation ([#670](https://github.com/railroadmedia/musora-content-services/issues/670)) ([a876736](https://github.com/railroadmedia/musora-content-services/commit/a8767363ff3428638bde477cd6c30e5bf61179b2))
|
|
13
|
+
|
|
14
|
+
### [2.107.3](https://github.com/railroadmedia/musora-content-services/compare/v2.107.2...v2.107.3) (2025-12-19)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **AGI:** contentType optional ([deae293](https://github.com/railroadmedia/musora-content-services/commit/deae2934c26ea0b9ee4d68c736fbb5753616a5e9))
|
|
20
|
+
* **AGI:** return children on AGI lessons functions ([#671](https://github.com/railroadmedia/musora-content-services/issues/671)) ([92ed791](https://github.com/railroadmedia/musora-content-services/commit/92ed791ce563aa4f1bf16cb41d2b6fe421504064))
|
|
21
|
+
* **onboarding:** call BE for recommendation ([#670](https://github.com/railroadmedia/musora-content-services/issues/670)) ([a876736](https://github.com/railroadmedia/musora-content-services/commit/a8767363ff3428638bde477cd6c30e5bf61179b2))
|
|
22
|
+
|
|
5
23
|
### [2.107.2](https://github.com/railroadmedia/musora-content-services/compare/v2.107.1...v2.107.2) (2025-12-19)
|
|
6
24
|
|
|
7
25
|
### [2.107.1](https://github.com/railroadmedia/musora-content-services/compare/v2.107.0...v2.107.1) (2025-12-19)
|
package/check_content.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { initializeService } = require('./src/services/config.js');
|
|
2
|
+
const { fetchByRailContentIds } = require('./src/services/sanity.js');
|
|
3
|
+
require('dotenv/config');
|
|
4
|
+
|
|
5
|
+
async function checkContent() {
|
|
6
|
+
initializeService({
|
|
7
|
+
sanityConfig: {
|
|
8
|
+
token: process.env.SANITY_TOKEN,
|
|
9
|
+
projectId: process.env.SANITY_PROJECT_ID,
|
|
10
|
+
dataset: process.env.SANITY_DATASET,
|
|
11
|
+
version: process.env.SANITY_VERSION || '2021-06-07',
|
|
12
|
+
},
|
|
13
|
+
railcontentConfig: {
|
|
14
|
+
token: process.env.RAILCONTENT_TOKEN,
|
|
15
|
+
userId: process.env.RAILCONTENT_USER_ID,
|
|
16
|
+
baseUrl: process.env.RAILCONTENT_BASE_URL,
|
|
17
|
+
authToken: process.env.RAILCONTENT_AUTH_TOKEN,
|
|
18
|
+
},
|
|
19
|
+
baseUrl: process.env.RAILCONTENT_BASE_URL,
|
|
20
|
+
localStorage: null,
|
|
21
|
+
isMA: false,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log('Checking railcontent_id: 421814');
|
|
25
|
+
const contents = await fetchByRailContentIds([421814]);
|
|
26
|
+
console.log('Results:', JSON.stringify(contents, null, 2));
|
|
27
|
+
console.log('Found:', contents.length, 'items');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
checkContent().catch(console.error);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { initializeService } from './src/services/config.js';
|
|
2
|
+
import { fetchByRailContentIds } from './src/services/sanity.js';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
|
|
5
|
+
dotenv.config();
|
|
6
|
+
|
|
7
|
+
async function checkContent() {
|
|
8
|
+
initializeService({
|
|
9
|
+
sanityConfig: {
|
|
10
|
+
token: process.env.SANITY_TOKEN,
|
|
11
|
+
projectId: process.env.SANITY_PROJECT_ID,
|
|
12
|
+
dataset: process.env.SANITY_DATASET,
|
|
13
|
+
version: process.env.SANITY_VERSION || '2021-06-07',
|
|
14
|
+
},
|
|
15
|
+
railcontentConfig: {
|
|
16
|
+
token: process.env.RAILCONTENT_TOKEN,
|
|
17
|
+
userId: process.env.RAILCONTENT_USER_ID,
|
|
18
|
+
baseUrl: process.env.RAILCONTENT_BASE_URL,
|
|
19
|
+
authToken: process.env.RAILCONTENT_AUTH_TOKEN,
|
|
20
|
+
},
|
|
21
|
+
baseUrl: process.env.RAILCONTENT_BASE_URL,
|
|
22
|
+
localStorage: null,
|
|
23
|
+
isMA: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
console.log('Checking railcontent_id: 421814');
|
|
27
|
+
const contents = await fetchByRailContentIds([421814]);
|
|
28
|
+
console.log('Results:', JSON.stringify(contents, null, 2));
|
|
29
|
+
console.log('Found:', contents.length, 'items');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
checkContent().catch(console.error);
|
package/package.json
CHANGED
package/src/filterBuilder.js
CHANGED
|
File without changes
|
package/src/index.d.ts
CHANGED
|
@@ -155,6 +155,7 @@ import {
|
|
|
155
155
|
createPost,
|
|
156
156
|
deletePost,
|
|
157
157
|
fetchCommunityGuidelines,
|
|
158
|
+
fetchPost,
|
|
158
159
|
fetchPosts,
|
|
159
160
|
jumpToPost,
|
|
160
161
|
likePost,
|
|
@@ -168,6 +169,7 @@ import {
|
|
|
168
169
|
deleteThread,
|
|
169
170
|
fetchFollowedThreads,
|
|
170
171
|
fetchLatestThreads,
|
|
172
|
+
fetchThread,
|
|
171
173
|
fetchThreads,
|
|
172
174
|
followThread,
|
|
173
175
|
lockThread,
|
|
@@ -310,6 +312,14 @@ import {
|
|
|
310
312
|
jumpToContinueContent
|
|
311
313
|
} from './services/sanity.js';
|
|
312
314
|
|
|
315
|
+
import {
|
|
316
|
+
generateCommentUrl,
|
|
317
|
+
generateContentUrl,
|
|
318
|
+
generateContentUrlWithDomain,
|
|
319
|
+
generateForumPostUrl,
|
|
320
|
+
generatePlaylistUrl
|
|
321
|
+
} from './services/urlBuilder.ts';
|
|
322
|
+
|
|
313
323
|
import {
|
|
314
324
|
confirmEmailChange,
|
|
315
325
|
deleteAccount,
|
|
@@ -543,6 +553,7 @@ declare module 'musora-content-services' {
|
|
|
543
553
|
fetchPlayAlongsCount,
|
|
544
554
|
fetchPlaylist,
|
|
545
555
|
fetchPlaylistItems,
|
|
556
|
+
fetchPost,
|
|
546
557
|
fetchPosts,
|
|
547
558
|
fetchRecent,
|
|
548
559
|
fetchRecentActivitiesActiveTabs,
|
|
@@ -563,6 +574,7 @@ declare module 'musora-content-services' {
|
|
|
563
574
|
fetchSongById,
|
|
564
575
|
fetchSongsInProgress,
|
|
565
576
|
fetchTabData,
|
|
577
|
+
fetchThread,
|
|
566
578
|
fetchThreads,
|
|
567
579
|
fetchTopComment,
|
|
568
580
|
fetchTopLevelParentId,
|
|
@@ -580,6 +592,11 @@ declare module 'musora-content-services' {
|
|
|
580
592
|
findIncompleteLesson,
|
|
581
593
|
followThread,
|
|
582
594
|
generateAuthSessionUrl,
|
|
595
|
+
generateCommentUrl,
|
|
596
|
+
generateContentUrl,
|
|
597
|
+
generateContentUrlWithDomain,
|
|
598
|
+
generateForumPostUrl,
|
|
599
|
+
generatePlaylistUrl,
|
|
583
600
|
getActiveDiscussions,
|
|
584
601
|
getActivePath,
|
|
585
602
|
getAllCompleted,
|
package/src/index.js
CHANGED
|
@@ -159,6 +159,7 @@ import {
|
|
|
159
159
|
createPost,
|
|
160
160
|
deletePost,
|
|
161
161
|
fetchCommunityGuidelines,
|
|
162
|
+
fetchPost,
|
|
162
163
|
fetchPosts,
|
|
163
164
|
jumpToPost,
|
|
164
165
|
likePost,
|
|
@@ -172,6 +173,7 @@ import {
|
|
|
172
173
|
deleteThread,
|
|
173
174
|
fetchFollowedThreads,
|
|
174
175
|
fetchLatestThreads,
|
|
176
|
+
fetchThread,
|
|
175
177
|
fetchThreads,
|
|
176
178
|
followThread,
|
|
177
179
|
lockThread,
|
|
@@ -314,6 +316,14 @@ import {
|
|
|
314
316
|
jumpToContinueContent
|
|
315
317
|
} from './services/sanity.js';
|
|
316
318
|
|
|
319
|
+
import {
|
|
320
|
+
generateCommentUrl,
|
|
321
|
+
generateContentUrl,
|
|
322
|
+
generateContentUrlWithDomain,
|
|
323
|
+
generateForumPostUrl,
|
|
324
|
+
generatePlaylistUrl
|
|
325
|
+
} from './services/urlBuilder.ts';
|
|
326
|
+
|
|
317
327
|
import {
|
|
318
328
|
confirmEmailChange,
|
|
319
329
|
deleteAccount,
|
|
@@ -542,6 +552,7 @@ export {
|
|
|
542
552
|
fetchPlayAlongsCount,
|
|
543
553
|
fetchPlaylist,
|
|
544
554
|
fetchPlaylistItems,
|
|
555
|
+
fetchPost,
|
|
545
556
|
fetchPosts,
|
|
546
557
|
fetchRecent,
|
|
547
558
|
fetchRecentActivitiesActiveTabs,
|
|
@@ -562,6 +573,7 @@ export {
|
|
|
562
573
|
fetchSongById,
|
|
563
574
|
fetchSongsInProgress,
|
|
564
575
|
fetchTabData,
|
|
576
|
+
fetchThread,
|
|
565
577
|
fetchThreads,
|
|
566
578
|
fetchTopComment,
|
|
567
579
|
fetchTopLevelParentId,
|
|
@@ -579,6 +591,11 @@ export {
|
|
|
579
591
|
findIncompleteLesson,
|
|
580
592
|
followThread,
|
|
581
593
|
generateAuthSessionUrl,
|
|
594
|
+
generateCommentUrl,
|
|
595
|
+
generateContentUrl,
|
|
596
|
+
generateContentUrlWithDomain,
|
|
597
|
+
generateForumPostUrl,
|
|
598
|
+
generatePlaylistUrl,
|
|
582
599
|
getActiveDiscussions,
|
|
583
600
|
getActivePath,
|
|
584
601
|
getAllCompleted,
|
|
File without changes
|
package/src/lib/ads/monoid.ts
CHANGED
|
File without changes
|
package/src/lib/ads/semigroup.ts
CHANGED
|
File without changes
|
package/src/lib/sanity/filter.ts
CHANGED
|
File without changes
|
package/src/lib/sanity/query.ts
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
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Artist
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { getFieldsForContentTypeWithFilteredChildren } from '../../contentTypeConfig.js'
|
|
5
|
+
import { Brands } from '../../lib/brands'
|
|
6
|
+
import { Filters as f } from '../../lib/sanity/filter'
|
|
5
7
|
import { BuildQueryOptions, query } from '../../lib/sanity/query'
|
|
6
8
|
import { fetchSanity, getSortOrder } from '../sanity.js'
|
|
7
9
|
import { Lesson } from './content'
|
|
8
|
-
import { Brands } from '../../lib/brands'
|
|
9
|
-
import { Filters as f } from '../../lib/sanity/filter'
|
|
10
10
|
|
|
11
11
|
export interface Artist {
|
|
12
12
|
slug: string
|
|
@@ -123,7 +123,7 @@ export interface ArtistLessons {
|
|
|
123
123
|
export async function fetchArtistLessons(
|
|
124
124
|
slug: string,
|
|
125
125
|
brand: Brands | string,
|
|
126
|
-
contentType
|
|
126
|
+
contentType?: string,
|
|
127
127
|
{
|
|
128
128
|
sort = '-published_on',
|
|
129
129
|
searchTerm = '',
|
|
@@ -150,7 +150,7 @@ export async function fetchArtistLessons(
|
|
|
150
150
|
.and(restrictions)
|
|
151
151
|
.order(sort)
|
|
152
152
|
.slice(offset, limit)
|
|
153
|
-
.select(
|
|
153
|
+
.select((await getFieldsForContentTypeWithFilteredChildren(contentType, true)) as string)
|
|
154
154
|
.build()
|
|
155
155
|
|
|
156
156
|
const total = query().and(restrictions).build()
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Genre
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import { fetchSanity, getSortOrder } from '../sanity.js'
|
|
6
|
-
import { Lesson } from './content'
|
|
7
|
-
import { BuildQueryOptions, query } from '../../lib/sanity/query'
|
|
4
|
+
import { getFieldsForContentTypeWithFilteredChildren } from '../../contentTypeConfig.js'
|
|
8
5
|
import { Brands } from '../../lib/brands'
|
|
9
6
|
import { Filters as f } from '../../lib/sanity/filter'
|
|
7
|
+
import { BuildQueryOptions, query } from '../../lib/sanity/query'
|
|
8
|
+
import { fetchSanity, getSortOrder } from '../sanity.js'
|
|
9
|
+
import { Lesson } from './content'
|
|
10
10
|
|
|
11
11
|
export interface Genre {
|
|
12
12
|
name: string
|
|
@@ -149,7 +149,7 @@ export async function fetchGenreLessons(
|
|
|
149
149
|
.and(restrictions)
|
|
150
150
|
.order(sort)
|
|
151
151
|
.slice(offset, limit)
|
|
152
|
-
.select(
|
|
152
|
+
.select((await getFieldsForContentTypeWithFilteredChildren(contentType, true)) as string)
|
|
153
153
|
.build()
|
|
154
154
|
|
|
155
155
|
const total = query().and(restrictions).build()
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Instructor
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import { fetchSanity, getSortOrder } from '../sanity.js'
|
|
6
|
-
import { Lesson } from './content'
|
|
7
|
-
import { BuildQueryOptions, query } from '../../lib/sanity/query'
|
|
4
|
+
import { getFieldsForContentTypeWithFilteredChildren } from '../../contentTypeConfig.js'
|
|
8
5
|
import { Brands } from '../../lib/brands'
|
|
9
6
|
import { Filters as f } from '../../lib/sanity/filter'
|
|
7
|
+
import { BuildQueryOptions, query } from '../../lib/sanity/query'
|
|
8
|
+
import { fetchSanity, getSortOrder } from '../sanity.js'
|
|
9
|
+
import { Lesson } from './content'
|
|
10
10
|
|
|
11
11
|
export interface Instructor {
|
|
12
12
|
lesson_count: number
|
|
@@ -106,7 +106,7 @@ export interface InstructorLessons {
|
|
|
106
106
|
* Fetch the data needed for the instructor screen.
|
|
107
107
|
* @param {string} slug - The slug of the instructor
|
|
108
108
|
* @param {Brands|string} brand - The brand for which to fetch instructor lessons
|
|
109
|
-
*
|
|
109
|
+
* @param {string|null} [contentType] - The content type to filter lessons by (e.g., 'lesson', 'course').
|
|
110
110
|
* @param {FetchInstructorLessonsOptions} options - Parameters for pagination, filtering and sorting.
|
|
111
111
|
* @param {string} [options.sortOrder="-published_on"] - The field to sort the lessons by.
|
|
112
112
|
* @param {string} [options.searchTerm=""] - The search term to filter content by title.
|
|
@@ -123,6 +123,7 @@ export interface InstructorLessons {
|
|
|
123
123
|
export async function fetchInstructorLessons(
|
|
124
124
|
slug: string,
|
|
125
125
|
brand: Brands | string,
|
|
126
|
+
contentType?: string,
|
|
126
127
|
{
|
|
127
128
|
sort = '-published_on',
|
|
128
129
|
searchTerm = '',
|
|
@@ -147,7 +148,7 @@ export async function fetchInstructorLessons(
|
|
|
147
148
|
.and(restrictions)
|
|
148
149
|
.order(sort)
|
|
149
150
|
.slice(offset, limit)
|
|
150
|
-
.select(
|
|
151
|
+
.select((await getFieldsForContentTypeWithFilteredChildren(contentType, true)) as string)
|
|
151
152
|
.build()
|
|
152
153
|
|
|
153
154
|
const total = query().and(restrictions).build()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/services/content.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -23,8 +23,26 @@ export interface CreatePostParams {
|
|
|
23
23
|
* @throws {HttpError} - If the request fails.
|
|
24
24
|
*/
|
|
25
25
|
export async function createPost(threadId: number, params: CreatePostParams): Promise<ForumPost> {
|
|
26
|
+
const { generateForumPostUrl } = await import('../urlBuilder.ts')
|
|
27
|
+
const { fetchThread } = await import('./threads.ts')
|
|
28
|
+
|
|
29
|
+
// Fetch thread to get category_id for URL generation
|
|
30
|
+
const thread = await fetchThread(threadId, params.brand)
|
|
31
|
+
|
|
32
|
+
// Generate forum post URL
|
|
33
|
+
const contentUrl = generateForumPostUrl({
|
|
34
|
+
brand: params.brand,
|
|
35
|
+
thread: {
|
|
36
|
+
category_id: thread.category_id,
|
|
37
|
+
id: threadId
|
|
38
|
+
}
|
|
39
|
+
}, false)
|
|
40
|
+
|
|
26
41
|
const httpClient = new HttpClient(globalConfig.baseUrl)
|
|
27
|
-
return httpClient.post<ForumPost>(`${baseUrl}/v1/threads/${threadId}/posts`,
|
|
42
|
+
return httpClient.post<ForumPost>(`${baseUrl}/v1/threads/${threadId}/posts`, {
|
|
43
|
+
...params,
|
|
44
|
+
content_url: contentUrl
|
|
45
|
+
})
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
/**
|
|
@@ -40,6 +58,19 @@ export async function updatePost(postId: number, params: CreatePostParams): Prom
|
|
|
40
58
|
return httpClient.put<ForumPost>(`${baseUrl}/v1/posts/${postId}`, params)
|
|
41
59
|
}
|
|
42
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Fetches a single forum post by ID.
|
|
63
|
+
*
|
|
64
|
+
* @param {number} postId - The ID of the post to fetch.
|
|
65
|
+
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
|
|
66
|
+
* @returns {Promise<ForumPost>} - A promise that resolves to the forum post.
|
|
67
|
+
* @throws {HttpError} - If the HTTP request fails.
|
|
68
|
+
*/
|
|
69
|
+
export async function fetchPost(postId: number, brand: string): Promise<ForumPost> {
|
|
70
|
+
const httpClient = new HttpClient(globalConfig.baseUrl)
|
|
71
|
+
return httpClient.get<ForumPost>(`${baseUrl}/v1/posts/${postId}?brand=${brand}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
43
74
|
export interface FetchPostParams {
|
|
44
75
|
page?: number
|
|
45
76
|
limit?: number
|
|
@@ -91,8 +122,25 @@ export async function fetchPosts(
|
|
|
91
122
|
* @throws {HttpError} - If the request fails.
|
|
92
123
|
*/
|
|
93
124
|
export async function likePost(postId: number, brand: string): Promise<void> {
|
|
125
|
+
const { generateForumPostUrl } = await import('../urlBuilder.ts')
|
|
126
|
+
|
|
127
|
+
// Fetch post to get thread info for URL generation
|
|
128
|
+
const post = await fetchPost(postId, brand)
|
|
129
|
+
|
|
130
|
+
// Generate forum post URL
|
|
131
|
+
const contentUrl = generateForumPostUrl({
|
|
132
|
+
brand,
|
|
133
|
+
thread: {
|
|
134
|
+
category_id: post.thread.category_id,
|
|
135
|
+
id: post.thread.id
|
|
136
|
+
}
|
|
137
|
+
}, false)
|
|
138
|
+
|
|
94
139
|
const httpClient = new HttpClient(globalConfig.baseUrl)
|
|
95
|
-
return httpClient.post<void>(`${baseUrl}/v1/posts/${postId}/likes`, {
|
|
140
|
+
return httpClient.post<void>(`${baseUrl}/v1/posts/${postId}/likes`, {
|
|
141
|
+
brand,
|
|
142
|
+
content_url: contentUrl
|
|
143
|
+
})
|
|
96
144
|
}
|
|
97
145
|
|
|
98
146
|
/**
|
|
@@ -89,6 +89,19 @@ export async function markThreadAsRead(threadId: number, brand: string): Promise
|
|
|
89
89
|
return httpClient.put<void>(`${baseUrl}/v1/threads/${threadId}/read?brand=${brand}`, {})
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Fetches a single forum thread by ID.
|
|
94
|
+
*
|
|
95
|
+
* @param {number} threadId - The ID of the thread to fetch.
|
|
96
|
+
* @param {string} brand - The brand context (e.g., "drumeo", "singeo").
|
|
97
|
+
* @returns {Promise<ForumThread>} - A promise that resolves to the forum thread.
|
|
98
|
+
* @throws {HttpError} - If the HTTP request fails.
|
|
99
|
+
*/
|
|
100
|
+
export async function fetchThread(threadId: number, brand: string): Promise<ForumThread> {
|
|
101
|
+
const httpClient = new HttpClient(globalConfig.baseUrl)
|
|
102
|
+
return httpClient.get<ForumThread>(`${baseUrl}/v1/threads/${threadId}?brand=${brand}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
92
105
|
export interface FetchThreadParams {
|
|
93
106
|
is_followed?: boolean,
|
|
94
107
|
page?: number,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -249,8 +249,38 @@ export async function restoreComment(commentId) {
|
|
|
249
249
|
* @returns {Promise<*|null>}
|
|
250
250
|
*/
|
|
251
251
|
export async function replyToComment(commentId, comment) {
|
|
252
|
+
const { generateCommentUrl } = await import('./urlBuilder.ts')
|
|
253
|
+
const { fetchByRailContentIds } = await import('./sanity.js')
|
|
254
|
+
|
|
255
|
+
// Fetch parent comment to get content info
|
|
256
|
+
const parentComment = await fetchComment(commentId)
|
|
257
|
+
|
|
258
|
+
if (!parentComment?.content) {
|
|
259
|
+
const url = `/api/content/v1/comments/${commentId}/reply`
|
|
260
|
+
return await POST(url, { comment })
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Fetch content from Sanity to get parentId and correct type
|
|
264
|
+
const contents = await fetchByRailContentIds([parentComment.content.id])
|
|
265
|
+
const content = contents?.[0]
|
|
266
|
+
|
|
267
|
+
// Generate content URL
|
|
268
|
+
const contentUrl = content ? generateCommentUrl({
|
|
269
|
+
id: commentId,
|
|
270
|
+
content: {
|
|
271
|
+
id: content.id,
|
|
272
|
+
type: content.type,
|
|
273
|
+
parentId: content.parentId || content.parent_id,
|
|
274
|
+
brand: content.brand
|
|
275
|
+
}
|
|
276
|
+
}, false) : null
|
|
277
|
+
|
|
278
|
+
const data = {
|
|
279
|
+
comment: comment,
|
|
280
|
+
...(contentUrl && { content_url: contentUrl })
|
|
281
|
+
}
|
|
252
282
|
const url = `/api/content/v1/comments/${commentId}/reply`
|
|
253
|
-
return await POST(url,
|
|
283
|
+
return await POST(url, data)
|
|
254
284
|
}
|
|
255
285
|
|
|
256
286
|
/**
|
|
@@ -259,8 +289,28 @@ export async function replyToComment(commentId, comment) {
|
|
|
259
289
|
* @returns {Promise<*|null>}
|
|
260
290
|
*/
|
|
261
291
|
export async function createComment(railcontentId, comment) {
|
|
292
|
+
const { generateContentUrl } = await import('./urlBuilder.ts')
|
|
293
|
+
const { fetchByRailContentIds } = await import('./sanity.js')
|
|
294
|
+
|
|
295
|
+
// Fetch content to get type and brand info
|
|
296
|
+
const contents = await fetchByRailContentIds([railcontentId])
|
|
297
|
+
const content = contents?.[0]
|
|
298
|
+
|
|
299
|
+
// Generate content URL
|
|
300
|
+
const contentUrl = content ? generateContentUrl({
|
|
301
|
+
id: content.id,
|
|
302
|
+
type: content.type,
|
|
303
|
+
parentId: content.parentId || content.parent_id,
|
|
304
|
+
brand: content.brand
|
|
305
|
+
}) : null
|
|
306
|
+
|
|
307
|
+
const data = {
|
|
308
|
+
comment: comment,
|
|
309
|
+
content_id: railcontentId,
|
|
310
|
+
...(contentUrl && { content_url: contentUrl })
|
|
311
|
+
}
|
|
262
312
|
const url = `/api/content/v1/comments/store`
|
|
263
|
-
return await POST(url,
|
|
313
|
+
return await POST(url, data)
|
|
264
314
|
}
|
|
265
315
|
|
|
266
316
|
/**
|
|
@@ -286,8 +336,35 @@ export async function unassignModeratorToComment(commentId) {
|
|
|
286
336
|
* @returns {Promise<*|null>}
|
|
287
337
|
*/
|
|
288
338
|
export async function likeComment(commentId) {
|
|
339
|
+
const { generateCommentUrl } = await import('./urlBuilder.ts')
|
|
340
|
+
const { fetchByRailContentIds } = await import('./sanity.js')
|
|
341
|
+
|
|
342
|
+
// Fetch comment to get content info
|
|
343
|
+
const comment = await fetchComment(commentId)
|
|
344
|
+
|
|
345
|
+
if (!comment?.content) {
|
|
346
|
+
const url = `/api/content/v1/comments/${commentId}/like`
|
|
347
|
+
return await POST(url, null)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Fetch content from Sanity to get parentId and correct type
|
|
351
|
+
const contents = await fetchByRailContentIds([comment.content.id])
|
|
352
|
+
const content = contents?.[0]
|
|
353
|
+
|
|
354
|
+
// Generate content URL
|
|
355
|
+
const contentUrl = content ? generateCommentUrl({
|
|
356
|
+
id: commentId,
|
|
357
|
+
content: {
|
|
358
|
+
id: content.id,
|
|
359
|
+
type: content.type,
|
|
360
|
+
parentId: content.parentId || content.parent_id,
|
|
361
|
+
brand: content.brand
|
|
362
|
+
}
|
|
363
|
+
}, false) : null
|
|
364
|
+
|
|
289
365
|
const url = `/api/content/v1/comments/${commentId}/like`
|
|
290
|
-
|
|
366
|
+
const data = contentUrl ? { content_url: contentUrl } : {}
|
|
367
|
+
return await POST(url, data)
|
|
291
368
|
}
|
|
292
369
|
|
|
293
370
|
/**
|
|
File without changes
|