From a487457d41a4abb9e365542d673e5ef2e5b3201e Mon Sep 17 00:00:00 2001 From: atlet Date: Thu, 12 Sep 2024 09:18:06 +0200 Subject: [PATCH 1/2] Limit the number of times a specific certificate can be issued to a user. --- classes/form/details.php | 11 +++++-- classes/persistent/template.php | 3 ++ classes/template.php | 22 +++++++++++++ db/install.xml | 3 +- db/upgrade.php | 58 +++++++++++++++++++++++++-------- lang/en/tool_certificate.php | 3 ++ 6 files changed, 84 insertions(+), 16 deletions(-) diff --git a/classes/form/details.php b/classes/form/details.php index 71505909..c4ad6f36 100644 --- a/classes/form/details.php +++ b/classes/form/details.php @@ -94,6 +94,11 @@ public function definition() { $mform->addHelpButton('shared', 'availableincourses', 'tool_certificate'); $mform->setDefault('shared', 1); + $mform->addElement('text', 'maxissuances', get_string('maxissuances', 'tool_certificate'), array('size' => '3')); + $mform->setType('maxissuances', PARAM_INT); + $mform->setDefault('maxissuances', 0); + $mform->addHelpButton('maxissuances', 'maxissuances', 'tool_certificate'); + if (!$this->get_template()->get_id()) { page::add_page_elements($mform); } else { @@ -156,7 +161,7 @@ public function check_access_for_dynamic_submission(): void { */ public function process_dynamic_submission() { global $CFG; - require_once($CFG->dirroot.'/course/lib.php'); + require_once($CFG->dirroot . '/course/lib.php'); $data = $this->get_data(); if (isset($data->categoryid)) { @@ -187,7 +192,9 @@ public function set_data_for_dynamic_submission(): void { 'id' => $this->template->get_id(), 'name' => $this->template->get_name(), 'shared' => $this->template->get_shared(), - 'categoryid' => $this->template->get_category_id(), ]); + 'categoryid' => $this->template->get_category_id(), + 'maxissuances' => $this->template->get_maxissuances(), + ]); } else { $data = template::instance()->new_page()->to_record(); unset($data->id, $data->templateid); diff --git a/classes/persistent/template.php b/classes/persistent/template.php index ea50f02f..286cfd7d 100644 --- a/classes/persistent/template.php +++ b/classes/persistent/template.php @@ -55,6 +55,9 @@ protected static function define_properties() { 'shared' => [ 'type' => PARAM_BOOL, ], + 'maxissuances' => [ + 'type' => PARAM_INT, + ] ]; } diff --git a/classes/template.php b/classes/template.php index fcf8f3b6..5c05809f 100644 --- a/classes/template.php +++ b/classes/template.php @@ -30,6 +30,7 @@ use core_user; use moodle_url; use tool_certificate\customfield\issue_handler; +use moodle_exception; /** * Class represents a certificate template. @@ -84,6 +85,9 @@ public function save($data) { if (isset($data->shared)) { $this->persistent->set('shared', $data->shared); } + if (isset($data->maxissuances)) { + $this->persistent->set('maxissuances', $data->maxissuances); + } $this->persistent->save(); \tool_certificate\event\template_updated::create_from_template($this)->trigger(); } @@ -443,6 +447,15 @@ public function get_shared() { return $this->persistent->get('shared'); } + /** + * Returns the maxissuances setting of the template. + * + * @return string the shared setting of the template + */ + public function get_maxissuances() { + return $this->persistent->get('maxissuances'); + } + /** * Returns the formatted name of the template. * @@ -647,6 +660,7 @@ public static function create($formdata) { $template = new \stdClass(); $template->name = $formdata->name; $template->shared = $formdata->shared ?? 0; + $template->maxissuances = $formdata->maxissuances ?? 0; if (!isset($formdata->contextid)) { debugging('Context is missing', DEBUG_DEVELOPER); $template->contextid = \context_system::instance()->id; @@ -697,6 +711,14 @@ public function issue_certificate($userid, $expires = null, array $data = [], $c component_class_callback(\tool_tenant\config::class, 'push_for_user', [$userid]); + $maxissuances = $DB->get_field('tool_certificate_templates', 'maxissuances', array('id' => $this->get_id())); + $usercertificates = $DB->count_records('tool_certificate_issues', array('userid' => $userid, 'templateid' => $this->get_id())); + + if ($maxissuances > 0 && $usercertificates >= $maxissuances) { + // Do not issue the certificate and possibly show an error message. + throw new moodle_exception('maxissuancesreached', 'tool_certificate'); + } + $issue = new \stdClass(); $issue->userid = $userid; $issue->templateid = $this->get_id(); diff --git a/db/install.xml b/db/install.xml index d0401b27..f9a827aa 100644 --- a/db/install.xml +++ b/db/install.xml @@ -1,5 +1,5 @@ - @@ -12,6 +12,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index e838cd51..428dd3b7 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -30,7 +30,7 @@ */ function xmldb_tool_certificate_upgrade($oldversion) { global $DB, $CFG; - require_once($CFG->dirroot.'/'.$CFG->admin.'/tool/certificate/db/upgradelib.php'); + require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/certificate/db/upgradelib.php'); $dbman = $DB->get_manager(); @@ -53,8 +53,10 @@ function xmldb_tool_certificate_upgrade($oldversion) { foreach ($elements as $element) { $data = @json_decode($element->data, true); $data['isbackground'] = 1; - $DB->update_record('tool_certificate_elements', - ['id' => $element->id, 'element' => 'image', 'data' => json_encode($data)]); + $DB->update_record( + 'tool_certificate_elements', + ['id' => $element->id, 'element' => 'image', 'data' => json_encode($data)] + ); } upgrade_plugin_savepoint(true, 2019030707, 'tool', 'certificate'); @@ -62,24 +64,30 @@ function xmldb_tool_certificate_upgrade($oldversion) { if ($oldversion < 2019030708) { // Change instances of studentname to userfield. - $DB->execute("UPDATE {tool_certificate_elements} SET element = ?, data = ? WHERE element = ?", - ['userfield', 'fullname', 'studentname']); + $DB->execute( + "UPDATE {tool_certificate_elements} SET element = ?, data = ? WHERE element = ?", + ['userfield', 'fullname', 'studentname'] + ); upgrade_plugin_savepoint(true, 2019030708, 'tool', 'certificate'); } if ($oldversion < 2019030710) { // Change refpoint of all images. - $DB->execute("UPDATE {tool_certificate_elements} SET refpoint = null WHERE element IN (?, ?, ?)", - ['image', 'userpicture', 'digitalsignature']); + $DB->execute( + "UPDATE {tool_certificate_elements} SET refpoint = null WHERE element IN (?, ?, ?)", + ['image', 'userpicture', 'digitalsignature'] + ); upgrade_plugin_savepoint(true, 2019030710, 'tool', 'certificate'); } if ($oldversion < 2019030711) { // Change refpoint of all images. - $DB->execute("DELETE FROM {config_plugins} WHERE name = ? AND plugin IN (?, ?)", - ['version', 'certificateelement_bgimage', 'certificateelement_studentname']); + $DB->execute( + "DELETE FROM {config_plugins} WHERE name = ? AND plugin IN (?, ?)", + ['version', 'certificateelement_bgimage', 'certificateelement_studentname'] + ); upgrade_plugin_savepoint(true, 2019030711, 'tool', 'certificate'); } @@ -205,12 +213,21 @@ function xmldb_tool_certificate_upgrade($oldversion) { $duplicatecounter = 1; // For each duplicate code, retrieve all subsequent duplicates after the initial one and append counter. - $records = $DB->get_records_select('tool_certificate_issues', 'id <> :id AND code = :code', - ['id' => $duplicatecode->minid, 'code' => $duplicatecode->code], 'id', 'id'); + $records = $DB->get_records_select( + 'tool_certificate_issues', + 'id <> :id AND code = :code', + ['id' => $duplicatecode->minid, 'code' => $duplicatecode->code], + 'id', + 'id' + ); foreach ($records as $record) { - $DB->set_field('tool_certificate_issues', 'code', $duplicatecode->code . $duplicatecounter++, - ['id' => $record->id]); + $DB->set_field( + 'tool_certificate_issues', + 'code', + $duplicatecode->code . $duplicatecounter++, + ['id' => $record->id] + ); } } @@ -247,5 +264,20 @@ function xmldb_tool_certificate_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2023071300, 'tool', 'certificate'); } + if ($oldversion < 2024081902) { + + // Define field maxissuances to be added to tool_certificate_templates. + $table = new xmldb_table('tool_certificate_templates'); + $field = new xmldb_field('maxissuances', XMLDB_TYPE_INTEGER, '3', null, XMLDB_NOTNULL, null, '0', 'timemodified'); + + // Conditionally launch add field maxissuances. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Certificate savepoint reached. + upgrade_plugin_savepoint(true, 2024081902, 'tool', 'certificate'); + } + return true; } diff --git a/lang/en/tool_certificate.php b/lang/en/tool_certificate.php index f132bb53..8ae9bac5 100644 --- a/lang/en/tool_certificate.php +++ b/lang/en/tool_certificate.php @@ -199,6 +199,9 @@ $string['verifycertificates'] = 'Verify certificates'; $string['verifynotallowed'] = 'You are not allowed to verify certificates.'; $string['viewcertificate'] = 'View certificate'; +$string['maxissuances'] = 'Maximum issuances per user'; +$string['maxissuances_help'] = 'The maximum number of times this certificate can be issued to a single user. If 0 there is no limit.'; +$string['maxissuancesreached'] = 'You have reached the maximum number of times this certificate can be issued to you.'; // Deprecated since 4.2. $string['editcertificate'] = 'Edit certificate template \'{$a}\''; From 4a6515f7d0181ab7ea99e1b9d1a6df51bcb6c62b Mon Sep 17 00:00:00 2001 From: atlet Date: Fri, 4 Oct 2024 13:16:15 +0200 Subject: [PATCH 2/2] Added an option to notify user when is getting a new certificate. --- classes/form/details.php | 5 +++++ classes/persistent/template.php | 3 +++ classes/template.php | 18 +++++++++++++++++- db/install.xml | 3 ++- db/upgrade.php | 15 +++++++++++++++ lang/en/tool_certificate.php | 2 ++ version.php | 2 +- 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/classes/form/details.php b/classes/form/details.php index c4ad6f36..70b03bd6 100644 --- a/classes/form/details.php +++ b/classes/form/details.php @@ -99,6 +99,10 @@ public function definition() { $mform->setDefault('maxissuances', 0); $mform->addHelpButton('maxissuances', 'maxissuances', 'tool_certificate'); + $mform->addElement('advcheckbox', 'notify', get_string('notify', 'tool_certificate')); + $mform->addHelpButton('notify', 'notify', 'tool_certificate'); + $mform->setDefault('notify', 1); + if (!$this->get_template()->get_id()) { page::add_page_elements($mform); } else { @@ -194,6 +198,7 @@ public function set_data_for_dynamic_submission(): void { 'shared' => $this->template->get_shared(), 'categoryid' => $this->template->get_category_id(), 'maxissuances' => $this->template->get_maxissuances(), + 'notify' => $this->template->get_notify(), ]); } else { $data = template::instance()->new_page()->to_record(); diff --git a/classes/persistent/template.php b/classes/persistent/template.php index 286cfd7d..cb00c67f 100644 --- a/classes/persistent/template.php +++ b/classes/persistent/template.php @@ -57,6 +57,9 @@ protected static function define_properties() { ], 'maxissuances' => [ 'type' => PARAM_INT, + ], + 'notify' => [ + 'type' => PARAM_BOOL ] ]; } diff --git a/classes/template.php b/classes/template.php index 5c05809f..019105d3 100644 --- a/classes/template.php +++ b/classes/template.php @@ -88,6 +88,9 @@ public function save($data) { if (isset($data->maxissuances)) { $this->persistent->set('maxissuances', $data->maxissuances); } + if (isset($data->notify)) { + $this->persistent->set('notify', $data->notify); + } $this->persistent->save(); \tool_certificate\event\template_updated::create_from_template($this)->trigger(); } @@ -456,6 +459,15 @@ public function get_maxissuances() { return $this->persistent->get('maxissuances'); } + /** + * Returns the notify setting of the template. + * + * @return string the shared setting of the template + */ + public function get_notify() { + return $this->persistent->get('notify'); + } + /** * Returns the formatted name of the template. * @@ -661,6 +673,7 @@ public static function create($formdata) { $template->name = $formdata->name; $template->shared = $formdata->shared ?? 0; $template->maxissuances = $formdata->maxissuances ?? 0; + $template->notify = $formdata->notify ?? 1; if (!isset($formdata->contextid)) { debugging('Context is missing', DEBUG_DEVELOPER); $template->contextid = \context_system::instance()->id; @@ -712,6 +725,7 @@ public function issue_certificate($userid, $expires = null, array $data = [], $c component_class_callback(\tool_tenant\config::class, 'push_for_user', [$userid]); $maxissuances = $DB->get_field('tool_certificate_templates', 'maxissuances', array('id' => $this->get_id())); + $notify = (bool) $DB->get_field('tool_certificate_templates', 'notify', array('id' => $this->get_id())); $usercertificates = $DB->count_records('tool_certificate_issues', array('userid' => $userid, 'templateid' => $this->get_id())); if ($maxissuances > 0 && $usercertificates >= $maxissuances) { @@ -749,7 +763,9 @@ public function issue_certificate($userid, $expires = null, array $data = [], $c // Create the issue file and send notification. $issuefile = $this->create_issue_file($issue); - self::send_issue_notification($issue, $issuefile); + if ($notify) { + self::send_issue_notification($issue, $issuefile); + } component_class_callback(\tool_tenant\config::class, 'pop', []); diff --git a/db/install.xml b/db/install.xml index f9a827aa..f7a67b54 100644 --- a/db/install.xml +++ b/db/install.xml @@ -1,5 +1,5 @@ - @@ -13,6 +13,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index 428dd3b7..73c0fb73 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -279,5 +279,20 @@ function xmldb_tool_certificate_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2024081902, 'tool', 'certificate'); } + if ($oldversion < 2024100401) { + + // Define field notify to be added to tool_certificate_templates. + $table = new xmldb_table('tool_certificate_templates'); + $field = new xmldb_field('notify', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'maxissuances'); + + // Conditionally launch add field notify. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Certificate savepoint reached. + upgrade_plugin_savepoint(true, 2024100401, 'tool', 'certificate'); + } + return true; } diff --git a/lang/en/tool_certificate.php b/lang/en/tool_certificate.php index 8ae9bac5..e276319b 100644 --- a/lang/en/tool_certificate.php +++ b/lang/en/tool_certificate.php @@ -202,6 +202,8 @@ $string['maxissuances'] = 'Maximum issuances per user'; $string['maxissuances_help'] = 'The maximum number of times this certificate can be issued to a single user. If 0 there is no limit.'; $string['maxissuancesreached'] = 'You have reached the maximum number of times this certificate can be issued to you.'; +$string['notify'] = 'Notify users'; +$string['notify_help'] = 'Notify users that they received a new certificate.'; // Deprecated since 4.2. $string['editcertificate'] = 'Edit certificate template \'{$a}\''; diff --git a/version.php b/version.php index 03e799a8..16022d14 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ $plugin->component = 'tool_certificate'; $plugin->release = '4.4.3'; -$plugin->version = 2024090300; +$plugin->version = 2024100401; $plugin->requires = 2022041900.00; $plugin->maturity = MATURITY_STABLE; $plugin->supported = [400, 404];