perform test

test to courses

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-06-24 12:48:51 +08:00
parent 358fecb510
commit 9b8577b79b
27 changed files with 1122 additions and 221 deletions
+18 -60
View File
@@ -11,13 +11,10 @@
***********************************************************************************************************************************************************************/
'use strict';
const R = require('../../utils/response.util');
const mdl_Users = require('../../models/users/users.mdl');
const mdl_Achievements = require('../../models/users/achievements.mdl');
const { generateCertificate } = require('../../services/certificate.service');
const { formatDuration } = require('../../utils/duration.util');
const UserNotification = require('../../models/notifications/user_notification.mdl');
const { NOTIFICATION_REGISTRY } = require('../../data/notifications.data');
const R = require('../../utils/response.util');
const mdl_Users = require('../../models/users/users.mdl');
const { generateCertificate } = require('../../services/certificate.service');
const { formatDuration } = require('../../utils/duration.util');
const {
Course,
@@ -113,17 +110,20 @@ exports.getCertificate = async (req, res) => {
const fullName = user?.personal_info?.name?.full_name?.trim() || 'Participant';
// ── 4. Resolve or create the certificate record ────────────────────────────
const [cert, created] = await Certificate.findOrCreate({
where: { user_id, course_id: course.course_id },
defaults: {
// CockroachDB does not support findOrCreate (uses temp PL/pgSQL functions).
let cert = await Certificate.findOne({ where: { user_id, course_id: course.course_id } });
if (!cert) {
cert = await Certificate.create({
user_id,
course_id: course.course_id,
cert_no: await buildCertNo(user_id),
ref_no: await buildRefNo(),
instructors: formatInstructors(course.instructors ?? []),
score: passedAttempt.score ?? null,
length_str: formatDuration(course.duration_seconds),
issued_at: passedAttempt.createdAt,
},
});
});
}
// Always use live instructors from course_instructors table for the PDF.
// Keep the snapshot in sync so it reflects the current state.
@@ -132,57 +132,15 @@ exports.getCertificate = async (req, res) => {
await cert.update({ instructors: liveInstructors });
}
// ── 5. On first issue: fire notification + achievements ────────────────────
if (created) {
// Certificate issued notification
UserNotification.create({
user_id,
...NOTIFICATION_REGISTRY.certificate_issued.build({
courseTitle: course.title,
courseUuid,
}),
}).catch(err => console.error('[CERTIFICATE] Failed to emit notification:', err));
// Per-course completion achievement
mdl_Achievements.findOrCreate({
where: { user_id, key: `course_completed_${courseUuid}` },
defaults: {
type: 'milestone',
label: 'Certificate of Completion',
description: course.title,
granted_at: passedAttempt.createdAt,
metadata: { courseTitle: course.title, courseUuid },
},
}).catch(err => console.error('[CERTIFICATE] Failed to grant course achievement:', err));
// First-course achievement (only if this is their very first certificate)
const totalCerts = await Certificate.count({ where: { user_id } });
if (totalCerts === 1) {
mdl_Achievements.findOrCreate({
where: { user_id, key: 'first_course_completed' },
defaults: {
type: 'milestone',
label: 'First Course Completed',
description: 'Completed your very first course on Philproperties.',
granted_at: passedAttempt.createdAt,
metadata: { courseTitle: course.title, courseUuid },
},
}).catch(err => console.error('[CERTIFICATE] Failed to grant first-course achievement:', err));
}
}
// ── 6. Format issued date as MM/DD/YY HH:MM AM/PM ────────────────────────
// ── 5. Format issued date as MM/DD/YY HH:MM AM/PM ───────────────────────────
const issuedDate = new Date(cert.issued_at);
const dateStr = new Intl.DateTimeFormat('en-US', {
month: '2-digit',
day: '2-digit',
year: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: true,
month: 'long',
day: 'numeric',
year: 'numeric',
}).format(issuedDate);
// ── 7. Generate PDF ────────────────────────────────────────────────────────
// ── 6. Generate PDF ────────────────────────────────────────────────────────
const pdf = await generateCertificate({
name: fullName,
course: course.title,
@@ -193,7 +151,7 @@ exports.getCertificate = async (req, res) => {
length: cert.length_str ?? '',
});
// ── 8. Stream response ─────────────────────────────────────────────────────
// ── 7. Stream response ─────────────────────────────────────────────────────
const nameParts = fullName.trim().split(/\s+/);
const lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : nameParts[0];
const firstName = nameParts.length > 1 ? nameParts.slice(0, -1).join(' ') : '';