@memberjunction/actions-bizapps-lms
Version:
LMS system integration actions for MemberJunction
285 lines • 12.3 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { RegisterClass } from '@memberjunction/global';
import { LearnWorldsBaseAction } from '../learnworlds-base.action.js';
import { BaseAction } from '@memberjunction/actions';
/**
* Action to retrieve comprehensive course details including curriculum structure
*/
let GetLearnWorldsCourseDetailsAction = class GetLearnWorldsCourseDetailsAction extends LearnWorldsBaseAction {
/**
* Metadata about this action
*/
get Description() {
return 'Retrieves comprehensive details about a specific LearnWorlds course including curriculum structure';
}
/**
* Typed public method for direct (non-framework) callers.
* Sets company context, fetches course details, and returns a strongly-typed result.
* Throws on error.
*/
async GetCourseDetails(params, contextUser) {
this.SetCompanyContext(params.CompanyID);
const { CourseID: courseId, IncludeModules: includeModules = true, IncludeInstructors: includeInstructors = true, IncludeStats: includeStats = true, } = params;
if (!courseId) {
throw new Error('CourseID is required');
}
this.validatePathSegment(courseId, 'CourseID');
// Get course details — LW v2 API returns the course object directly
const course = await this.makeLearnWorldsRequest(`courses/${courseId}`, 'GET', undefined, contextUser);
if (!course || !course.id) {
throw new Error('Failed to retrieve course details');
}
const courseDetails = this.buildCourseDetails(course);
if (includeModules) {
await this.attachModules(courseId, courseDetails, contextUser);
}
if (includeInstructors) {
await this.attachInstructors(courseId, courseDetails, contextUser);
}
if (includeStats) {
await this.attachStats(courseId, courseDetails, contextUser);
}
const summary = this.buildCourseSummary(courseDetails);
return {
CourseDetails: courseDetails,
Summary: summary,
};
}
/**
* Framework entry-point – thin wrapper around the typed public method.
*/
async InternalRunAction(params) {
const { Params, ContextUser } = params;
this.params = Params;
try {
const typedParams = this.extractGetCourseDetailsParams(Params);
const result = await this.GetCourseDetails(typedParams, ContextUser);
this.setOutputParam(Params, 'CourseDetails', result.CourseDetails);
this.setOutputParam(Params, 'Summary', result.Summary);
return this.buildSuccessResult('Course details retrieved successfully', Params);
}
catch (error) {
const msg = error instanceof Error ? error.message : 'Unknown error occurred';
return this.buildErrorResult('ERROR', `Error retrieving course details: ${msg}`, Params);
}
}
/**
* Extract typed params from framework ActionParam[]
*/
extractGetCourseDetailsParams(params) {
return {
CompanyID: this.getRequiredStringParam(params, 'CompanyID'),
CourseID: this.getRequiredStringParam(params, 'CourseID'),
IncludeModules: this.getOptionalBooleanParam(params, 'IncludeModules', true),
IncludeInstructors: this.getOptionalBooleanParam(params, 'IncludeInstructors', true),
IncludeStats: this.getOptionalBooleanParam(params, 'IncludeStats', true),
};
}
/**
* Build the base course details from raw API data
*/
buildCourseDetails(course) {
return {
id: course.id,
title: course.title,
slug: course.slug,
description: course.description || undefined,
shortDescription: course.short_description,
status: course.access || 'published',
price: course.final_price ?? course.original_price ?? 0,
originalPrice: course.original_price,
currency: course.currency || 'USD',
level: course.level || 'all',
language: course.language || 'en',
duration: course.duration,
durationText: this.formatDuration(course.duration || 0),
totalEnrollments: course.total_enrollments || 0,
averageRating: course.average_rating,
totalRatings: course.total_ratings || 0,
tags: course.tags || [],
categories: course.categories || [],
imageUrl: course.courseImage || course.image_url || undefined,
videoUrl: course.video_url,
certificateEnabled: course.certificate_enabled || false,
createdAt: course.created ? String(course.created) : course.created_at,
updatedAt: course.modified ? String(course.modified) : course.updated_at,
publishedAt: course.published_at,
};
}
/**
* Fetch and attach modules/curriculum to course details
*/
async attachModules(courseId, courseDetails, contextUser) {
try {
const modulesResponse = await this.makeLearnWorldsRequest(`courses/${courseId}/sections`, 'GET', undefined, contextUser);
const rawModules = modulesResponse.data
? (Array.isArray(modulesResponse.data) ? modulesResponse.data : modulesResponse.data.data || [])
: [];
if (rawModules.length > 0) {
courseDetails.modules = this.formatModules(rawModules);
courseDetails.totalModules = courseDetails.modules.length;
courseDetails.totalLessons = courseDetails.modules.reduce((sum, mod) => sum + (mod.lessons?.length || 0), 0);
}
}
catch (error) {
console.warn(`Sections endpoint unavailable for course ${courseId}:`, error instanceof Error ? error.message : error);
}
}
/**
* Fetch and attach instructors to course details
*/
async attachInstructors(courseId, courseDetails, contextUser) {
try {
const instructorsResponse = await this.makeLearnWorldsRequest(`courses/${courseId}/instructors`, 'GET', undefined, contextUser);
const rawInstructors = instructorsResponse.data
? (Array.isArray(instructorsResponse.data) ? instructorsResponse.data : instructorsResponse.data.data || [])
: [];
if (rawInstructors.length > 0) {
courseDetails.instructors = this.formatInstructors(rawInstructors);
}
}
catch (error) {
console.warn(`Instructors endpoint unavailable for course ${courseId}:`, error instanceof Error ? error.message : error);
}
}
/**
* Fetch and attach stats to course details
*/
async attachStats(courseId, courseDetails, contextUser) {
try {
const statsResponse = await this.makeLearnWorldsRequest(`courses/${courseId}/stats`, 'GET', undefined, contextUser);
if (statsResponse.data) {
const statsData = statsResponse.data;
courseDetails.stats = {
totalEnrollments: statsData.total_enrollments || courseDetails.totalEnrollments,
activeStudents: statsData.active_students || 0,
completionRate: statsData.completion_rate || 0,
averageProgressPercentage: statsData.average_progress || 0,
averageTimeToComplete: statsData.average_time_to_complete,
totalRevenue: statsData.total_revenue || 0,
};
}
}
catch (error) {
console.warn(`Stats endpoint unavailable for course ${courseId}:`, error instanceof Error ? error.message : error);
}
}
/**
* Format course modules/sections data
*/
formatModules(modules) {
return modules
.map((module) => ({
id: module.id,
title: module.title,
description: module.description,
order: module.order || module.position || 0,
duration: module.duration,
durationText: this.formatDuration(module.duration || 0),
totalLessons: module.total_lessons || module.lessons?.length || 0,
lessons: this.formatLessons(module.lessons || []),
}))
.sort((a, b) => a.order - b.order);
}
/**
* Format lesson data within a module
*/
formatLessons(lessons) {
return lessons.map((lesson) => ({
id: lesson.id,
title: lesson.title,
type: lesson.type || 'video',
duration: lesson.duration,
durationText: this.formatDuration(lesson.duration || 0),
order: lesson.order || lesson.position || 0,
isFree: lesson.is_free || false,
hasVideo: lesson.has_video || false,
hasQuiz: lesson.has_quiz || false,
hasAssignment: lesson.has_assignment || false,
}));
}
/**
* Format instructor data
*/
formatInstructors(instructors) {
return instructors.map((instructor) => ({
id: instructor.id,
name: instructor.name || `${instructor.first_name || ''} ${instructor.last_name || ''}`.trim(),
email: instructor.email,
bio: instructor.bio,
title: instructor.title,
imageUrl: instructor.image_url || instructor.avatar_url,
totalCourses: instructor.total_courses || 0,
totalStudents: instructor.total_students || 0,
averageRating: instructor.average_rating || 0,
}));
}
/**
* Build a summary from the course details
*/
buildCourseSummary(courseDetails) {
return {
courseId: courseDetails.id,
title: courseDetails.title,
status: courseDetails.status,
level: courseDetails.level,
duration: courseDetails.durationText,
totalModules: courseDetails.totalModules || 0,
totalLessons: courseDetails.totalLessons || 0,
totalEnrollments: courseDetails.totalEnrollments,
averageRating: courseDetails.averageRating || 0,
certificateEnabled: courseDetails.certificateEnabled,
price: courseDetails.price,
currency: courseDetails.currency,
};
}
/**
* Define the parameters this action expects
*/
get Params() {
const baseParams = this.getCommonLMSParams();
const specificParams = [
{
Name: 'CourseID',
Type: 'Input',
Value: null,
},
{
Name: 'IncludeModules',
Type: 'Input',
Value: true,
},
{
Name: 'IncludeInstructors',
Type: 'Input',
Value: true,
},
{
Name: 'IncludeStats',
Type: 'Input',
Value: true,
},
{
Name: 'CourseDetails',
Type: 'Output',
Value: null,
},
{
Name: 'Summary',
Type: 'Output',
Value: null,
},
];
return [...baseParams, ...specificParams];
}
};
GetLearnWorldsCourseDetailsAction = __decorate([
RegisterClass(BaseAction, 'GetLearnWorldsCourseDetailsAction')
], GetLearnWorldsCourseDetailsAction);
export { GetLearnWorldsCourseDetailsAction };
//# sourceMappingURL=get-course-details.action.js.map