getcert-backend / api /v2 /_services /certificatePublicSystem.ts
ggop213's picture
feat: add free starter courses, Google OAuth integration, and resilient profile sync
6f30bfd
Raw History Blame Contribute Delete
9.21 kB
import { getSupabaseAdmin } from '../_shared/supabaseAdmin.js';
import type {
CertificationTrack,
PublicCertificatePayload,
ScoreBreakdown,
ValidationSummary,
VerificationStatus,
} from '../_types.js';
type JsonRecord = Record<string, unknown>;
type CertificateRow = {
id: string;
user_id: string;
topic: string | null;
project_title: string | null;
issued_at: string;
metadata: JsonRecord | null;
};
const CANONICAL_PUBLIC_DOMAIN = 'https://getcert.eu.cc';
function baseAppUrl(): string {
const configured = (process.env.CERTIFICATE_VERIFY_BASE_URL || process.env.APP_ORIGIN || '').trim();
if (
!configured ||
configured.includes('hf.space') ||
configured.includes('huggingface.co') ||
configured.includes('vercel.app') ||
configured.includes('localhost')
) {
return CANONICAL_PUBLIC_DOMAIN;
}
return configured.replace(/\/$/, '');
}
function toStringValue(value: unknown): string | null {
if (typeof value !== 'string') {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
function toNumberValue(value: unknown): number | null {
if (typeof value === 'number' && Number.isFinite(value)) {
return value;
}
if (typeof value === 'string' && value.trim()) {
const parsed = Number(value);
if (Number.isFinite(parsed)) {
return parsed;
}
}
return null;
}
function getObject(value: unknown): JsonRecord | null {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return null;
}
return value as JsonRecord;
}
function parseScoreBreakdown(metadata: JsonRecord): ScoreBreakdown | null {
const nested = getObject(metadata.score_breakdown);
const interviewScore = toNumberValue(nested?.interview_score) ?? toNumberValue(nested?.interviewScore);
const githubValidationScore =
toNumberValue(nested?.github_validation_score) ?? toNumberValue(nested?.githubValidationScore);
const proofValidationScore =
toNumberValue(nested?.proof_validation_score) ?? toNumberValue(nested?.proofValidationScore);
const commitScore = toNumberValue(nested?.commit_score) ?? toNumberValue(nested?.commitScore);
const structureScore = toNumberValue(nested?.structure_score) ?? toNumberValue(nested?.structureScore);
const readmeScore = toNumberValue(nested?.readme_score) ?? toNumberValue(nested?.readmeScore);
if (
interviewScore === null &&
githubValidationScore === null &&
proofValidationScore === null &&
commitScore === null &&
structureScore === null &&
readmeScore === null
) {
return null;
}
return {
interviewScore: Math.round(interviewScore ?? 0),
githubValidationScore: Math.round(githubValidationScore ?? 0),
proofValidationScore: Math.round(proofValidationScore ?? 0),
commitScore: Math.round(commitScore ?? 0),
structureScore: Math.round(structureScore ?? 0),
readmeScore: Math.round(readmeScore ?? 0),
};
}
function parseValidationSummary(metadata: JsonRecord): ValidationSummary | null {
const nested = getObject(metadata.validation_summary);
if (!nested) {
return null;
}
const suspiciousSignals = Array.isArray(nested.suspicious_signals)
? nested.suspicious_signals.filter((item): item is string => typeof item === 'string')
: [];
return {
overallPassed: Boolean(nested.overall_passed),
commitPassed: Boolean(nested.commit_passed),
readmePassed: Boolean(nested.readme_passed),
proofPassed: Boolean(nested.proof_passed),
commitCount: Math.round(toNumberValue(nested.commit_count) ?? 0),
fileCount: Math.round(toNumberValue(nested.file_count) ?? 0),
meaningfulFileCount: Math.round(toNumberValue(nested.meaningful_file_count) ?? 0),
readmeRichness: Math.round(toNumberValue(nested.readme_richness) ?? 0),
suspiciousSignals,
};
}
function buildCertificateShareLinks(
skill: string | null,
verifyUrl: string
): { linkedin: string; twitter: string; whatsapp: string } {
const safeSkill = skill || 'software engineering';
const message = `I just got certified in ${safeSkill} on GetCert by building a real project and passing validation.`;
return {
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(verifyUrl)}&summary=${encodeURIComponent(message)}`,
twitter: `https://twitter.com/intent/tweet?text=${encodeURIComponent(`${message} ${verifyUrl}`)}`,
whatsapp: `https://api.whatsapp.com/send?text=${encodeURIComponent(`${message} ${verifyUrl}`)}`,
};
}
function buildInvalidPayload(certificateId: string): PublicCertificatePayload {
const appUrl = baseAppUrl();
const verifyUrl = `${appUrl}/verify/${encodeURIComponent(certificateId)}`;
const badgeUrl = `${appUrl}/api/v2/certificate/${encodeURIComponent(certificateId)}/badge`;
return {
verificationStatus: 'INVALID',
certificateId,
certificateDbId: null,
userId: null,
userName: null,
skill: null,
projectTitle: null,
githubRepoUrl: null,
liveDemoUrl: null,
finalScore: null,
scoreBreakdown: null,
projectType: null,
commitCount: null,
validationSummary: null,
issuedAt: null,
verifyUrl,
badgeUrl,
embedSnippet: `<iframe src="${verifyUrl}" title="GetCert verification" width="760" height="920" loading="lazy" style="border:0; border-radius:12px; overflow:hidden;"></iframe>`,
shareLinks: buildCertificateShareLinks(null, verifyUrl),
track: null,
};
}
function mapCertificateRow(row: CertificateRow, requestedCertificateId: string): PublicCertificatePayload {
const metadata = row.metadata || {};
const metadataCertificateId = toStringValue(metadata.certificate_id);
const certificateId = metadataCertificateId || row.id;
const appUrl = baseAppUrl();
const verifyUrl = `${appUrl}/verify/${encodeURIComponent(certificateId)}`;
const badgeUrl = `${appUrl}/api/v2/certificate/${encodeURIComponent(certificateId)}/badge`;
const scoreBreakdown = parseScoreBreakdown(metadata);
const validationSummary = parseValidationSummary(metadata);
const verificationStatus: VerificationStatus =
requestedCertificateId === row.id || requestedCertificateId === certificateId ? 'VERIFIED' : 'INVALID';
const finalScore = toNumberValue(metadata.final_score);
const commitCount =
toNumberValue(metadata.commit_count) ??
toNumberValue(validationSummary?.commitCount) ??
null;
const track = (toStringValue(metadata.certification_track) || 'verifiedcert') as CertificationTrack;
return {
verificationStatus,
certificateId,
certificateDbId: row.id,
userId: row.user_id,
userName: toStringValue(metadata.username) || toStringValue((row as any).username) || 'Student',
skill: row.topic,
projectTitle: row.project_title,
githubRepoUrl: toStringValue(metadata.github_repo_url) || toStringValue(metadata.github_url),
liveDemoUrl: toStringValue(metadata.live_demo_url) || toStringValue(metadata.proof_url),
finalScore: finalScore === null ? null : Math.round(finalScore),
scoreBreakdown,
projectType: toStringValue(metadata.project_type),
commitCount: commitCount === null ? null : Math.round(commitCount),
validationSummary,
issuedAt: row.issued_at,
verifyUrl,
badgeUrl,
embedSnippet: `<iframe src="${verifyUrl}" title="GetCert verification" width="760" height="920" loading="lazy" style="border:0; border-radius:12px; overflow:hidden;"></iframe>`,
shareLinks: buildCertificateShareLinks(row.topic, verifyUrl),
track,
};
}
function isUuid(value: string): boolean {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
}
async function getByMetadataCertificateId(
certificateId: string,
_authToken?: string | null
): Promise<CertificateRow | null> {
const supabase = getSupabaseAdmin();
const { data, error } = await supabase
.from('certificates')
.select('id, user_id, topic, project_title, issued_at, metadata')
.contains('metadata', { certificate_id: certificateId })
.maybeSingle();
if (error || !data) {
return null;
}
return data as CertificateRow;
}
async function getByDatabaseId(certificateId: string, _authToken?: string | null): Promise<CertificateRow | null> {
if (!isUuid(certificateId)) {
return null;
}
const supabase = getSupabaseAdmin();
const { data, error } = await supabase
.from('certificates')
.select('id, user_id, topic, project_title, issued_at, metadata')
.eq('id', certificateId)
.maybeSingle();
if (error || !data) {
return null;
}
return data as CertificateRow;
}
export async function getPublicCertificateById(
certificateId: string,
authToken?: string | null
): Promise<PublicCertificatePayload> {
const sanitized = certificateId.trim();
if (!sanitized) {
return buildInvalidPayload(certificateId);
}
const byMetadata = await getByMetadataCertificateId(sanitized, authToken);
if (byMetadata) {
return mapCertificateRow(byMetadata, sanitized);
}
const byId = await getByDatabaseId(sanitized, authToken);
if (byId) {
return mapCertificateRow(byId, sanitized);
}
return buildInvalidPayload(sanitized);
}