From d9eb78eee19a2c0a46f71a9a548f26957108b823 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sat, 26 Aug 2017 18:50:24 +0800 Subject: [PATCH] #46 Added digital signature element --- classes/certificate.php | 5 +- element/digitalsignature/classes/element.php | 330 ++++++++++++++++++ .../en/customcertelement_digitalsignature.php | 33 ++ element/digitalsignature/version.php | 29 ++ element/image/classes/element.php | 2 +- tests/behat/managing_elements.feature | 22 ++ upload_image.php | 2 +- 7 files changed, 419 insertions(+), 4 deletions(-) create mode 100644 element/digitalsignature/classes/element.php create mode 100644 element/digitalsignature/lang/en/customcertelement_digitalsignature.php create mode 100644 element/digitalsignature/version.php diff --git a/classes/certificate.php b/classes/certificate.php index 45c2ef5..846e19f 100644 --- a/classes/certificate.php +++ b/classes/certificate.php @@ -86,13 +86,14 @@ class certificate { * * @param int $draftitemid the draft area containing the files * @param int $contextid the context we are storing this image in + * @param string $filearea indentifies the file area. */ - public static function upload_imagefiles($draftitemid, $contextid) { + public static function upload_files($draftitemid, $contextid, $filearea = 'image') { global $CFG; // Save the file if it exists that is currently in the draft area. require_once($CFG->dirroot . '/lib/filelib.php'); - file_save_draft_area_files($draftitemid, $contextid, 'mod_customcert', 'image', 0); + file_save_draft_area_files($draftitemid, $contextid, 'mod_customcert', $filearea, 0); } /** diff --git a/element/digitalsignature/classes/element.php b/element/digitalsignature/classes/element.php new file mode 100644 index 0000000..d218eb9 --- /dev/null +++ b/element/digitalsignature/classes/element.php @@ -0,0 +1,330 @@ +. + +namespace customcertelement_digitalsignature; + +defined('MOODLE_INTERNAL') || die(); + +/** + * The customcert element signature's core interaction API. + * + * @package customcertelement_digitalsignature + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class element extends \customcertelement_image\element { + + /** + * @var array The file manager options for the certificate. + */ + protected $signaturefilemanageroptions = array(); + + /** + * Constructor. + * + * @param \stdClass $element the element data + */ + public function __construct($element) { + global $COURSE; + + $this->signaturefilemanageroptions = [ + 'maxbytes' => $COURSE->maxbytes, + 'subdirs' => 1, + 'accepted_types' => ['.crt'] + ]; + + parent::__construct($element); + } + + /** + * This function renders the form elements when adding a customcert element. + * + * @param \mod_customcert\edit_element_form $mform the edit_form instance + */ + public function render_form_elements($mform) { + $mform->addElement('select', 'fileid', get_string('image', 'customcertelement_image'), self::get_images()); + + $mform->addElement('select', 'signaturefileid', get_string('digitalsignature', 'customcertelement_digitalsignature'), + self::get_signatures()); + + $mform->addElement('text', 'signaturename', get_string('signaturename', 'customcertelement_digitalsignature')); + $mform->setType('signaturename', PARAM_TEXT); + $mform->setDefault('signaturename', ''); + + $mform->addElement('passwordunmask', 'signaturepassword', + get_string('signaturepassword', 'customcertelement_digitalsignature')); + $mform->setType('signaturepassword', PARAM_TEXT); + $mform->setDefault('signaturepassword', ''); + + $mform->addElement('text', 'signaturelocation', get_string('signaturelocation', 'customcertelement_digitalsignature')); + $mform->setType('signaturelocation', PARAM_TEXT); + $mform->setDefault('signaturelocation', ''); + + $mform->addElement('text', 'signaturereason', get_string('signaturereason', 'customcertelement_digitalsignature')); + $mform->setType('signaturereason', PARAM_TEXT); + $mform->setDefault('signaturereason', ''); + + $mform->addElement('text', 'signaturecontactinfo', + get_string('signaturecontactinfo', 'customcertelement_digitalsignature')); + $mform->setType('signaturecontactinfo', PARAM_TEXT); + $mform->setDefault('signaturecontactinfo', ''); + + $mform->addElement('text', 'width', get_string('width', 'customcertelement_image'), array('size' => 10)); + $mform->setType('width', PARAM_INT); + $mform->setDefault('width', 0); + $mform->addHelpButton('width', 'width', 'customcertelement_image'); + + $mform->addElement('text', 'height', get_string('height', 'customcertelement_image'), array('size' => 10)); + $mform->setType('height', PARAM_INT); + $mform->setDefault('height', 0); + $mform->addHelpButton('height', 'height', 'customcertelement_image'); + + if (get_config('customcert', 'showposxy')) { + \mod_customcert\element_helper::render_form_element_position($mform); + } + + $mform->addElement('filemanager', 'customcertimage', get_string('uploadimage', 'customcert'), '', + $this->filemanageroptions); + + $mform->addElement('filemanager', 'digitalsignature', + get_string('uploaddigitalsignature', 'customcertelement_digitalsignature'), '', + $this->signaturefilemanageroptions); + } + + /** + * Handles saving the form elements created by this element. + * Can be overridden if more functionality is needed. + * + * @param \stdClass $data the form data + * @return bool true of success, false otherwise. + */ + public function save_form_elements($data) { + global $COURSE, $SITE; + + // Set the context. + if ($COURSE->id == $SITE->id) { + $context = \context_system::instance(); + } else { + $context = \context_course::instance($COURSE->id); + } + + // Handle file uploads. + \mod_customcert\certificate::upload_files($data->customcertimage, $context->id); + + // Handle file certificate uploads. + \mod_customcert\certificate::upload_files($data->digitalsignature, $context->id, 'signature'); + + return parent::save_form_elements($data); + } + + /** + * This will handle how form data will be saved into the data column in the + * customcert_elements table. + * + * @param \stdClass $data the form data + * @return string the json encoded array + */ + public function save_unique_data($data) { + $arrtostore = [ + 'signaturename' => $data->signaturename, + 'signaturepassword' => $data->signaturepassword, + 'signaturelocation' => $data->signaturelocation, + 'signaturereason' => $data->signaturereason, + 'signaturecontactinfo' => $data->signaturecontactinfo, + 'width' => !empty($data->width) ? (int) $data->width : 0, + 'height' => !empty($data->height) ? (int) $data->height : 0 + ]; + + // Array of data we will be storing in the database. + $fs = get_file_storage(); + + if (!empty($data->fileid)) { + if ($file = $fs->get_file_by_id($data->fileid)) { + $arrtostore += [ + 'contextid' => $file->get_contextid(), + 'filearea' => $file->get_filearea(), + 'itemid' => $file->get_itemid(), + 'filepath' => $file->get_filepath(), + 'filename' => $file->get_filename(), + ]; + } + } + + if (!empty($data->signaturefileid)) { + if ($signaturefile = $fs->get_file_by_id($data->signaturefileid)) { + $arrtostore += [ + 'signaturecontextid' => $signaturefile->get_contextid(), + 'signaturefilearea' => $signaturefile->get_filearea(), + 'signatureitemid' => $signaturefile->get_itemid(), + 'signaturefilepath' => $signaturefile->get_filepath(), + 'signaturefilename' => $signaturefile->get_filename() + ]; + } + } + + return json_encode($arrtostore); + } + + /** + * Handles rendering the element on the pdf. + * + * @param \pdf $pdf the pdf object + * @param bool $preview true if it is a preview, false otherwise + * @param \stdClass $user the user we are rendering this for + */ + public function render($pdf, $preview, $user) { + // If there is no element data, we have nothing to display. + if (empty($this->get_data())) { + return; + } + + $imageinfo = json_decode($this->get_data()); + + // If there is no file, we have nothing to display. + if (empty($imageinfo->filename)) { + return; + } + + // If there is no signature file, we have nothing to display. + if (empty($imageinfo->signaturefilename)) { + return; + } + + if ($file = $this->get_file()) { + $location = make_request_directory() . '/target'; + $file->copy_content_to($location); + + $mimetype = $file->get_mimetype(); + if ($mimetype == 'image/svg+xml') { + $pdf->ImageSVG($location, $this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height); + } else { + $pdf->Image($location, $this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height); + } + } + + if ($signaturefile = $this->get_signature_file()) { + $location = make_request_directory() . '/target'; + $signaturefile->copy_content_to($location); + $info = [ + 'Name' => $imageinfo->signaturename, + 'Location' => $imageinfo->signaturelocation, + 'Reason' => $imageinfo->signaturereason, + 'ContactInfo' => $imageinfo->signaturecontactinfo + ]; + $pdf->setSignature('file://' . $location, '', $imageinfo->signaturepassword, '', 2, $info); + $pdf->setSignatureAppearance($this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height); + } + } + + /** + * Sets the data on the form when editing an element. + * + * @param \mod_customcert\edit_element_form $mform the edit_form instance + */ + public function definition_after_data($mform) { + global $COURSE, $SITE; + + // Set the context. + if ($COURSE->id == $SITE->id) { + $context = \context_system::instance(); + } else { + $context = \context_course::instance($COURSE->id); + } + + if (!empty($this->get_data())) { + $imageinfo = json_decode($this->get_data()); + + $element = $mform->getElement('signaturename'); + $element->setValue($imageinfo->signaturename); + + $element = $mform->getElement('signaturepassword'); + $element->setValue($imageinfo->signaturepassword); + + $element = $mform->getElement('signaturelocation'); + $element->setValue($imageinfo->signaturelocation); + + $element = $mform->getElement('signaturereason'); + $element->setValue($imageinfo->signaturereason); + + $element = $mform->getElement('signaturecontactinfo'); + $element->setValue($imageinfo->signaturecontactinfo); + + if (!empty($imageinfo->signaturefilename)) { + if ($signaturefile = $this->get_signature_file()) { + $element = $mform->getElement('signaturefileid'); + $element->setValue($signaturefile->get_id()); + } + } + } + + // Editing existing instance - copy existing files into draft area. + $draftitemid = file_get_submitted_draft_itemid('digitalsignature'); + file_prepare_draft_area($draftitemid, $context->id, 'mod_customcert', 'signature', 0, + $this->signaturefilemanageroptions); + $element = $mform->getElement('digitalsignature'); + $element->setValue($draftitemid); + + parent::definition_after_data($mform); + } + + /** + * Return the list of possible images to use. + * + * @return array the list of images that can be used + */ + public static function get_signatures() { + global $COURSE; + + // Create file storage object. + $fs = get_file_storage(); + + // The array used to store the digital signatures. + $arrfiles = array(); + // Loop through the files uploaded in the system context. + if ($files = $fs->get_area_files(\context_system::instance()->id, 'mod_customcert', 'signature', false, + 'filename', false)) { + foreach ($files as $hash => $file) { + $arrfiles[$file->get_id()] = $file->get_filename(); + } + } + // Loop through the files uploaded in the course context. + if ($files = $fs->get_area_files(\context_course::instance($COURSE->id)->id, 'mod_customcert', 'signature', false, + 'filename', false)) { + foreach ($files as $hash => $file) { + $arrfiles[$file->get_id()] = $file->get_filename(); + } + } + + \core_collator::asort($arrfiles); + $arrfiles = array('0' => get_string('nosignature', 'customcertelement_digitalsignature')) + $arrfiles; + + return $arrfiles; + } + + /** + * Fetch stored file. + * + * @return \stored_file|bool stored_file instance if exists, false if not + */ + public function get_signature_file() { + $imageinfo = json_decode($this->get_data()); + + $fs = get_file_storage(); + + return $fs->get_file($imageinfo->signaturecontextid, 'mod_customcert', $imageinfo->signaturefilearea, + $imageinfo->signatureitemid, $imageinfo->signaturefilepath, $imageinfo->signaturefilename); + } +} diff --git a/element/digitalsignature/lang/en/customcertelement_digitalsignature.php b/element/digitalsignature/lang/en/customcertelement_digitalsignature.php new file mode 100644 index 0000000..79a51cd --- /dev/null +++ b/element/digitalsignature/lang/en/customcertelement_digitalsignature.php @@ -0,0 +1,33 @@ +. + +/** + * Strings for component 'customcertelement_digitalsignature', language 'en'. + * + * @package customcertelement_digitalsignature + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['digitalsignature'] = 'Digital signature'; +$string['nosignature'] = 'No signature'; +$string['pluginname'] = 'Digital signature'; +$string['signaturename'] = 'Signature name'; +$string['signaturepassword'] = 'Signature password'; +$string['signaturelocation'] = 'Signature location'; +$string['signaturereason'] = 'Signature reason'; +$string['signaturecontactinfo'] = 'Signature contact info'; +$string['uploaddigitalsignature'] = 'Upload digital signature'; diff --git a/element/digitalsignature/version.php b/element/digitalsignature/version.php new file mode 100644 index 0000000..b7366e2 --- /dev/null +++ b/element/digitalsignature/version.php @@ -0,0 +1,29 @@ +. + +/** + * This file contains the version information for the digital signature plugin. + * + * @package customcertelement_digitalsignature + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); + +$plugin->version = 2016052300; // The current module version (Date: YYYYMMDDXX). +$plugin->requires = 2016052300; // Requires this Moodle version (3.1). +$plugin->component = 'customcertelement_digitalsignature'; diff --git a/element/image/classes/element.php b/element/image/classes/element.php index 6025b83..8261bb8 100644 --- a/element/image/classes/element.php +++ b/element/image/classes/element.php @@ -130,7 +130,7 @@ class element extends \mod_customcert\element { } // Handle file uploads. - \mod_customcert\certificate::upload_imagefiles($data->customcertimage, $context->id); + \mod_customcert\certificate::upload_files($data->customcertimage, $context->id); return parent::save_form_elements($data); } diff --git a/tests/behat/managing_elements.feature b/tests/behat/managing_elements.feature index 56db814..f2fe4b8 100644 --- a/tests/behat/managing_elements.feature +++ b/tests/behat/managing_elements.feature @@ -119,6 +119,28 @@ Feature: Being able to manage elements in a certificate template | Width | 20 | | Reference point location | Top left | And I press "Save changes" + # Digital signature. + And I add the element "Digital signature" to page "1" of the "Custom certificate 1" certificate template + And I set the following fields to these values: + | Signature name | This is the signature name | + | Signature password | Some awesome password | + | Signature location | Mordor | + | Signature reason | Meh, felt like it. | + | Signature contact info | Sauron | + | Width | 25 | + | Height | 15 | + And I press "Save changes" + And I should see "Digital signature" in the "elementstable" "table" + And I click on ".edit-icon" "css_element" in the "Digital signature" "table_row" + And the following fields match these values: + | Signature name | This is the signature name | + | Signature password | Some awesome password | + | Signature location | Mordor | + | Signature reason | Meh, felt like it. | + | Signature contact info | Sauron | + | Width | 25 | + | Height | 15 | + And I press "Save changes" # Grade. And I add the element "Grade" to page "1" of the "Custom certificate 1" certificate template And I set the following fields to these values: diff --git a/upload_image.php b/upload_image.php index 93f359a..fb1832b 100644 --- a/upload_image.php +++ b/upload_image.php @@ -44,7 +44,7 @@ if ($uploadform->is_cancelled()) { redirect(new moodle_url('/admin/settings.php?section=modsettingcustomcert')); } else if ($data = $uploadform->get_data()) { // Handle file uploads. - \mod_customcert\certificate::upload_imagefiles($data->customcertimage, $context->id); + \mod_customcert\certificate::upload_files($data->customcertimage, $context->id); redirect(new moodle_url('/mod/customcert/upload_image.php'), get_string('changessaved')); }