UNPKG

@memberjunction/actions-bizapps-lms

Version:

LMS system integration actions for MemberJunction

237 lines 9.74 kB
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 enroll a user in a LearnWorlds course or bundle */ let EnrollUserAction = class EnrollUserAction extends LearnWorldsBaseAction { /** * Typed public method for direct (non-framework) callers. * Supports both course and bundle enrollment via ProductType. * Throws on failure. */ async EnrollUser(params, contextUser) { this.SetCompanyContext(params.CompanyID); if (!params.UserID) { throw new Error('UserID is required'); } if (!params.CourseID) { throw new Error('CourseID is required'); } this.validatePathSegment(params.UserID, 'UserID'); this.validatePathSegment(params.CourseID, 'CourseID'); const price = params.Price ?? 0; const justification = params.Justification || 'API Enrollment'; const notifyUser = params.NotifyUser !== false; const productType = params.ProductType || 'course'; // Build enrollment body and choose endpoint based on product type const { endpoint, enrollmentData } = this.buildEnrollmentRequest(params.UserID, params.CourseID, productType, price, justification, notifyUser); // Create enrollment const enrollmentResponse = await this.makeLearnWorldsRequest(endpoint, 'POST', enrollmentData, contextUser); if (enrollmentResponse.success === false) { throw new Error(enrollmentResponse.message || 'Failed to enroll user'); } const enrollment = enrollmentResponse.data; // Format enrollment details const enrollmentDetails = this.buildEnrollmentDetails(enrollment, params.UserID, params.CourseID, price); // Fetch course title and user name in parallel for the summary const [courseTitle, userName] = await Promise.all([ this.fetchCourseTitle(params.CourseID, contextUser), this.fetchUserName(params.UserID, contextUser), ]); // Create summary const summary = { enrollmentId: enrollmentDetails.id, userId: params.UserID, userName: userName, courseId: params.CourseID, courseTitle: courseTitle, enrolledAt: enrollmentDetails.enrolledAt, status: enrollmentDetails.status, price: enrollmentDetails.price, notificationSent: notifyUser, }; return { EnrollmentDetails: enrollmentDetails, Summary: summary, }; } /** * Framework entry point -- delegates to the typed public method. */ async InternalRunAction(params) { const { Params, ContextUser } = params; this.params = Params; try { const typedParams = this.extractEnrollUserParams(Params); const result = await this.EnrollUser(typedParams, ContextUser); this.setOutputParam(Params, 'EnrollmentDetails', result.EnrollmentDetails); this.setOutputParam(Params, 'Summary', result.Summary); return this.buildSuccessResult(`Successfully enrolled user ${result.Summary.userName} in course ${result.Summary.courseTitle}`, Params); } catch (error) { const msg = error instanceof Error ? error.message : 'Unknown error'; return this.buildErrorResult('ERROR', `Error enrolling user: ${msg}`, Params); } } /** * Extract typed params from the generic ActionParam array */ extractEnrollUserParams(params) { return { CompanyID: this.getRequiredStringParam(params, 'CompanyID'), UserID: this.getRequiredStringParam(params, 'UserID'), CourseID: this.getRequiredStringParam(params, 'CourseID'), ProductType: (this.getOptionalStringParam(params, 'ProductType') || 'course'), Price: this.getOptionalNumberParam(params, 'Price', 0), Justification: this.getOptionalStringParam(params, 'Justification') || 'API Enrollment', NotifyUser: this.getOptionalBooleanParam(params, 'NotifyUser', true), StartDate: this.getOptionalStringParam(params, 'StartDate'), ExpiryDate: this.getOptionalStringParam(params, 'ExpiryDate'), }; } /** * Build the endpoint and body for enrollment (unified endpoint per LW v2 API). */ buildEnrollmentRequest(userId, courseId, productType, price, justification, notifyUser) { return { endpoint: `users/${userId}/enrollment`, enrollmentData: { productId: courseId, productType, justification, price, send_enrollment_email: notifyUser, }, }; } /** * Map the raw enrollment response data to our typed LearnWorldsEnrollment shape. */ buildEnrollmentDetails(enrollment, userId, courseId, price) { return { id: enrollment?.id || '', userId: enrollment?.user_id || userId, courseId: enrollment?.course_id || courseId, enrolledAt: enrollment?.enrolled_at || enrollment?.created_at || new Date().toISOString(), startsAt: enrollment?.starts_at, expiresAt: enrollment?.expires_at, status: enrollment?.status || 'active', price: enrollment?.price ?? price, progress: { percentage: enrollment?.progress_percentage || 0, completedUnits: enrollment?.completed_units || 0, totalUnits: enrollment?.total_units || 0, lastAccessedAt: enrollment?.last_accessed_at, }, certificateEligible: enrollment?.certificate_eligible || false, certificateIssuedAt: enrollment?.certificate_issued_at, }; } /** * Try to fetch the course title for the summary. Falls back to a default. */ async fetchCourseTitle(courseId, contextUser) { try { const courseResponse = await this.makeLearnWorldsRequest(`courses/${courseId}`, 'GET', null, contextUser); if (courseResponse.success !== false && courseResponse.data) { return courseResponse.data.title || 'Unknown Course'; } } catch (error) { console.warn(`Failed to fetch course title for ${courseId}:`, error instanceof Error ? error.message : error); } return 'Unknown Course'; } /** * Try to fetch the user display name for the summary. Falls back to a default. */ async fetchUserName(userId, contextUser) { try { const userResponse = await this.makeLearnWorldsRequest(`users/${userId}`, 'GET', null, contextUser); if (userResponse.success !== false && userResponse.data) { return userResponse.data.email || userResponse.data.username || 'Unknown User'; } } catch (error) { console.warn(`Failed to fetch user name for ${userId}:`, error instanceof Error ? error.message : error); } return 'Unknown User'; } /** * Define the parameters this action expects */ get Params() { const baseParams = this.getCommonLMSParams(); const specificParams = [ { Name: 'UserID', Type: 'Input', Value: null, }, { Name: 'CourseID', Type: 'Input', Value: null, }, { Name: 'ProductType', Type: 'Input', Value: 'course', }, { Name: 'Price', Type: 'Input', Value: 0, }, { Name: 'Justification', Type: 'Input', Value: 'API Enrollment', }, { Name: 'NotifyUser', Type: 'Input', Value: true, }, { Name: 'StartDate', Type: 'Input', Value: null, }, { Name: 'ExpiryDate', Type: 'Input', Value: null, }, { Name: 'EnrollmentDetails', Type: 'Output', Value: null, }, { Name: 'Summary', Type: 'Output', Value: null, }, ]; return [...baseParams, ...specificParams]; } /** * Metadata about this action */ get Description() { return 'Enrolls a user in a LearnWorlds course or bundle with optional pricing and notification settings'; } }; EnrollUserAction = __decorate([ RegisterClass(BaseAction, 'EnrollUserAction') ], EnrollUserAction); export { EnrollUserAction }; //# sourceMappingURL=enroll-user.action.js.map