UNPKG

@memberjunction/actions-bizapps-lms

Version:

LMS system integration actions for MemberJunction

209 lines 10.7 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 update a user's course progress in LearnWorlds */ let UpdateUserProgressAction = class UpdateUserProgressAction extends LearnWorldsBaseAction { // ---------------------------------------------------------------- // Typed public method – can be called directly from code // ---------------------------------------------------------------- /** * Update user progress for a course or lesson. * Throws on any error. */ async UpdateProgress(params, contextUser) { this.SetCompanyContext(params.CompanyID); const { UserID, CourseID, LessonID, ProgressPercentage, Completed, TimeSpent, Score, Notes } = params; // Validate required fields if (!UserID) { throw new Error('UserID is required'); } if (!CourseID) { throw new Error('CourseID is required'); } this.validatePathSegment(UserID, 'UserID'); this.validatePathSegment(CourseID, 'CourseID'); if (LessonID) { this.validatePathSegment(LessonID, 'LessonID'); } if (ProgressPercentage !== undefined && (ProgressPercentage < 0 || ProgressPercentage > 100)) { throw new Error('ProgressPercentage must be between 0 and 100'); } // Get current enrollment first const currentEnrollment = await this.fetchCurrentEnrollment(UserID, CourseID, contextUser); const updateResult = {}; // Update lesson progress if lessonId is provided if (LessonID) { updateResult.lessonProgress = await this.updateLessonProgress(UserID, CourseID, LessonID, { Completed, ProgressPercentage, TimeSpent, Score, Notes }, contextUser); } // Update overall course progress if progressPercentage is provided at course level if (ProgressPercentage !== undefined && !LessonID) { updateResult.courseProgress = await this.updateCourseProgress(UserID, CourseID, currentEnrollment, { Completed, ProgressPercentage, TimeSpent }, contextUser); } // Get updated enrollment details const updatedProgress = await this.fetchUpdatedEnrollment(UserID, CourseID, currentEnrollment, contextUser); // Build typed result const updateType = LessonID ? 'lesson' : 'course'; const progressDetails = this.buildProgressDetails(UserID, CourseID, LessonID, currentEnrollment, updatedProgress, updateType, updateResult); const summary = this.buildProgressSummary(UserID, CourseID, LessonID, currentEnrollment, updatedProgress, TimeSpent, updateType); return { ProgressDetails: progressDetails, Summary: summary }; } // ---------------------------------------------------------------- // Framework wrapper – thin delegation to the public method // ---------------------------------------------------------------- async InternalRunAction(params) { const { Params, ContextUser } = params; this.params = Params; try { const typedParams = this.extractUpdateProgressParams(Params); const result = await this.UpdateProgress(typedParams, ContextUser); this.setOutputParam(Params, 'ProgressDetails', result.ProgressDetails); this.setOutputParam(Params, 'Summary', result.Summary); return this.buildSuccessResult(`Successfully updated ${result.ProgressDetails.updateType} progress`, Params); } catch (error) { const msg = error instanceof Error ? error.message : 'Unknown error'; return this.buildErrorResult('ERROR', `Error updating progress: ${msg}`, Params); } } // ---------------------------------------------------------------- // Private helpers // ---------------------------------------------------------------- extractUpdateProgressParams(params) { return { CompanyID: this.getRequiredStringParam(params, 'CompanyID'), UserID: this.getRequiredStringParam(params, 'UserID'), CourseID: this.getRequiredStringParam(params, 'CourseID'), LessonID: this.getOptionalStringParam(params, 'LessonID'), ProgressPercentage: this.getOptionalNumberParam(params, 'ProgressPercentage', undefined), Completed: this.getOptionalBooleanParam(params, 'Completed', undefined), TimeSpent: this.getOptionalNumberParam(params, 'TimeSpent', undefined), Score: this.getOptionalNumberParam(params, 'Score', undefined), Notes: this.getOptionalStringParam(params, 'Notes'), }; } async fetchCurrentEnrollment(userId, courseId, contextUser) { try { return await this.makeLearnWorldsRequest(`users/${userId}/enrollments/${courseId}`, 'GET', undefined, contextUser); } catch (error) { throw new Error('User is not enrolled in this course: ' + (error instanceof Error ? error.message : String(error))); } } async updateLessonProgress(userId, courseId, lessonId, data, contextUser) { const body = { completed: data.Completed !== undefined ? data.Completed : false, progress_percentage: data.ProgressPercentage, }; if (data.TimeSpent !== undefined) { body.time_spent = data.TimeSpent; } if (data.Score !== undefined) { body.score = data.Score; } if (data.Notes) { body.notes = data.Notes; } return await this.makeLearnWorldsRequest(`users/${userId}/courses/${courseId}/lessons/${lessonId}/progress`, 'PUT', body, contextUser); } async updateCourseProgress(userId, courseId, currentEnrollment, data, contextUser) { const body = { progress_percentage: data.ProgressPercentage, }; if (data.Completed !== undefined) { body.completed = data.Completed; } if (data.TimeSpent !== undefined) { body.total_time_spent = (currentEnrollment.total_time_spent || 0) + data.TimeSpent; } return await this.makeLearnWorldsRequest(`users/${userId}/enrollments/${courseId}/progress`, 'PUT', body, contextUser); } async fetchUpdatedEnrollment(userId, courseId, fallback, contextUser) { try { return await this.makeLearnWorldsRequest(`users/${userId}/enrollments/${courseId}`, 'GET', undefined, contextUser); } catch (error) { // If we can't get updated details, use previous enrollment console.warn('Failed to get updated enrollment details:', error); return fallback; } } buildProgressDetails(userId, courseId, lessonId, currentEnrollment, updatedProgress, updateType, updateResult) { return { userId, courseId, lessonId, previousProgress: { percentage: currentEnrollment.progress_percentage || 0, completedUnits: currentEnrollment.completed_units || 0, totalTimeSpent: currentEnrollment.total_time_spent || 0, }, updatedProgress: { percentage: updatedProgress.progress_percentage || 0, completedUnits: updatedProgress.completed_units || 0, totalUnits: updatedProgress.total_units || 0, totalTimeSpent: updatedProgress.total_time_spent || 0, totalTimeSpentText: this.formatDuration(updatedProgress.total_time_spent || 0), lastAccessedAt: updatedProgress.last_accessed_at || new Date().toISOString(), completed: updatedProgress.completed || false, completedAt: updatedProgress.completed_at, }, updateType, updateResult, }; } buildProgressSummary(userId, courseId, lessonId, currentEnrollment, updatedProgress, timeSpent, updateType) { return { userId, courseId, lessonId, progressIncreased: (updatedProgress.progress_percentage || 0) > (currentEnrollment.progress_percentage || 0), previousPercentage: currentEnrollment.progress_percentage || 0, newPercentage: updatedProgress.progress_percentage || 0, timeAdded: timeSpent || 0, totalTimeSpent: updatedProgress.total_time_spent || 0, isCompleted: updatedProgress.completed || false, updateType, }; } // ---------------------------------------------------------------- // Params & Description metadata // ---------------------------------------------------------------- /** * 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: 'LessonID', Type: 'Input', Value: null }, { Name: 'ProgressPercentage', Type: 'Input', Value: null }, { Name: 'Completed', Type: 'Input', Value: null }, { Name: 'TimeSpent', Type: 'Input', Value: null }, { Name: 'Score', Type: 'Input', Value: null }, { Name: 'Notes', Type: 'Input', Value: null }, { Name: 'ProgressDetails', Type: 'Output', Value: null }, { Name: 'Summary', Type: 'Output', Value: null }, ]; return [...baseParams, ...specificParams]; } /** * Metadata about this action */ get Description() { return "Updates a user's progress for a course or specific lesson in LearnWorlds"; } }; UpdateUserProgressAction = __decorate([ RegisterClass(BaseAction, 'UpdateUserProgressAction') ], UpdateUserProgressAction); export { UpdateUserProgressAction }; //# sourceMappingURL=update-user-progress.action.js.map