diff --git a/backup/moodle2/backup_customcert_stepslib.php b/backup/moodle2/backup_customcert_stepslib.php index 01dc0f75..52d6616f 100644 --- a/backup/moodle2/backup_customcert_stepslib.php +++ b/backup/moodle2/backup_customcert_stepslib.php @@ -41,7 +41,7 @@ protected function define_structure() { // The instance. $customcert = new backup_nested_element('customcert', ['id'], [ 'templateid', 'name', 'intro', 'introformat', 'requiredtime', 'verifyany', 'emailstudents', - 'emailteachers', 'emailothers', 'protection', 'timecreated', 'timemodified']); + 'emailteachers', 'emailothers', 'protection', 'timecreated', 'timemodified', 'keeplocalcopy']); // The template. $template = new backup_nested_element('template', ['id'], [ diff --git a/classes/localfile.php b/classes/localfile.php new file mode 100644 index 00000000..e4102bd1 --- /dev/null +++ b/classes/localfile.php @@ -0,0 +1,249 @@ +. + +/** + * Class represents a local file of an issued certificate. + * + * @package mod_customcert + * @copyright 2023 Giorgio Consorti + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_customcert; + +use file_exception; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Class represents a local file of an issued certificate. + * + * @package mod_customcert + * @copyright 023 Giorgio Consorti + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class localfile { + + /** + * The template representing the content of the file. + * + * @var \mod_customcert\template + */ + protected $template; + + /** + * The component name for the file storage. + */ + const component = 'mod_customcert'; + + /** + * The filearea name for the file storage. + */ + const filearea = 'customcert_issues'; + + /** + * The constructor. + * + * @param \mod_customcert\template $template + */ + public function __construct(\mod_customcert\template $template) { + $this->template = $template; + } + + /** + * Save the PDF to the file storage. + * + * @param string $pdfcontent string content of the pdf + * @param integer|null $userid the id of the user whose certificate we want to save + * @return stored_file|false the stored_file object on success, false on error + */ + public function savePDF(string $pdfcontent, ?int $userid = null) { + global $CFG, $USER; + require_once($CFG->libdir . '/filelib.php'); + + if (empty($userid)) { + $userid = $USER->id; + } + + try { + $file = $this->getPDF($userid); + if (!$file) { + // Create file containing the pdf + $fs = get_file_storage(); + $file = $fs->create_file_from_string($this->buildFileInfo($userid), $pdfcontent); + } + return $file; + } catch (file_exception $e) { + // maybe log the exception + return false; + } + } + + /** + * Get the PDF from the file storage. + * + * @param integer|null $userid the id of the user whose certificate we want to get + * @return \stored_file|false the stored_file object on success, false on error + */ + public function getPDF(?int $userid = null) { + global $CFG, $USER; + require_once($CFG->libdir . '/filelib.php'); + + if (empty($userid)) { + $userid = $USER->id; + } + + $fileinfo = $this->buildFileInfo($userid); + $fs = get_file_storage(); + return $fs->get_file($fileinfo['contextid'], $fileinfo['component'], $fileinfo['filearea'], + $fileinfo['itemid'], $fileinfo['filepath'], $fileinfo['filename']); + } + + /** + * Delete the PDF from the file storage. + * + * @param integer|null $userid the id of the user whose certificate we want to get + * @return bool true on success + */ + public function deletePDF(?int $userid = null) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + try { + $file = $this->getPDF($userid); + if ($file) { + return $file->delete(); + } + return false; + } catch (file_exception $e) { + // maybe log the exception + return false; + } + } + + /** + * Send the PDF to the browser or return it as a string. + * + * @param int $userid the id of the user whose certificate we want to view + * @param string $deliveryoption the delivery option of the customcert + * @param bool $return Do we want to return the contents of the PDF? + * @return string|void Can return the PDF in string format if specified. + */ + public function sendPDF(?int $userid = NULL, string $deliveryoption = certificate::DELIVERY_OPTION_DOWNLOAD, bool $return = false) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + $file = $this->getPDF($userid); + if ($file) { + if ($return) { + return $file->get_content(); + } else { + // send the file to the browser + send_stored_file( + $file, + 0, + 0, + $deliveryoption == certificate::DELIVERY_OPTION_DOWNLOAD, + ['filename' => $file->get_filename()] + ); + die(); + } + } + } + + /** + * Check if a pdf exists in the file storage area. + * + * @param \stdClass $cm the course module + * @param integer|null $userid the id of the user whose PDF we want to check + * @param integer|null $templateid the template id of the customcert we want to check + * @return \stored_file|false the stored_file object on success, false on error + */ + public static function existsPDF($cm, ?int $userid = null, ?int $templateid = null) { + + $fileinfo = self::buildFileInfoArr($cm, $userid, $templateid); + $fs = get_file_storage(); + return $fs->get_file($fileinfo['contextid'], $fileinfo['component'], $fileinfo['filearea'], + $fileinfo['itemid'], $fileinfo['filepath'], $fileinfo['filename']); + } + + /** + * Build the fileinfo array needed by the file storage. + * + * @param integer|null $userid the id of the user whose fileinfo array we want to generate + * @return array the fileinfo array + */ + protected function buildFileInfo(?int $userid = null) { + + return self::buildFileInfoArr($this->template->get_cm(), $userid, $this->template->get_id()); + } + + /** + * Build the fileinfo array needed by the file storage, static version. + * + * @param \stdClass $cm the course module + * @param integer|null $userid the id of the user whose fileinfo array we want to generate + * @param integer|null $templateid the template id of the customcert of the array we want to generate + * @return array the fileinfo array + */ + private static function buildFileInfoArr ($cm, ?int $userid = null, ?int $templateid = null) { + + /** @var \moodle_database $DB */ + global $DB, $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + if (empty($templateid)) { + $customcert = $DB->get_record('customcert', array('id' => $cm->instance), '*', MUST_EXIST); + $templateid = $customcert->templateid; + } + + $course = $DB->get_record('course', ['id' => $cm->course]); + $context = $DB->get_record('context', ['contextlevel' => '50', 'instanceid' => $course->id]); + $user_info = $DB->get_record('user', ['id' => $userid]); + + return [ + 'contextid' => $context->id, + 'component' => self::component, + 'filearea' => self::filearea, + 'itemid' => $templateid, + 'userid' => $USER->id, + 'author' => fullname($USER), + 'filepath' => '/' . $course->id . '/', + 'filename' => self::buildFileName($user_info->username, $templateid, $course->shortname), + ]; + } + + /** + * Build the PDF filename. + * + * @param string $username + * @param string $templateid + * @param string $courseShortname + * @return string the PDF file name + */ + public static function buildFileName($username, $templateid, $courseShortname) { + return $username . '_cert-' . $templateid . '_course-' . $courseShortname . '.pdf'; + } +} diff --git a/classes/report_table.php b/classes/report_table.php index 40cc4ab2..df652fad 100644 --- a/classes/report_table.php +++ b/classes/report_table.php @@ -177,16 +177,42 @@ public function col_download($user) { public function col_actions($user) { global $OUTPUT; - $icon = new \pix_icon('i/delete', get_string('delete')); - $link = new \moodle_url('/mod/customcert/view.php', + $actions = [ [ - 'id' => $this->cm->id, - 'deleteissue' => $user->issueid, - 'sesskey' => sesskey() + 'icon' => new \pix_icon('i/delete', get_string('delete')), + 'link' => new \moodle_url( + '/mod/customcert/view.php', + [ + 'id' => $this->cm->id, + 'deleteissue' => $user->issueid, + 'sesskey' => sesskey() + ] + ), + 'attributes' => ['class' => 'action-icon delete-icon'], ] - ); + ]; + + if (has_capability('mod/customcert:deletelocalcopy', \context_module::instance($this->cm->id)) && localfile::existsPDF($this->cm, $user->id)) { + $actions[] = [ + 'icon' => new \pix_icon('deletelocalcopy', get_string('deletelocalcopy', 'customcert'), 'customcert'), + 'link' => new \moodle_url( + '/mod/customcert/view.php', + [ + 'id' => $this->cm->id, + 'deleteissue' => $user->issueid, + 'deletelocalcopy' => 1, + 'sesskey' => sesskey() + ] + ), + 'attributes' => ['class' => 'action-icon deletelocalcopy-icon'], + ]; + } - return $OUTPUT->action_icon($link, $icon, null, ['class' => 'action-icon delete-icon']); + return implode(" ", array_map( + fn ($action) => + $OUTPUT->action_icon($action['link'], $action['icon'], null, $action['attributes'] ?? []), + $actions + )); } /** diff --git a/classes/template.php b/classes/template.php index 444af034..5792f886 100644 --- a/classes/template.php +++ b/classes/template.php @@ -48,6 +48,11 @@ class template { */ protected $contextid; + /** + * @var \mod_customcert\localfile the local file for the template. + */ + protected $localfile; + /** * The constructor. * @@ -57,6 +62,7 @@ public function __construct($template) { $this->id = $template->id; $this->name = $template->name; $this->contextid = $template->contextid; + $this->localfile = new localfile($this); } /** @@ -314,6 +320,13 @@ public function generate_pdf(bool $preview = false, int $userid = null, bool $re $deliveryoption = $customcert->deliveryoption; } + if ($customcert->keeplocalcopy) { + $retval = $this->localfile->sendPDF($userid, $deliveryoption, $return); + if ($return && !empty($retval)) { + return $retval; + } + } + // Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename. $filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.'); @@ -362,6 +375,10 @@ public function generate_pdf(bool $preview = false, int $userid = null, bool $re } } + if ($customcert->keeplocalcopy) { + $this->localfile->savePDF($pdf->Output('', 'S'), $userid); + } + if ($return) { return $pdf->Output('', 'S'); } diff --git a/db/access.php b/db/access.php index f3f71555..78770706 100644 --- a/db/access.php +++ b/db/access.php @@ -104,6 +104,26 @@ ] ], + 'mod/customcert:managekeeplocalcopy' => [ + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/course:manageactivities' + ], + + 'mod/customcert:deletelocalcopy' => [ + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/course:manageactivities' + ], + 'mod/customcert:manageemailstudents' => [ 'captype' => 'write', 'contextlevel' => CONTEXT_COURSE, diff --git a/db/install.xml b/db/install.xml index c4226720..1eff50a6 100644 --- a/db/install.xml +++ b/db/install.xml @@ -22,6 +22,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index c089d027..fe34659f 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -235,5 +235,17 @@ function xmldb_customcert_upgrade($oldversion) { upgrade_mod_savepoint(true, 2023042405, 'customcert'); } + if ($oldversion < 2023101000) { + $table = new xmldb_table('customcert'); + $field = new xmldb_field('keeplocalcopy', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'language'); + + // Conditionally launch add field. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + upgrade_mod_savepoint(true, 2023101000, 'customcert'); // Replace with the actual version number. + } + return true; } diff --git a/downloadcerts.php b/downloadcerts.php new file mode 100644 index 00000000..d6779317 --- /dev/null +++ b/downloadcerts.php @@ -0,0 +1,108 @@ +. + +/** + * Handles zip and download of certificates. + * + * Derived from the local_bulkcustomcert by Gonzalo Romero. + * + * @package mod_customcert + * @author Gonzalo Romero + * @author Giorgio Consorti + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/../../config.php'); + +$courseid = optional_param('courseid', null, PARAM_INT); +$customcertid = optional_param('customcertid', null, PARAM_INT); + +if (!has_capability('mod/customcert:viewallcertificates', context_system::instance()) && !$courseid && !$customcert) { + die(); +} + +/** @var \moodle_database $DB */ +global $DB; + +// Increase the server timeout to handle the creation and sending of large zip files. +core_php_time_limit::raise(); + +if ($courseid) { + $course = $DB->get_record('course', ['id' => $courseid]); + $certs = $DB->get_records('customcert', ['course' => $courseid]); +} else if ($customcertid) { + $cert = $DB->get_record('customcert', ['id' => $customcertid], '*', MUST_EXIST); + $certs[$cert->id] = $cert; + $course = $DB->get_record('course', ['id' => $certs[$cert->id]->course], '*', MUST_EXIST); + $courseid = $course->id; + unset($cert); +} + +// Build a list of files to zip. +$filesforzipping = []; + +foreach ($certs as $certid => $cert_fields) { + $issues = $DB->get_records('customcert_issues', ['customcertid' => $certid]); + list($userssql, $params) = $DB->get_in_or_equal(array_map(fn($i) => $i->userid, $issues), SQL_PARAMS_NAMED); + $usersObjs = $DB->get_records_select('user', "id {$userssql}", $params); + $template = $DB->get_record('customcert_templates', ['id' => $cert_fields->templateid], '*', MUST_EXIST); + $template = new \mod_customcert\template($template); + $lf = new \mod_customcert\localfile($template); + foreach ($issues as $issue) { + if (false === $file = $lf->getPDF($issue->userid)) { + // must generate the pdf + $pdf = $template->generate_pdf(false, $issue->userid, true); + if (!empty($pdf)) { + if ($cert_fields->keeplocalcopy) { + $file = $lf->getPDF($issue->userid); + } else { + $file = [ + 'content' => $pdf, + ]; + } + } + } + if ($file) { + $filename = \mod_customcert\localfile::buildFileName($usersObjs[$issue->userid]->username, $template->get_id(), $course->shortname); + $filesforzipping['/' . $course->shortname . '/' . $cert_fields->name . '/' . $filename] = $file; + } + } +} + +if (count($filesforzipping) == 0) { + // This should never happen. The option only show up if there is available certs. + $url = new moodle_url('/course/view.php?id=' . $courseid); + redirect($url); +} else if ($zipfile = pack_files($filesforzipping)) { + send_temp_file($zipfile, get_string('modulenameplural', 'customcert') . '-' . $course->shortname . '.zip'); +} +die(); + + +function pack_files($filesforzipping) +{ + global $CFG; + // Create path for new zip file. + $tempzip = tempnam($CFG->tempdir . '/', 'customcert_'); + // Zip files. + $zipper = new zip_packer(); + if ($zipper->archive_to_pathname($filesforzipping, $tempzip)) { + return $tempzip; + } + return false; +} diff --git a/lang/en/customcert.php b/lang/en/customcert.php index 28910b8f..3783da2b 100644 --- a/lang/en/customcert.php +++ b/lang/en/customcert.php @@ -41,6 +41,8 @@ $string['createtemplate'] = 'Create template'; $string['customcert:addinstance'] = 'Add a new custom certificate instance'; $string['customcert:manage'] = 'Manage a custom certificate'; +$string['customcert:managekeeplocalcopy'] = 'Manage keep local certificate copy setting'; +$string['customcert:deletelocalcopy'] = 'Delete local certificate copies'; $string['customcert:manageemailstudents'] = 'Manage email students setting'; $string['customcert:manageemailteachers'] = 'Manage email teachers setting'; $string['customcert:manageemailothers'] = 'Manage email others setting'; @@ -59,6 +61,7 @@ $string['deleteelement'] = 'Delete element'; $string['deleteelementconfirm'] = 'Are you sure you want to delete this element?'; $string['deleteissueconfirm'] = 'Are you sure you want to delete this certificate issue?'; +$string['deletelocalcopyconfirm'] = 'Are you sure you want to delete this certificate PDF file?'; $string['deleteissuedcertificates'] = 'Delete issued certificates'; $string['deletepageconfirm'] = 'Are you sure you want to delete this certificate page?'; $string['deletetemplateconfirm'] = 'Are you sure you want to delete this certificate template?'; @@ -95,6 +98,10 @@ $string['emailstudentsubject'] = '{$a->coursefullname}: {$a->certificatename}'; $string['emailstudents'] = 'Email students'; $string['emailstudents_help'] = 'If set this will email the students a copy of the certificate when it becomes available. Warning: Setting this to \'Yes\' before you have finished creating the certificate will email the student an incomplete certificate.'; +$string['keeplocalcopy'] = 'Keep local certificate copy'; +$string['keeplocalcopy_help'] = 'If set this will keep a local copy of the certificate PDF. The copy will be served on all future certificate downloads until the file is deleted from the moodle files table.'; +$string['deletelocalcopy'] = 'Delete local certificate copy'; +$string['bulkdownloadlink'] = 'Download certificates'; $string['emailteachers'] = 'Email teachers'; $string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available. Warning: Setting this to \'Yes\' before you have finished creating the certificate will email the teacher an incomplete certificate.'; $string['emailothers'] = 'Email others'; diff --git a/lang/it/customcert.php b/lang/it/customcert.php new file mode 100644 index 00000000..0a8753e5 --- /dev/null +++ b/lang/it/customcert.php @@ -0,0 +1,31 @@ +. + +/** + * Language strings for the customcert module. + * + * @package mod_customcert + * @copyright 2013 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + $string['keeplocalcopy'] = 'Mantieni copia dei certificati'; + $string['keeplocalcopy_help'] = 'Se impostato a Sì, mantiene una copia del PDF dei certificati. La copia sarà scaricata ad ogni futura richiesta del certificato, finché il file non è cancellato dalla tabella files di moodle.'; + $string['deletelocalcopy'] = 'Cancella copia locale del certificato'; + $string['bulkdownloadlink'] = 'Download certificati'; + $string['deletelocalcopyconfirm'] = 'Sei sicuro di voler cancellare il file PDF del certificato?'; + $string['customcert:managekeeplocalcopy'] = 'Gestire impostazioni copia locale certificati'; + $string['customcert:deletelocalcopy'] = 'Cancella copia locale dei certificati'; diff --git a/lib.php b/lib.php index 819aec3f..260bb7ca 100644 --- a/lib.php +++ b/lib.php @@ -312,6 +312,27 @@ function mod_customcert_output_fragment_editelement($args) { return $form->render(); } +/** + * This function extends the course navigation block for the site. + * + * @param \navigation_node $parentnode + * @param \stdClass $course + * @param \context_course $context + */ +function customcert_extend_navigation_course(\navigation_node $parentnode, \stdClass $course, \context_course $context) { + global $PAGE; + + $addnode = $context->contextlevel === 50; + $addnode = $addnode && !($context->instanceid === SITEID); + $addnode = $addnode && has_capability('mod/customcert:viewallcertificates', $context); + $isCourseNav = !is_null($PAGE->cm) && is_null($PAGE->cm->instance); + if ($addnode && $isCourseNav) { + if ($node = build_downloadall_node($isCourseNav, $course, $context)) { + $parentnode->add_node($node); + } + } +} + /** * This function extends the settings navigation block for the site. * @@ -343,6 +364,12 @@ function customcert_extend_settings_navigation(settings_navigation $settings, na $customcertnode->add_node($node, $beforekey); } + if (has_capability('mod/customcert:viewallcertificates', $PAGE->cm->context)) { + if ($node = build_downloadall_node(false, $PAGE->cm->get_course(), null)) { + $customcertnode->add_node($node, $beforekey); + } + } + if (has_capability('mod/customcert:verifycertificate', $settings->get_page()->cm->context)) { $node = navigation_node::create(get_string('verifycertificate', 'customcert'), new moodle_url('/mod/customcert/verify_certificate.php', ['contextid' => $settings->get_page()->cm->context->id]), @@ -354,6 +381,50 @@ function customcert_extend_settings_navigation(settings_navigation $settings, na return $customcertnode->trim_if_empty(); } +/** + * Build the navigation node for the 'Download certificates' item. + * + * @param boolean $isCourseNav + * @param \stdClass $course + * @param \course_context $context + * @return \navigation_node|null null if there are no certifcates available for the download + */ +function build_downloadall_node(bool $isCourseNav, stdClass $course, \context_course $context = null) { + + global $DB, $PAGE; + + if (!$isCourseNav) { + $courseContext = \context_course::instance($course->id); + //Check if there is available certs + $certs = $DB->get_records('customcert', ['id' => $PAGE->cm->instance]); + $users = $DB->get_records('role_assignments', ['contextid' => $courseContext->id]); + $urlparams = ['customcertid' => $PAGE->cm->instance]; + } else { + $certs = $DB->get_records('customcert', ['course' => $context->instanceid]); + $users = $DB->get_records('role_assignments', ['contextid' => $context->id]); + $urlparams = ['courseid' => $course->id]; + } + $availablecerts = false; + foreach ($certs as $certid => $cert_fields) { + foreach ($users as $userid => $user_fields) { + if (!$DB->get_record('customcert_issues', ['userid' => $user_fields->userid, 'customcertid' => $certid])) { + continue; + } + $availablecerts = true; + break; + } + if ($availablecerts) break; + } + if ($availablecerts) { + $node = \navigation_node::create(get_string('bulkdownloadlink', 'mod_customcert'), + new \moodle_url('/mod/customcert/downloadcerts.php', $urlparams), + \navigation_node::TYPE_SETTING, null, 'mod_customcert_downloadcerts', + new \pix_icon('a/download_all', 'certificates')); + return $node; + } + return null; +} + /** * Add nodes to myprofile page. * @@ -427,7 +498,8 @@ function mod_customcert_inplace_editable($itemtype, $itemid, $newvalue) { */ function mod_customcert_get_fontawesome_icon_map() { return [ - 'mod_customcert:download' => 'fa-download' + 'mod_customcert:deletelocalcopy' => 'fa-minus-square', + 'mod_customcert:download' => 'fa-download', ]; } diff --git a/mod_form.php b/mod_form.php index 917deec2..1e947bd2 100644 --- a/mod_form.php +++ b/mod_form.php @@ -66,6 +66,13 @@ public function definition() { $mform->addElement('select', 'deliveryoption', get_string('deliveryoptions', 'customcert'), $deliveryoptions); $mform->setDefault('deliveryoption', certificate::DELIVERY_OPTION_INLINE); + if (has_capability('mod/customcert:managekeeplocalcopy', $this->get_context())) { + $mform->addElement('selectyesno', 'keeplocalcopy', get_string('keeplocalcopy', 'customcert')); + $mform->setDefault('keeplocalcopy', get_config('customcert', 'keeplocalcopy')); + $mform->addHelpButton('keeplocalcopy', 'keeplocalcopy', 'customcert'); + $mform->setType('keeplocalcopy', PARAM_INT); + } + if (has_capability('mod/customcert:manageemailstudents', $this->get_context())) { $mform->addElement('selectyesno', 'emailstudents', get_string('emailstudents', 'customcert')); $mform->setDefault('emailstudents', get_config('customcert', 'emailstudents')); @@ -207,6 +214,7 @@ public function validation($data, $files) { */ protected function get_options_elements_with_required_caps() { return [ + 'keeplocalcopy' => 'mod/customcert:managekeeplocalcopy', 'emailstudents' => 'mod/customcert:manageemailstudents', 'emailteachers' => 'mod/customcert:manageemailteachers', 'emailothers' => 'mod/customcert:manageemailothers', diff --git a/settings.php b/settings.php index 6a648edc..d0399606 100644 --- a/settings.php +++ b/settings.php @@ -59,6 +59,8 @@ 1 => get_string('yes'), ]; +$settings->add(new admin_setting_configselect('customcert/keeplocalcopy', + get_string('keeplocalcopy', 'customcert'), get_string('keeplocalcopy_help', 'customcert'), 0, $yesnooptions)); $settings->add(new admin_setting_configselect('customcert/emailstudents', get_string('emailstudents', 'customcert'), get_string('emailstudents_help', 'customcert'), 0, $yesnooptions)); $settings->add(new admin_setting_configselect('customcert/emailteachers', diff --git a/version.php b/version.php index f6a0bdfb..d48efd3e 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); -$plugin->version = 2023042406; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2023101000; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2023042400; // Requires this Moodle version (4.2). $plugin->cron = 0; // Period for cron to check this module (secs). $plugin->component = 'mod_customcert'; diff --git a/view.php b/view.php index 04c2ae2e..19f327f0 100644 --- a/view.php +++ b/view.php @@ -29,6 +29,7 @@ $downloadtable = optional_param('download', null, PARAM_ALPHA); $downloadissue = optional_param('downloadissue', 0, PARAM_INT); $deleteissue = optional_param('deleteissue', 0, PARAM_INT); +$deletelocalcopy = optional_param('deletelocalcopy', 0, PARAM_INT); $confirm = optional_param('confirm', false, PARAM_BOOL); $page = optional_param('page', 0, PARAM_INT); $perpage = optional_param('perpage', \mod_customcert\certificate::CUSTOMCERT_PER_PAGE, PARAM_INT); @@ -46,6 +47,7 @@ $canreceive = has_capability('mod/customcert:receiveissue', $context); $canmanage = has_capability('mod/customcert:manage', $context); $canviewreport = has_capability('mod/customcert:viewreport', $context); +$candeletelocalcopy = has_capability('mod/customcert:deletelocalcopy', $context); // Initialise $PAGE. $pageurl = new moodle_url('/mod/customcert/view.php', ['id' => $cm->id]); @@ -70,14 +72,20 @@ [ 'id' => $id, 'deleteissue' => $deleteissue, + 'deletelocalcopy' => $deletelocalcopy, 'confirm' => 1, 'sesskey' => sesskey() ] ); // Show a confirmation page. - $PAGE->navbar->add(get_string('deleteconfirm', 'customcert')); - $message = get_string('deleteissueconfirm', 'customcert'); + if ($deletelocalcopy) { + $PAGE->navbar->add(get_string('deleteconfirm', 'customcert')); + $message = get_string('deletelocalcopyconfirm', 'customcert'); + } else if ($deleteissue) { + $PAGE->navbar->add(get_string('deleteconfirm', 'customcert')); + $message = get_string('deleteissueconfirm', 'customcert'); + } echo $OUTPUT->header(); echo $OUTPUT->heading(format_string($customcert->name)); echo $OUTPUT->confirm($message, $yesurl, $nourl); @@ -85,8 +93,19 @@ exit(); } - // Delete the issue. - $DB->delete_records('customcert_issues', ['id' => $deleteissue, 'customcertid' => $customcert->id]); + // Always delete local copy. + if ($candeletelocalcopy) { + $issues = $DB->get_records('customcert_issues', ['id' => $deleteissue, 'customcertid' => $customcert->id]); + if (!empty($issues)) { + $lf = new \mod_customcert\localfile(new \mod_customcert\template($template)); + array_map(fn($issue) => $lf->deletePDF($issue->userid), $issues); + } + } + + if (!$deletelocalcopy) { + // Delete the issue. + $DB->delete_records('customcert_issues', ['id' => $deleteissue, 'customcertid' => $customcert->id]); + } // Redirect back to the manage templates page. redirect(new moodle_url('/mod/customcert/view.php', ['id' => $id]));