@memberjunction/actions-bizapps-lms
Version:
LMS system integration actions for MemberJunction
333 lines (304 loc) • 12.7 kB
text/typescript
import { RegisterClass } from '@memberjunction/global';
import { LearnWorldsBaseAction } from '../learnworlds-base.action';
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
import { BaseAction } from '@memberjunction/actions';
/**
* Action to retrieve certificates earned by users in LearnWorlds
*/
(BaseAction, 'GetCertificatesAction')
export class GetCertificatesAction extends LearnWorldsBaseAction {
/**
* Get certificates for a user or course
*/
public async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
const { Params, ContextUser } = params;
this.params = Params;
try {
// Extract and validate parameters
const userId = this.getParamValue(Params, 'UserID');
const courseId = this.getParamValue(Params, 'CourseID');
const dateFrom = this.getParamValue(Params, 'DateFrom');
const dateTo = this.getParamValue(Params, 'DateTo');
const includeDownloadLinks = this.getParamValue(Params, 'IncludeDownloadLinks') !== false;
const sortBy = this.getParamValue(Params, 'SortBy') || 'issued_at';
const sortOrder = this.getParamValue(Params, 'SortOrder') || 'desc';
const maxResults = this.getParamValue(Params, 'MaxResults') || 100;
// Require either userId or courseId
if (!userId && !courseId) {
return {
Success: false,
ResultCode: 'VALIDATION_ERROR',
Message: 'Either UserID or CourseID is required',
Params
};
}
// Build query parameters
const queryParams: any = {
limit: Math.min(maxResults, 100),
sort: sortBy,
order: sortOrder
};
if (dateFrom) {
queryParams.issued_after = new Date(dateFrom).toISOString();
}
if (dateTo) {
queryParams.issued_before = new Date(dateTo).toISOString();
}
// Determine endpoint based on parameters
let endpoint = '/certificates';
if (userId && courseId) {
// Get specific certificate for user/course combination
endpoint = `/users/${userId}/courses/${courseId}/certificate`;
} else if (userId) {
// Get all certificates for a user
endpoint = `/users/${userId}/certificates`;
} else if (courseId) {
// Get all certificates issued for a course
endpoint = `/courses/${courseId}/certificates`;
}
// Build query string
const queryString = Object.keys(queryParams).length > 0
? '?' + new URLSearchParams(queryParams).toString()
: '';
// Get certificates
const certificatesResponse = await this.makeLearnWorldsRequest(
endpoint + queryString,
'GET',
null,
ContextUser
);
if (!certificatesResponse.success) {
return {
Success: false,
ResultCode: 'API_ERROR',
Message: certificatesResponse.message || 'Failed to retrieve certificates',
Params
};
}
// Handle single certificate vs array
const rawData = certificatesResponse.data;
const certificatesArray = Array.isArray(rawData)
? rawData
: (rawData?.data || (rawData?.id ? [rawData] : []));
const formattedCertificates: any[] = [];
// Process each certificate
for (const cert of certificatesArray) {
const formattedCert: any = {
id: cert.id || cert.certificate_id,
userId: cert.user_id || userId,
courseId: cert.course_id || courseId,
certificateNumber: cert.certificate_number || cert.number,
issuedAt: cert.issued_at || cert.created_at,
expiresAt: cert.expires_at,
status: cert.status || 'active',
grade: cert.grade,
score: cert.score,
completionPercentage: cert.completion_percentage || 100
};
// Add user info if available
if (cert.user) {
formattedCert.user = {
id: cert.user.id || cert.user_id,
email: cert.user.email,
name: cert.user.name || `${cert.user.first_name || ''} ${cert.user.last_name || ''}`.trim()
};
} else if (!userId && cert.user_id) {
// Try to get user info
const userResponse = await this.makeLearnWorldsRequest(
`/users/${cert.user_id}`,
'GET',
null,
ContextUser
);
if (userResponse.success && userResponse.data) {
const user = userResponse.data;
formattedCert.user = {
id: user.id,
email: user.email,
name: `${user.first_name || ''} ${user.last_name || ''}`.trim() || user.username
};
}
}
// Add course info if available
if (cert.course) {
formattedCert.course = {
id: cert.course.id || cert.course_id,
title: cert.course.title,
duration: cert.course.duration
};
} else if (!courseId && cert.course_id) {
// Try to get course info
const courseResponse = await this.makeLearnWorldsRequest(
`/courses/${cert.course_id}`,
'GET',
null,
ContextUser
);
if (courseResponse.success && courseResponse.data) {
const course = courseResponse.data;
formattedCert.course = {
id: course.id,
title: course.title,
duration: course.duration
};
}
}
// Add download links if requested
if (includeDownloadLinks) {
formattedCert.downloadLinks = {
pdf: cert.pdf_url || cert.download_url,
image: cert.image_url,
publicUrl: cert.public_url || cert.certificate_url
};
}
// Add verification info
formattedCert.verification = {
url: cert.verification_url,
code: cert.verification_code,
qrCode: cert.qr_code_url
};
formattedCertificates.push(formattedCert);
}
// Calculate summary statistics
const totalCertificates = formattedCertificates.length;
const activeCertificates = formattedCertificates.filter(c =>
c.status === 'active' && (!c.expiresAt || new Date(c.expiresAt) > new Date())
).length;
const expiredCertificates = formattedCertificates.filter(c =>
c.expiresAt && new Date(c.expiresAt) <= new Date()
).length;
// Group by course if getting user certificates
const certificatesByCourse: any = {};
if (userId && !courseId) {
formattedCertificates.forEach(cert => {
const courseTitle = cert.course?.title || 'Unknown Course';
if (!certificatesByCourse[courseTitle]) {
certificatesByCourse[courseTitle] = [];
}
certificatesByCourse[courseTitle].push(cert);
});
}
// Group by user if getting course certificates
const certificatesByUser: any = {};
if (courseId && !userId) {
formattedCertificates.forEach(cert => {
const userName = cert.user?.name || cert.user?.email || 'Unknown User';
if (!certificatesByUser[userName]) {
certificatesByUser[userName] = [];
}
certificatesByUser[userName].push(cert);
});
}
// Create summary
const summary = {
totalCertificates: totalCertificates,
activeCertificates: activeCertificates,
expiredCertificates: expiredCertificates,
dateRange: {
from: dateFrom || 'all-time',
to: dateTo || 'current'
},
filterType: userId && courseId ? 'user-course' : (userId ? 'user' : 'course'),
groupedData: userId && !courseId ? certificatesByCourse : (courseId && !userId ? certificatesByUser : null)
};
// Update output parameters
const outputParams = [...Params];
const certificatesParam = outputParams.find(p => p.Name === 'Certificates');
if (certificatesParam) {
certificatesParam.Value = formattedCertificates;
}
const totalCountParam = outputParams.find(p => p.Name === 'TotalCount');
if (totalCountParam) {
totalCountParam.Value = totalCertificates;
}
const summaryParam = outputParams.find(p => p.Name === 'Summary');
if (summaryParam) {
summaryParam.Value = summary;
}
return {
Success: true,
ResultCode: 'SUCCESS',
Message: `Retrieved ${totalCertificates} certificate(s)`,
Params: outputParams
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
return {
Success: false,
ResultCode: 'EXECUTION_ERROR',
Message: `Error retrieving certificates: ${errorMessage}`,
Params
};
}
}
/**
* Define the parameters this action expects
*/
public get Params(): ActionParam[] {
const baseParams = this.getCommonLMSParams();
const specificParams: ActionParam[] = [
{
Name: 'UserID',
Type: 'Input',
Value: null
},
{
Name: 'CourseID',
Type: 'Input',
Value: null
},
{
Name: 'DateFrom',
Type: 'Input',
Value: null
},
{
Name: 'DateTo',
Type: 'Input',
Value: null
},
{
Name: 'IncludeDownloadLinks',
Type: 'Input',
Value: true
},
{
Name: 'SortBy',
Type: 'Input',
Value: 'issued_at'
},
{
Name: 'SortOrder',
Type: 'Input',
Value: 'desc'
},
{
Name: 'MaxResults',
Type: 'Input',
Value: 100
},
{
Name: 'Certificates',
Type: 'Output',
Value: null
},
{
Name: 'TotalCount',
Type: 'Output',
Value: null
},
{
Name: 'Summary',
Type: 'Output',
Value: null
}
];
return [...baseParams, ...specificParams];
}
/**
* Metadata about this action
*/
public get Description(): string {
return 'Retrieves certificates earned by users in LearnWorlds courses with download links and verification info';
}
}