From ca08fe954a4a70ffed0cfedf895984b59f99fe12 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 1 Feb 2017 18:23:15 +0800 Subject: [PATCH] #51 Added ability to verify certificates --- classes/output/renderer.php | 52 +++++++++++ classes/output/verify_certificate_result.php | 90 +++++++++++++++++++ classes/output/verify_certificate_results.php | 83 +++++++++++++++++ classes/verify_certificate_form.php | 60 +++++++++++++ db/access.php | 10 +++ lang/en/customcert.php | 6 ++ lib.php | 8 ++ templates/verify_certificate_result.mustache | 5 ++ templates/verify_certificate_results.mustache | 9 ++ verify_certificate.php | 84 +++++++++++++++++ version.php | 4 +- 11 files changed, 409 insertions(+), 2 deletions(-) create mode 100644 classes/output/renderer.php create mode 100644 classes/output/verify_certificate_result.php create mode 100644 classes/output/verify_certificate_results.php create mode 100644 classes/verify_certificate_form.php create mode 100644 templates/verify_certificate_result.mustache create mode 100644 templates/verify_certificate_results.mustache create mode 100644 verify_certificate.php diff --git a/classes/output/renderer.php b/classes/output/renderer.php new file mode 100644 index 0000000..df946b7 --- /dev/null +++ b/classes/output/renderer.php @@ -0,0 +1,52 @@ +. + +/** + * Contains renderer class. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_customcert\output; + +defined('MOODLE_INTERNAL') || die(); + +use plugin_renderer_base; + +/** + * Renderer class. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends plugin_renderer_base { + + /** + * Renders the verify certificate results. + * + * Defer to template. + * + * @param \mod_customcert\output\verify_certificate_results $page + * @return string html for the page + */ + public function render_verify_certificate_results(verify_certificate_results $page) { + $data = $page->export_for_template($this); + return parent::render_from_template('mod_customcert/verify_certificate_results', $data); + } +} diff --git a/classes/output/verify_certificate_result.php b/classes/output/verify_certificate_result.php new file mode 100644 index 0000000..01233a1 --- /dev/null +++ b/classes/output/verify_certificate_result.php @@ -0,0 +1,90 @@ +. + +/** + * Contains class used to prepare a verification result for display. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_customcert\output; + +defined('MOODLE_INTERNAL') || die(); + +use renderable; +use templatable; + +/** + * Class to prepare a verification result for display. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class verify_certificate_result implements templatable, renderable { + + /** + * @var string The URL to the user's profile. + */ + public $userprofileurl; + + /** + * @var string The user's fullname. + */ + public $userfullname; + + /** + * @var string The URL to the course page. + */ + public $courseurl; + + /** + * @var string The course's fullname. + */ + public $coursefullname; + + /** + * @var string The certificate's name. + */ + public $certificatename; + + /** + * Constructor. + * + * @param \stdClass $result + */ + public function __construct($result) { + $this->userprofileurl = new \moodle_url('/user/view.php', array('id' => $result->userid, + 'course' => $result->courseid)); + $this->userfullname = fullname($result); + $this->courseurl = new \moodle_url('/course/view.php', array('id' => $result->courseid)); + $this->coursefullname = $result->coursefullname; + $this->certificatename = $result->certificatename; + } + + public function export_for_template(\renderer_base $output) { + $result = new \stdClass(); + $result->userprofileurl = $this->userprofileurl; + $result->userfullname = $this->userfullname; + $result->coursefullname = $this->coursefullname; + $result->courseurl = $this->courseurl; + $result->certificatename = $this->certificatename; + + return $result; + } +} diff --git a/classes/output/verify_certificate_results.php b/classes/output/verify_certificate_results.php new file mode 100644 index 0000000..c08b6ed --- /dev/null +++ b/classes/output/verify_certificate_results.php @@ -0,0 +1,83 @@ +. + +/** + * Contains class used to prepare verification results for display. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_customcert\output; + +defined('MOODLE_INTERNAL') || die(); + +use renderable; +use templatable; + +/** + * Class to prepare verification results for display. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class verify_certificate_results implements templatable, renderable { + + /** + * @var bool Was the code successfully verified? + */ + public $success; + + /** + * @var string The message to display. + */ + public $message; + + /** + * @var array The certificates issued with the matching code. + */ + public $issues; + + /** + * Constructor. + * + * @param \stdClass $result + */ + public function __construct($result) { + $this->success = $result->success; + if ($this->success) { + $this->message = get_string('verified', 'customcert'); + } else { + $this->message = get_string('notverified', 'customcert'); + } + $this->issues = $result->issues; + } + + public function export_for_template(\renderer_base $output) { + $result = new \stdClass(); + $result->success = $this->success; + $result->message = $this->message; + $result->issues = array(); + foreach ($this->issues as $issue) { + $resultissue = new verify_certificate_result($issue); + $result->issues[] = $resultissue->export_for_template($output); + } + + return $result; + } +} diff --git a/classes/verify_certificate_form.php b/classes/verify_certificate_form.php new file mode 100644 index 0000000..97020b3 --- /dev/null +++ b/classes/verify_certificate_form.php @@ -0,0 +1,60 @@ +. + +namespace mod_customcert; + +defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); + +require_once($CFG->libdir . '/formslib.php'); + +/** + * The form for verifying a certificate + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class verify_certificate_form extends \moodleform { + + /** + * Form definition. + */ + public function definition() { + $mform =& $this->_form; + + $mform->addElement('text', 'code', get_string('code', 'customcert')); + $mform->setType('code', PARAM_ALPHANUM); + + $mform->addElement('submit', 'verify', get_string('verify', 'customcert')); + } + + /** + * Validation. + * + * @param array $data + * @param array $files + * @return array the errors that were found + */ + public function validation($data, $files) { + $errors = array(); + + if ($data['code'] === '') { + $errors['code'] = get_string('invalidcode', 'customcert'); + } + + return $errors; + } +} diff --git a/db/access.php b/db/access.php index cf61c08..60a36d1 100644 --- a/db/access.php +++ b/db/access.php @@ -67,4 +67,14 @@ $capabilities = array( 'manager' => CAP_ALLOW ) ), + + 'mod/customcert:verifycertificate' => array( + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ) + ), ); diff --git a/lang/en/customcert.php b/lang/en/customcert.php index 9b79409..41d8888 100644 --- a/lang/en/customcert.php +++ b/lang/en/customcert.php @@ -36,6 +36,7 @@ $string['customcert:addinstance'] = 'Add a new custom certificate instance'; $string['customcert:manage'] = 'Manage a custom certificate'; $string['customcert:view'] = 'View a custom certificate'; $string['customcert:viewallcertificates'] = 'View all certificates'; +$string['customcert:verifycertificate'] = 'Verify a certificate'; $string['deletecertpage'] = 'Delete certificate page'; $string['deleteconfirm'] = 'Delete confirmation'; $string['deleteelement'] = 'Delete element'; @@ -64,6 +65,7 @@ $string['fontsize_help'] = 'The size of the font in points.'; $string['getcustomcert'] = 'Download certificate'; $string['height'] = 'Height'; $string['height_help'] = 'This is the height of the certificate PDF in mm. For reference an A4 piece of paper is 297mm high and a letter is 279mm high.'; +$string['invalidcode'] = 'Invalid code supplied.'; $string['invalidcolour'] = 'Invalid colour chosen, please enter a valid HTML colour name, or a six-digit, or three-digit hexadecimal colour.'; $string['invalidelementwidth'] = 'Please enter a positive number.'; $string['invalidposition'] = 'Please select a positive number for position {$a}.'; @@ -91,6 +93,7 @@ $string['nocustomcerts'] = 'There are no custom certificates for this course'; $string['noimage'] = 'No image'; $string['notemplates'] = 'No templates'; $string['notissued'] = 'Not issued'; +$string['notverified'] = 'Not verified'; $string['options'] = 'Options'; $string['page'] = 'Page {$a}'; $string['pluginadministration'] = 'Custom certificate administration'; @@ -132,6 +135,9 @@ $string['type'] = 'Type'; $string['uploadimage'] = 'Upload image'; $string['uploadimagedesc'] = 'This link will take you to a new screen where you will be able to upload images. Images uploaded using this method will be available throughout your site to all users who are able to create a custom certificate.'; +$string['verified'] = 'Verified'; +$string['verify'] = 'Verify'; +$string['verifycertificate'] = 'Verify certificate'; $string['viewcustomcertissues'] = 'View {$a} issued custom certificates'; $string['width'] = 'Width'; $string['width_help'] = 'This is the width of the certificate PDF in mm. For reference an A4 piece of paper is 210mm wide and a letter is 216mm wide.'; diff --git a/lib.php b/lib.php index 0e900a5..c565dd8 100644 --- a/lib.php +++ b/lib.php @@ -350,6 +350,14 @@ function customcert_extend_settings_navigation(settings_navigation $settings, na $customcertnode->add_node($node, $beforekey); } + if (has_capability('mod/customcert:verifycertificate', $PAGE->cm->context)) { + $node = navigation_node::create(get_string('verifycertificate', 'customcert'), + new moodle_url('/mod/customcert/verify_certificate.php', array('contextid' => $PAGE->cm->context->id)), + navigation_node::TYPE_SETTING, null, 'mod_customcert_verify_certificate', + new pix_icon('t/check', '')); + $customcertnode->add_node($node, $beforekey); + } + return $customcertnode->trim_if_empty(); } diff --git a/templates/verify_certificate_result.mustache b/templates/verify_certificate_result.mustache new file mode 100644 index 0000000..8fbb9c6 --- /dev/null +++ b/templates/verify_certificate_result.mustache @@ -0,0 +1,5 @@ + diff --git a/templates/verify_certificate_results.mustache b/templates/verify_certificate_results.mustache new file mode 100644 index 0000000..95c0cbd --- /dev/null +++ b/templates/verify_certificate_results.mustache @@ -0,0 +1,9 @@ +{{#success}} + {{#issues}} + {{> mod_customcert/verify_certificate_result }} + {{/issues}} + {{> core/notification_success}} +{{/success}} +{{^success}} + {{> core/notification_error}} +{{/success}} diff --git a/verify_certificate.php b/verify_certificate.php new file mode 100644 index 0000000..3e04bc1 --- /dev/null +++ b/verify_certificate.php @@ -0,0 +1,84 @@ +. + +/** + * Handles verifying the code for a certificate. + * + * @package mod_customcert + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once('../../config.php'); + +$contextid = required_param('contextid', PARAM_INT); +$code = optional_param('code', '', PARAM_ALPHANUM); // The code for the certificate we are verifying. + +// Need to be logged in. +require_login(); + +// Ok, now check the user has the ability to verify certificates. +require_capability('mod/customcert:verifycertificate', context::instance_by_id($contextid)); + +// Set up the page. +$pageurl = new moodle_url('/mod/customcert/verify_certificate.php', array('contextid' => $contextid)); +if ($code) { + $pageurl->param('code', $code); +} + +$PAGE->set_url($pageurl); +$PAGE->set_context(context_system::instance()); +$PAGE->set_title(get_string('verifycertificate', 'customcert')); + +// The form we are using to verify these codes. +$form = new \mod_customcert\verify_certificate_form($pageurl); + +if ($form->get_data()) { + $result = new stdClass(); + $result->issues = array(); + + // Ok, now check if the code is valid. + $userfields = get_all_user_name_fields(true, 'u'); + $sql = "SELECT ci.id, u.id as userid, $userfields, co.id as courseid, + co.fullname as coursefullname, c.name as certificatename + FROM {customcert} c + JOIN {customcert_issues} ci + ON c.id = ci.customcertid + JOIN {course} co + ON c.course = co.id + JOIN {user} u + ON ci.userid = u.id + WHERE ci.code = :code + AND u.deleted = 0"; + // It is possible (though unlikely) that there is the same code for issued certificates. + if ($issues = $DB->get_records_sql($sql, array('code' => $code))) { + $result->success = true; + $result->issues = $issues; + } else { + // Can't find it, let's say it's not verified. + $result->success = false; + } +} + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('verifycertificate', 'customcert')); +echo $form->display(); +if (isset($result)) { + $renderer = $PAGE->get_renderer('mod_customcert'); + $result = new \mod_customcert\output\verify_certificate_results($result); + echo $renderer->render($result); +} +echo $OUTPUT->footer(); diff --git a/version.php b/version.php index db988eb..1183582 100644 --- a/version.php +++ b/version.php @@ -24,10 +24,10 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); -$plugin->version = 2016120503; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2016120504; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2016120500; // Requires this Moodle version (3.2). $plugin->cron = 0; // Period for cron to check this module (secs). $plugin->component = 'mod_customcert'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = "3.2 release (Build: 2016120502)"; // User-friendly version number. +$plugin->release = "3.2 release (Build: 2016120504)"; // User-friendly version number.