Skip to content

Commit d1b8723

Browse files
authored
Merge pull request #6922 from christianbeeznest/GH-5074-4
Certificate: Migrate to Resource (‘user_certificate’) and replace PersonalFile - refs #5074
2 parents 8bced18 + e3f051f commit d1b8723

File tree

8 files changed

+1244
-359
lines changed

8 files changed

+1244
-359
lines changed

public/main/gradebook/gradebook_display_certificate.php

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -336,43 +336,109 @@ function confirmation() {
336336
echo '<td width="30%">'.get_lang('Date').' : '.api_convert_and_format_date($valueCertificate['created_at']).'</td>';
337337
echo '<td width="20%">';
338338

339-
// Normalize and availability checks
340-
$pathRaw = isset($valueCertificate['path_certificate']) ? (string) $valueCertificate['path_certificate'] : '';
341-
$path = ltrim($pathRaw, '/'); // ensure no leading slash
342-
$hasPath = $path !== '';
343-
$hash = $hasPath ? pathinfo($path, PATHINFO_FILENAME) : '';
344-
345-
// Admin can bypass publish flag for visibility
339+
/**
340+
* Resource-first per-course certificate resolution.
341+
* - First: try to resolve a Resource certificate for (cat_id, user_id).
342+
* - Never fallback to the user's general/custom certificate here.
343+
* - If no Resource exists, use legacy path_certificate (HTML/PDF in /certificates/).
344+
* - Keep publish flag behavior; platform admins bypass publish.
345+
*/
346346
$isPublished = !empty($valueCertificate['publish']) || api_is_platform_admin();
347-
$isAvailable = $hasPath && $isPublished;
348347

349-
// Build URLs only if available
350-
$htmlUrl = $isAvailable ? api_get_path(WEB_PATH).'certificates/'.$hash.'.html' : '';
351-
$pdfUrl = $isAvailable ? api_get_path(WEB_PATH).'certificates/'.$hash.'.pdf' : '';
348+
$certRepo = Container::getGradeBookCertificateRepository();
349+
$router = null;
350+
try {
351+
$router = Container::getRouter(); // Might not exist in some installs; guarded below.
352+
} catch (\Throwable $e) {
353+
// Non-fatal. We'll just skip route generation if router is not available.
354+
}
355+
356+
$htmlUrl = '';
357+
$pdfUrl = '';
358+
$isAvailable = false;
359+
360+
// Try to resolve the per-category (course/session) resource
361+
try {
362+
$entity = $certRepo->getCertificateByUserId(
363+
$categoryId === 0 ? null : (int) $categoryId,
364+
(int) $value['user_id']
365+
);
366+
367+
if ($entity && $entity->hasResourceNode()) {
368+
// HTML is served through the Resource layer (secured, hashed filename)
369+
$htmlUrl = (string) $certRepo->getResourceFileUrl($entity);
370+
$isAvailable = $isPublished && $htmlUrl !== '';
371+
372+
// PDF is served by your Symfony controller (update the route name/params if needed)
373+
if ($router && $isAvailable) {
374+
// Attempt 1: route by certificateId (common signature)
375+
try {
376+
$pdfUrl = $router->generate('gradebook_certificate_pdf', [
377+
'certificateId' => (int) $valueCertificate['id'],
378+
]);
379+
} catch (\Throwable $e1) {
380+
// Attempt 2: route by userId+catId (alternative signature)
381+
try {
382+
$pdfUrl = $router->generate('gradebook_certificate_pdf', [
383+
'userId' => (int) $value['user_id'],
384+
'catId' => (int) $categoryId,
385+
]);
386+
} catch (\Throwable $e2) {
387+
// Route not found or wrong signature: leave $pdfUrl empty.
388+
error_log('[gradebook_display_certificate] PDF route resolution failed: '.$e2->getMessage());
389+
}
390+
}
391+
}
392+
}
393+
} catch (\Throwable $e) {
394+
error_log('[gradebook_display_certificate] resource resolve error: '.$e->getMessage());
395+
}
396+
397+
// Legacy per-course fallback ONLY if no resource is available.
398+
// IMPORTANT: do NOT fallback to general/custom certificate on this screen.
399+
if (!$isAvailable) {
400+
$pathRaw = isset($valueCertificate['path_certificate']) ? (string) $valueCertificate['path_certificate'] : '';
401+
$path = ltrim($pathRaw, '/'); // normalize: remove leading slash if present
402+
$hasPath = $path !== '';
403+
$hash = $hasPath ? pathinfo($path, PATHINFO_FILENAME) : '';
404+
405+
$isAvailable = $hasPath && $isPublished;
406+
407+
if ($isAvailable) {
408+
$htmlUrl = api_get_path(WEB_PATH).'certificates/'.$hash.'.html';
409+
$pdfUrl = api_get_path(WEB_PATH).'certificates/'.$hash.'.pdf';
410+
}
411+
}
352412

353-
// HTML certificate button/link
413+
// Render buttons (enabled/disabled) preserving existing UI
354414
if ($isAvailable) {
415+
// HTML certificate button/link
355416
echo Display::url(
356417
get_lang('Certificate'),
357418
$htmlUrl,
358419
['target' => '_blank', 'class' => 'btn btn--plain']
359420
);
421+
422+
// PDF download icon/link (only if we have a URL)
423+
if (!empty($pdfUrl)) {
424+
echo Display::url(
425+
Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Download')),
426+
$pdfUrl,
427+
['target' => '_blank', 'title' => 'Download PDF certificate']
428+
);
429+
} else {
430+
// Route not available: show disabled icon with a clear tooltip
431+
echo '<button type="button" class="btn btn-link disabled" disabled '
432+
.'title="PDF route unavailable">'
433+
.Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon text-muted', null, ICON_SIZE_SMALL, get_lang('PDF route unavailable'))
434+
.'</button>';
435+
}
360436
} else {
361-
// Disabled button with clear message
437+
// Disabled HTML button
362438
echo '<button type="button" class="btn btn--plain disabled" disabled '
363439
.'title="Certificate not available"> '.get_lang('Certificate').' </button>';
364-
}
365-
echo PHP_EOL;
366440

367-
// PDF download button/link (mdi icon)
368-
if ($isAvailable) {
369-
echo Display::url(
370-
Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Download')),
371-
$pdfUrl,
372-
['target' => '_blank', 'title' => 'Download PDF certificate']
373-
);
374-
} else {
375-
// Disabled icon with tooltip
441+
// Disabled PDF icon
376442
echo '<button type="button" class="btn btn-link disabled" disabled '
377443
.'title="PDF download unavailable">'
378444
.Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon text-muted', null, ICON_SIZE_SMALL, get_lang('PDF download unavailable'))

0 commit comments

Comments
 (0)