Servicio de Gestión y Validación de Usuarios para Laab2 y LaabPro
Este servicio consta de funciones para gestionar la validación, creación y asociación de usuarios a cursos o productos, integrándose con los sistemas externos Laab2 y LaabPro.
Archivo
src/api/laab-connection/services/laab-connection.ts
Funcionalidad General del Servicio
El servicio está diseñado para:
- Validar fechas y condiciones de compra en órdenes.
- Separar nombres y apellidos de datos de usuario.
- Construir cuerpos de solicitud para APIs externas.
- Consultar productos, usuarios y órdenes en base de datos Strapi.
- Interactuar con APIs de Laab2 y LaabPro para registrar usuarios, obtener cursos y matricular usuarios en cursos.
- Generar tokens JWT para LaabPro.
- Gestionar accesos y enrolamientos de usuarios.
Laab Connection Service
Funciones comunes
Método: checkDateValidation
Valida si la fecha proporcionada ya ha pasado.
Método: checkValidations
Verifica que la fecha de inicio sea válida, que el contrato esté firmado (si aplica) y que el pago haya sido exitoso.
Método: separateNameSurnames
Separa el nombre completo en nombre y apellidos.
Método: buildBody
Construye un FormData con los datos del usuario y la compra.
Método: getProductBySKU
Obtiene un producto desde Strapi según su SKU.
Método: getLastOrderByEmailProductSKU
Busca la última orden completada por un usuario para un SKU dado.
Método: getUserByEmail
Busca un usuario en Strapi a partir del email.
Funciones Laab2
Método: checkLaab2UserExists
Comprueba si el usuario existe en la plataforma Laab2.
async checkLaab2UserExists(userData: userData) { const body = new FormData(); body.append('email', userData.email); body.append('token', process.env.LAAB_ENCRYPTED_TOKEN || ''); body.append('origen', 'AE');
const data = await laab2HttpClient.postLaab2<{ status: string; idUser?: string; }>('usuario/existeAlumno', body, {});
return data; }Método: getIdCourseByIdGroup
Obtiene el ID del curso vinculado a un grupo de Laab2.
async getIdCourseByIdGroup(groupId: string): Promise<{ status?: number; response?: { idCurso: string }; code?: string; error?: string; }> { const data = await laab2HttpClient.get<{ status: number; response: { idCurso: string }; code: string; error: string; }>(`idcursogrp/${groupId}`);
if (data.code === CODES.ko) { return { status: 400, error: data.error }; } else { return data; } }Método: checkLaab2UserCourses
Lista los cursos en los que está inscrito un usuario en Laab2.
async checkLaab2UserCourses(userId: string) { const body = new FormData(); body.append('token', process.env.LAAB_ENCRYPTED_TOKEN || ''); body.append('idLaab2', userId);
const data = await laab2HttpClient.postLaab2<{ status: number; ListaCursos: { id: string }[]; }>('getusercourses', body, {}); return data; }Método: unimedLaab2ApiCall
Realiza la llamada para inscribir al usuario en un curso de Laab2.
async unimedLaab2ApiCall( name: string, surnames: string, userData: userData, price: number, discountPercentage: number, groupId: string, sku: string, ) { const headers = { 'Content-Type': 'multipart/form-data', Authorization: `Laab-oauthtoken ${process.env.LAAB_REGISTER_TOKEN}`, }; const body = this.buildBody( name, surnames, userData, price, discountPercentage, );
const data = await laab2HttpClient.postLaab2<{ status: string; message: string; link: string; }>(`laab2/registro/3/${groupId}/${sku}/vertical`, body, headers);
return data; }Método: manageUserLaab2
Flujo completo de gestión del usuario en Laab2: comprobar existencia, registrar si es necesario y verificar acceso.
async manageUserLaab2( userData: userData, name: string, surnames: string, groupId: string, price: number, discountPercentage: number, sku: string, ) { const groupCourseData = await this.getIdCourseByIdGroup(groupId); if (groupCourseData.status === 400) return groupCourseData;
const courseId = groupCourseData.response.idCurso; const userExistsData = await this.checkLaab2UserExists(userData);
if (userExistsData.status === CODES.ok) { const userId = userExistsData.idUser; const userCourseData = await this.checkLaab2UserCourses(userId);
if (userCourseData.status !== 1002) { return { status: 500, message: ERROR_CHECKING_ASSOCIATED_COURSES }; }
const isRegistered = userCourseData.ListaCursos.some( (course) => course.id === courseId, );
if (isRegistered) { return { status: 200, access_link: `${process.env.LAAB2_URL}laab2/action/accesoAdministrativoAction.php?action=alumno&id_curso=${courseId}&id_usr=${userId}`, }; } }
const unimedResponse = await this.unimedLaab2ApiCall( name, surnames, userData, price, discountPercentage, groupId, sku, );
if (Array.isArray(unimedResponse)) { return { status: 500, message: ERROR_REGISTERING_NEW_USER }; }
return { status: 200, access_link: unimedResponse.link }; }Funciones LaabPro
Método: getRegisteredLaabproUserId
Consulta el ID de usuario en LaabPro por email.
async getRegisteredLaabproUserId( userData: userData, ): Promise<number | false> { const laabproUserData = await laabproClient.getLaabpro<{ status: number; code?: number; body?: { id: number }[]; }>('local_contentdata_get_users', [ { name: 'text', value: userData.email }, { name: 'roleid', value: '3' }, { name: 'usertoken', value: process.env.LAABPRO_USER_TOKEN }, ]);
if (laabproUserData.body.length > 0) { const userId = laabproUserData.body[0].id; return userId; } return false; }Método: createLaabproUser
Crea un nuevo usuario en LaabPro.
async createLaabproUser( userData: userData, name: string, surnames: string, ): Promise<{ status: number; code?: number; body?: { id: number } }> { const laabproSurnames = surnames || '-';
const laabproUserData = await laabproClient.getLaabpro<{ status: number; code?: number; body?: { id: number }; }>('local_servicerefactor_user_create_users', [ { name: 'firstname', value: name }, { name: 'lastname', value: laabproSurnames }, { name: 'dni', value: userData.identificationNumber }, { name: 'email', value: userData.email }, { name: 'country', value: userData.mailingAddress.country }, { name: 'city', value: 'Ciudad' }, { name: 'roleid', value: '3' }, ]);
return laabproUserData; }Método: enrolUserInCourse
Matricula al usuario en un curso LaabPro y genera un token de acceso.
async enrolUserInCourse( email: string, userId: number, courseId: number, groupId: number, vertical: string, ): Promise<{ status: number; access_link?: string; message?: string }> { const enrollmentStatus = await laabproClient.getLaabpro<{ status: number; code: number; message: string; body?: []; }>('local_servicerefactor_enrol_course_group_user', [ { name: 'userid', value: String(userId) }, { name: 'courseid', value: String(courseId) }, { name: 'groupid', value: String(groupId) }, { name: 'usertoken', value: process.env.LAABPRO_USER_TOKEN }, ]);
if (enrollmentStatus.status === 200 || enrollmentStatus.code === 6) { const studentAccessStatus = await this.laabproGenerateAccessStudent( email, vertical, );
if (studentAccessStatus.status !== 200) { return studentAccessStatus; } return { status: 200, access_link: `${process.env.LAABPRO_URL}?token=${encodeURI(btoa(studentAccessStatus.accesstoken))}`, }; } else { return { status: enrollmentStatus.status, message: enrollmentStatus.message, }; } }Método: craftLaabproJWT
Genera un JWT firmado con clave privada específica de vertical.
craftLaabproJWT(vertical: string): string { const jwt = require('jsonwebtoken'); const fileSystem = require('graceful-fs'); const verticalDirectory = VERTICALS_DIRECTORIES[vertical]; const PEMROUTE = 'keys/' + verticalDirectory + '/private.pem';
const privateKeyBuffer = fileSystem.readFileSync(PEMROUTE); const now = Math.floor(Date.now() / 1000); const expires = now + 300;
const laabproJWT = jwt.sign( { kid: process.env.LAABPRO_KID, aud: LAABPROAUD, iat: now, exp: expires, }, privateKeyBuffer, { algorithm: 'RS256', }, );
return laabproJWT; }Método: laabproGenerateAccessStudent
Usa el JWT para obtener el token de acceso para el alumno.
async laabproGenerateAccessStudent( email: string, vertical: string, ): Promise<{ status: number; message?: string; accesstoken?: string }> { const encryptedToken = encodeURI(btoa(this.craftLaabproJWT(vertical)));
const tokenStatus = await laabproClient.getLaabpro<{ status: number; code: number; message: string; body?: { accesstoken: string }; }>('local_servicerefactor_generate_access_student_external', [ { name: 'token', value: encryptedToken }, { name: 'email', value: email }, ]);
if (tokenStatus.status !== 200) { return tokenStatus; } return { status: tokenStatus.status, accesstoken: tokenStatus.body.accesstoken, }; }Método: manageUserLaabpro
Orquesta la creación o recuperación de usuario, inscripción y acceso para LaabPro.
async manageUserLaabpro( userData: userData, name: string, surnames: string, courseId: number, groupId: number, vertical: string, ): Promise<{ status: number; message?: string; access_link?: string }> { const laabproUserData = await this.createLaabproUser( userData, name, surnames, );
if (laabproUserData.status === 400) { if (laabproUserData.code === 6) { const userId = await this.getRegisteredLaabproUserId(userData); if (!userId) { return { status: laabproUserData.status, message: ERROR_TRYING_GET_USER_ID, }; } const enrollmentStatus = await this.enrolUserInCourse( userData.email, userId, courseId, groupId, vertical, ); return enrollmentStatus; } else { return { status: laabproUserData.status, message: ERROR_CREATING_USER, }; } } else { const userId = laabproUserData.body.id; const enrollmentStatus = await this.enrolUserInCourse( userData.email, userId, courseId, groupId, vertical, ); return enrollmentStatus; } }Función de gestión global
Método: manageAccessLaab2Laabpro
Decide si la gestión del acceso debe hacerse con Laab2 o LaabPro y ejecuta la lógica correspondiente.
async manageAccessLaab2Laabpro( userData: userData, name: string, surnames: string, groupId: string, price: number, discountPercentage: number, sku: string, courseId?: number, vertical?: string, ) { if (courseId) { const userStatus = await this.manageUserLaabpro( userData, name, surnames, courseId, Number(groupId), vertical, ); return userStatus; }
const userStatus = await this.manageUserLaab2( userData, name, surnames, groupId, price, discountPercentage, sku, ); return userStatus; }