├── .gitignore ├── pix ├── icon.gif ├── icon.png ├── qrcode.png ├── target.gif ├── download.png ├── signature.png ├── background.jpg ├── brokenfile.png ├── download.svg └── icon.svg ├── db ├── subplugins.json ├── events.php ├── install.php ├── messages.php ├── access.php └── services.php ├── element ├── border │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── lang │ │ └── en │ │ │ └── certificateelement_border.php │ ├── version.php │ ├── classes │ │ └── privacy │ │ │ └── provider.php │ └── tests │ │ └── element_test.php ├── code │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── version.php │ ├── lang │ │ └── en │ │ │ └── certificateelement_code.php │ └── classes │ │ └── privacy │ │ └── provider.php ├── date │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── version.php │ ├── lang │ │ └── en │ │ │ └── certificateelement_date.php │ └── classes │ │ └── privacy │ │ └── provider.php ├── image │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── db │ │ └── upgrade.php │ ├── version.php │ ├── classes │ │ └── privacy │ │ │ └── provider.php │ ├── lang │ │ └── en │ │ │ └── certificateelement_image.php │ └── tests │ │ └── element_test.php ├── text │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── lang │ │ └── en │ │ │ └── certificateelement_text.php │ ├── version.php │ └── classes │ │ └── privacy │ │ └── provider.php ├── program │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── version.php │ ├── lang │ │ └── en │ │ │ └── certificateelement_program.php │ └── classes │ │ └── privacy │ │ └── provider.php ├── userfield │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── lang │ │ └── en │ │ │ └── certificateelement_userfield.php │ ├── version.php │ └── classes │ │ └── privacy │ │ └── provider.php ├── userpicture │ ├── pix │ │ ├── icon.png │ │ └── icon.svg │ ├── version.php │ ├── lang │ │ └── en │ │ │ └── certificateelement_userpicture.php │ └── classes │ │ └── privacy │ │ └── provider.php └── digitalsignature │ ├── pix │ ├── icon.png │ └── icon.svg │ ├── version.php │ ├── classes │ └── privacy │ │ └── provider.php │ ├── lang │ └── en │ │ └── certificateelement_digitalsignature.php │ └── tests │ └── element_test.php ├── CHANGELOG.md ├── amd └── build │ ├── form-potential-user-selector.min.js │ ├── issues-list.min.js │ └── templates-list.min.js ├── tests ├── behat │ ├── my_certificates.feature │ ├── show_position_x_y.feature │ ├── view_certificate.feature │ ├── adminmanageplugins.feature │ ├── verify_certificates.feature │ ├── managing_pages.feature │ └── admin_tree.feature ├── fixtures │ └── signature.crt ├── element_factory_test.php └── observer_test.php ├── my_certificates.php ├── version.php ├── templates ├── content_with_heading.mustache ├── verify_certificate_results.mustache ├── page_header_button.mustache ├── form-user-selector-suggestion.mustache ├── content_heading.mustache ├── verify_certificate_result.mustache ├── edit_layout.mustache ├── edit_layout_elementlist.mustache └── edit_layout_pdf.mustache ├── adminmanageplugins.php ├── customfield.php ├── classes ├── output │ ├── email │ │ ├── renderer.php │ │ └── renderer_textemail.php │ ├── renderer.php │ ├── page_header_button.php │ └── verify_certificate_results.php ├── persistent │ ├── template.php │ └── page.php ├── tool_tenant.php ├── verify_certificate_form.php ├── observer.php ├── admin_externalpage.php ├── upload_image_form.php ├── event │ ├── template_deleted.php │ ├── template_created.php │ ├── template_updated.php │ ├── certificate_issued.php │ ├── certificate_revoked.php │ └── certificate_verified.php └── plugininfo │ └── certificateelement.php ├── upload_image.php ├── adminlib.php ├── README.md ├── index.php ├── view.php ├── manage_templates.php ├── my.php ├── styles.css ├── settings.php ├── certificates.php ├── includes └── colourpicker.php └── template.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | phpunit.xml 3 | -------------------------------------------------------------------------------- /pix/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/icon.gif -------------------------------------------------------------------------------- /pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/icon.png -------------------------------------------------------------------------------- /pix/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/qrcode.png -------------------------------------------------------------------------------- /pix/target.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/target.gif -------------------------------------------------------------------------------- /pix/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/download.png -------------------------------------------------------------------------------- /pix/signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/signature.png -------------------------------------------------------------------------------- /pix/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/background.jpg -------------------------------------------------------------------------------- /pix/brokenfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/pix/brokenfile.png -------------------------------------------------------------------------------- /db/subplugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugintypes": { 3 | "certificateelement": "admin\/tool\/certificate\/element" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /element/border/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/border/pix/icon.png -------------------------------------------------------------------------------- /element/code/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/code/pix/icon.png -------------------------------------------------------------------------------- /element/date/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/date/pix/icon.png -------------------------------------------------------------------------------- /element/image/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/image/pix/icon.png -------------------------------------------------------------------------------- /element/text/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/text/pix/icon.png -------------------------------------------------------------------------------- /element/program/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/program/pix/icon.png -------------------------------------------------------------------------------- /element/userfield/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/userfield/pix/icon.png -------------------------------------------------------------------------------- /element/userpicture/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/userpicture/pix/icon.png -------------------------------------------------------------------------------- /element/digitalsignature/pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/moodle-tool_certificate/master/element/digitalsignature/pix/icon.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.10.1 (2021011900) 4 | ### Changed 5 | - Fixed issue when moving/deleting categories that contained certificates. All pages/elements 6 | and issued certificates are now handled correctly 7 | 8 | ## 3.10+ (2020121700) 9 | ### Changed 10 | - Fixed a bug in how a 'Text area' course custom field is handled in the certificate templates 11 | - Fixed occasional double modal popups when editing templates 12 | - Small visual fixes in the template editing UI 13 | 14 | ## Previous versions 15 | Changelog was not maintained before version 3.10 16 | -------------------------------------------------------------------------------- /pix/download.svg: -------------------------------------------------------------------------------- 1 | 3 | ]> -------------------------------------------------------------------------------- /element/digitalsignature/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 11 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /element/code/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /element/userpicture/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /amd/build/form-potential-user-selector.min.js: -------------------------------------------------------------------------------- 1 | define ("tool_certificate/form-potential-user-selector",["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){return{processResults:function processResults(b,c){var d=[];if(a.isArray(c)){a.each(c,function(a,b){d.push({value:b.id,label:b._label})});return d}else{return c}},transport:function transport(e,f,g,h){var i=b.call([{methodname:"tool_certificate_potential_users_selector",args:{search:f,itemid:a(e).data("itemid")}}]);i[0].then(function(b){var e=[],f=0;if(b.length<=100){a.each(b,function(b,d){var f=d,g=[];a.each(["idnumber","email","phone1","phone2","department","institution"],function(a,b){if("undefined"!=typeof d[b]&&""!==d[b]){f.hasidentity=!0;g.push(d[b])}});f.identity=g.join(", ");e.push(c.render("tool_certificate/form-user-selector-suggestion",f))});return a.when.apply(a.when,e).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[f];f++});g(b)})}else{return d.get_string("toomanyuserstoshow","core",">100").then(function(a){g(a)})}}).fail(h)}}}); 2 | //# sourceMappingURL=form-potential-user-selector.min.js.map 3 | -------------------------------------------------------------------------------- /element/program/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 15 | 16 | -------------------------------------------------------------------------------- /pix/icon.svg: -------------------------------------------------------------------------------- 1 | Asset 23 -------------------------------------------------------------------------------- /tests/behat/my_certificates.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace 2 | Feature: Being able to view the certificates you have been issued 3 | In order to ensure that a user can view the certificates they have been issued 4 | As a student 5 | I need to view the certificates I have been issued 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | | manager1 | Manager | 1 | manager1@example.com | 12 | And the following certificate templates exist: 13 | | name | 14 | | Certificate 1 | 15 | | Certificate 2 | 16 | And the following certificate issues exist: 17 | | template | user | 18 | | Certificate 1 | student1 | 19 | 20 | Scenario: View your issued site certificates on the my certificates page 21 | When I log in as "student1" 22 | And I follow "Profile" in the user menu 23 | And I click on "//a[contains(.,'My certificates') and contains(@href,'tool/certificate')]" "xpath_element" 24 | Then I should see "Certificate 1" 25 | And I should not see "Certificate 2" 26 | -------------------------------------------------------------------------------- /element/image/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 15 | 16 | -------------------------------------------------------------------------------- /my_certificates.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Handles viewing the certificates for a certain user. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2016 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | 27 | $userid = optional_param('userid', 0, PARAM_INT); 28 | $pageurl = $url = new moodle_url('/admin/tool/certificate/my.php', ['userid' => $userid]); 29 | 30 | require_login(); 31 | redirect($pageurl); -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Code fragment to define the version of the certificate tool 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $plugin->component = 'tool_certificate'; 28 | $plugin->release = '3.10.1'; 29 | $plugin->version = 2021011900; 30 | $plugin->requires = 2020061502.00; 31 | $plugin->maturity = MATURITY_STABLE; 32 | -------------------------------------------------------------------------------- /db/events.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Events for tool_certificate. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2020 Moodle Pty Ltd 22 | * @author 2020 Mikel Martín 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die; 27 | 28 | $observers = [ 29 | [ 30 | 'eventname' => '\core\event\course_content_deleted', 31 | 'callback' => tool_certificate_observer::class . '::on_course_content_deleted' 32 | ], 33 | ]; -------------------------------------------------------------------------------- /element/text/lang/en/certificateelement_text.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_text', language 'en'. 19 | * 20 | * @package certificateelement_text 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['pluginname'] = 'Text'; 26 | $string['privacy:metadata'] = 'The Text plugin does not store any personal data.'; 27 | $string['text'] = 'Text'; 28 | $string['text_help'] = 'This is the text that will display on the PDF.'; 29 | -------------------------------------------------------------------------------- /templates/content_with_heading.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/content_with_heading 19 | 20 | Page with heading and content 21 | 22 | Classes required for JS: 23 | 24 | Data attibutes required for JS: 25 | 26 | Context variables required for this template: 27 | 28 | Example context (json): 29 | { 30 | "addbuttontitle": "New item", 31 | "addbuttonurl": "#", 32 | "content": "

Here goes content...

" 33 | } 34 | }} 35 | {{> tool_certificate/content_heading }} 36 | {{{content}}} -------------------------------------------------------------------------------- /element/userfield/lang/en/certificateelement_userfield.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_userfield', language 'en'. 19 | * 20 | * @package certificateelement_userfield 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['pluginname'] = 'User field'; 26 | $string['privacy:metadata'] = 'The User field plugin does not store any personal data.'; 27 | $string['userfield'] = 'User field'; 28 | $string['userfield_help'] = 'This is the user field that will be displayed on the PDF.'; 29 | -------------------------------------------------------------------------------- /element/image/db/upgrade.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Customcert image element upgrade code. 19 | * 20 | * @package certificateelement_image 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die; 26 | 27 | /** 28 | * Customcert image element upgrade code. 29 | * 30 | * @param int $oldversion the version we are upgrading from 31 | * @return bool always true 32 | */ 33 | function xmldb_certificateelement_image_upgrade($oldversion) { 34 | global $DB; 35 | 36 | return true; 37 | } 38 | -------------------------------------------------------------------------------- /tests/behat/show_position_x_y.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace @javascript 2 | Feature: Being able to set a site setting to determine whether or not to display the position X and Y fields 3 | In order to ensure the show position X and Y fields setting works as expected 4 | As an admin 5 | I need to ensure admins can see the position X and Y fields depending on the site setting 6 | 7 | Background: 8 | Given the following certificate templates exist: 9 | | name | numberofpages | 10 | | Certificate 1 | 1 | 11 | 12 | Scenario: Adding an element with the show position X and Y setting enabled 13 | When I log in as "admin" 14 | And I navigate to "Certificates > Manage certificate templates" in site administration 15 | And I click on "Edit content" "link" 16 | And I add the element "Code" to page "1" of the "Certificate 1" site certificate template 17 | And I follow "Show more..." 18 | And I should see "Position X" 19 | And I should see "Position Y" 20 | And I set the following fields to these values: 21 | | Position X | 5 | 22 | | Position Y | 10 | 23 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 24 | And I click on "Edit 'Code'" "link" in the "Code" "list_item" 25 | And the following fields match these values: 26 | | Position X | 5 | 27 | | Position Y | 10 | 28 | -------------------------------------------------------------------------------- /element/code/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the code plugin. 19 | * 20 | * @package certificateelement_code 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_code'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/date/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the date plugin. 19 | * 20 | * @package certificateelement_date 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_date'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/image/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the image plugin. 19 | * 20 | * @package certificateelement_image 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_image'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/text/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the text plugin. 19 | * 20 | * @package certificateelement_text 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_text'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/border/lang/en/certificateelement_border.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_border', language 'en'. 19 | * 20 | * @package certificateelement_border 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['invalidwidth'] = 'The width has to be a valid number greater than 0.'; 26 | $string['pluginname'] = 'Border'; 27 | $string['privacy:metadata'] = 'The Border plugin does not store any personal data.'; 28 | $string['width'] = 'Width'; 29 | $string['width_help'] = 'Width of the border in mm.'; 30 | -------------------------------------------------------------------------------- /element/border/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the border plugin. 19 | * 20 | * @package certificateelement_border 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_border'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/program/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the program element. 19 | * 20 | * @package certificateelement_program 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_program'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/userfield/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the userfield plugin. 19 | * 20 | * @package certificateelement_userfield 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_userfield'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/userpicture/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the userpicture plugin. 19 | * 20 | * @package certificateelement_userpicture 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_userpicture'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /element/digitalsignature/version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the version information for the digital signature plugin. 19 | * 20 | * @package certificateelement_digitalsignature 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | // This plugin is part of Moodle Workplace product. 28 | $plugin->component = 'certificateelement_digitalsignature'; 29 | $plugin->release = '3.10.1'; 30 | $plugin->version = 2021011900; 31 | $plugin->requires = 2020061502.00; 32 | $plugin->maturity = MATURITY_STABLE; 33 | -------------------------------------------------------------------------------- /templates/verify_certificate_results.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/verify_certificate_results 19 | 20 | The certificate verification results page 21 | 22 | Classes required for JS: 23 | * None 24 | 25 | Data attibutes required for JS: 26 | * All data attributes are required 27 | 28 | Context variables required for this template: 29 | * None 30 | 31 | Example context (json): 32 | { 33 | } 34 | }} 35 | {{#success}} 36 | {{#issue}} 37 | {{> tool_certificate/verify_certificate_result }} 38 | {{/issue}} 39 | {{/success}} 40 | {{^success}} 41 | {{> core/notification_error}} 42 | {{/success}} 43 | -------------------------------------------------------------------------------- /element/program/lang/en/certificateelement_program.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_program', language 'en'. 19 | * 20 | * @package certificateelement_program 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['fieldoptions'] = 'Field'; 26 | $string['fieldoptions_help'] = 'The field to be displayed. If you need to display more than one field, add more instances of this element and configure accordingly.'; 27 | $string['pluginname'] = 'Dynamic fields'; 28 | $string['privacy:metadata'] = 'The dynamic fields plugin does not store any personal data.'; 29 | -------------------------------------------------------------------------------- /element/date/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 18 | 19 | -------------------------------------------------------------------------------- /db/install.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * tool_certificate installation script 19 | * 20 | * @package tool_certificate 21 | * @copyright 2020 Moodle Pty Ltd 22 | * @author 2020 Mikel Martín 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Create a default certificate template. 30 | * 31 | * @return bool 32 | */ 33 | function xmldb_tool_certificate_install() { 34 | if (!defined('BEHAT_SITE_RUNNING') && !(defined('PHPUNIT_TEST') && PHPUNIT_TEST)) { 35 | \tool_certificate\certificate::create_demo_template(); 36 | } 37 | 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /db/messages.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Defines message providers (types of messages being sent) 19 | * 20 | * @package tool_certificate 21 | * @copyright 2020 Mikel Martín 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $messageproviders = [ 29 | // Notification for certificate issued. 30 | 'certificateissued' => [ 31 | 'defaults' => [ 32 | 'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF, 33 | 'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF, 34 | ], 35 | ], 36 | ]; 37 | -------------------------------------------------------------------------------- /templates/page_header_button.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/page_header_button 19 | 20 | Button to display in the page heading 21 | 22 | Classes required for JS: 23 | 24 | Data attibutes required for JS: 25 | 26 | Context variables required for this template: 27 | 28 | Example context (json): 29 | { 30 | "title": "Edit details", 31 | "class": "", 32 | "attributes": [ 33 | {"name": "data-id", "value": 0} 34 | ] 35 | } 36 | }} 37 |
38 | 39 |
-------------------------------------------------------------------------------- /templates/form-user-selector-suggestion.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/form-user-selector-suggestion 19 | 20 | Template for showing a user suggestion in user selector list 21 | 22 | Example context (json): 23 | { 24 | "profileimageurlsmall": "https://raw.githubusercontent.com/moodle/moodle/master/pix/g/f1.png", 25 | "fullname": "John Smith", 26 | "hasidentity": "1", 27 | "identity": "john@smith.com" 28 | } 29 | }} 30 | 31 | 32 | {{fullname}} 33 | {{#hasidentity}} 34 | {{identity}} 35 | {{/hasidentity}} 36 | 37 | -------------------------------------------------------------------------------- /adminmanageplugins.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Allows the admin to manage assignment plugins 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once(__DIR__ . '/../../../config.php'); 26 | 27 | $action = optional_param('action', null, PARAM_PLUGIN); 28 | $plugin = optional_param('plugin', null, PARAM_PLUGIN); 29 | 30 | if (!empty($plugin)) { 31 | require_sesskey(); 32 | } 33 | 34 | $pluginmanager = new \tool_certificate\plugin_manager(); 35 | 36 | \admin_externalpage_setup('tool_certificate_manageelementplugins'); 37 | 38 | $pluginmanager->execute($action, $plugin); 39 | -------------------------------------------------------------------------------- /element/date/lang/en/certificateelement_date.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_date', language 'en'. 19 | * 20 | * @package certificateelement_date 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['dateformat'] = 'Date format'; 26 | $string['dateformat_help'] = 'This is the format of the date that will be displayed'; 27 | $string['dateitem'] = 'Date item'; 28 | $string['dateitem_help'] = 'This will be the date that is printed on the certificate'; 29 | $string['expirydate'] = 'Expiry date'; 30 | $string['issueddate'] = 'Issued date'; 31 | $string['pluginname'] = 'Date'; 32 | $string['privacy:metadata'] = 'The Date plugin does not store any personal data.'; 33 | -------------------------------------------------------------------------------- /customfield.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage course custom fields 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | require_once($CFG->libdir.'/adminlib.php'); 27 | 28 | admin_externalpage_setup('tool_certificate_customfield'); 29 | 30 | $output = $PAGE->get_renderer('core_customfield'); 31 | $handler = \tool_certificate\customfield\issue_handler::create(); 32 | $handler->create_custom_fields_if_not_exist(); 33 | $outputpage = new \core_customfield\output\management($handler); 34 | 35 | echo $output->header(), 36 | $output->heading(new lang_string('certificate_customfield', 'tool_certificate')), 37 | $output->render($outputpage), 38 | $output->footer(); 39 | -------------------------------------------------------------------------------- /tests/behat/view_certificate.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace 2 | Feature: Being able to download valid certificates 3 | In order to ensure that a user can download a valid certificate 4 | As an admin and non-user 5 | I need to be able to download a certificate 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Teacher | 1 | teacher1@example.com | 11 | | student1 | Student | 1 | student1@example.com | 12 | And the following certificate templates exist: 13 | | name | 14 | | Certificate 1 | 15 | | Certificate 2 | 16 | And the following certificate issues exist: 17 | | template | user | 18 | | Certificate 1 | student1 | 19 | 20 | Scenario: Download a certificate as admin 21 | When I log in as "admin" 22 | And I visit the sites certificates verification url 23 | And I verify the "Certificate 1" site certificate for the user "student1" 24 | And I click on "View certificate" "link" 25 | 26 | Scenario: Verify a certificate as a guest using the site-wide URL 27 | And the following "permission overrides" exist: 28 | | capability | permission | role | contextlevel | reference | 29 | | tool/certificate:verify | Allow | guest | System | | 30 | And I log in as "guest" 31 | And I visit the sites certificates verification url 32 | And I verify the "Certificate 1" site certificate for the user "student1" 33 | And I click on "View certificate" "link" 34 | -------------------------------------------------------------------------------- /tests/behat/adminmanageplugins.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace 2 | Feature: Manage certificate elements plugins 3 | In order to manage certificate elements plugins 4 | As a manager 5 | I need to be able to view, hide/show, reorder and unistall element plugins 6 | 7 | Scenario: View default element plugins 8 | When I log in as "admin" 9 | And I navigate to "Plugins > Admin tools > Manage certificate element plugins" in site administration 10 | Then I should see "Border" 11 | And I should see "Code" 12 | And I should see "Date" 13 | And I should see "Digital signature" 14 | And I should see "Image" 15 | And I should see "Dynamic fields" 16 | And I should see "Text" 17 | And I should see "User field" 18 | And I should see "User picture" 19 | 20 | Scenario: Uninstall an element plugin 21 | When I log in as "admin" 22 | And I navigate to "Plugins > Admin tools > Manage certificate element plugins" in site administration 23 | And I click on "Uninstall" "link" in the "User field" "table_row" 24 | And I press "Continue" 25 | Then I should see "Success" 26 | 27 | Scenario: Disable and enable an element plugin 28 | When I log in as "admin" 29 | And I navigate to "Plugins > Admin tools > Manage certificate element plugins" in site administration 30 | And I click on "Disable" "link" in the "User field" "table_row" 31 | Then "Enable" "link" should exist in the "User field" "table_row" 32 | And I click on "Enable" "link" in the "User field" "table_row" 33 | Then "Disable" "link" should exist in the "User field" "table_row" 34 | -------------------------------------------------------------------------------- /classes/output/email/renderer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Email certificate as html renderer. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\output\email; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Email certificate as html renderer. 31 | * 32 | * @package tool_certificate 33 | * @copyright 2017 Mark Nelson 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class renderer extends \tool_certificate\output\renderer { 37 | 38 | /** 39 | * The template name for this renderer. 40 | * 41 | * @return string 42 | */ 43 | public function get_template_name() { 44 | return 'email_certificate_html'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classes/output/email/renderer_textemail.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Email certificate as text renderer. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\output\email; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Email certificate as text renderer. 31 | * 32 | * @package tool_certificate 33 | * @copyright 2017 Mark Nelson 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class renderer_textemail extends \tool_certificate\output\renderer { 37 | 38 | /** 39 | * The template name for this renderer. 40 | * 41 | * @return string 42 | */ 43 | public function get_template_name() { 44 | return 'email_certificate_text'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/userpicture/lang/en/certificateelement_userpicture.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_userpicture', language 'en'. 19 | * 20 | * @package certificateelement_userpicture 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['height'] = 'Height'; 26 | $string['height_help'] = 'Height of the image in mm. If equal to zero, it is automatically calculated.'; 27 | $string['invalidheight'] = 'The height has to be a valid number greater than or equal to 0.'; 28 | $string['invalidwidth'] = 'The width has to be a valid number greater than or equal to 0.'; 29 | $string['pluginname'] = 'User picture'; 30 | $string['privacy:metadata'] = 'The User picture plugin does not store any personal data.'; 31 | $string['width'] = 'Width'; 32 | $string['width_help'] = 'Width of the image in mm. If equal to zero, it is automatically calculated.'; 33 | -------------------------------------------------------------------------------- /element/code/lang/en/certificateelement_code.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_code', language 'en'. 19 | * 20 | * @package certificateelement_code 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['display'] = 'Display'; 26 | $string['display_help'] = 'How to display the code: 27 | 28 | * Code only (default): will display only the code to verify the certificate 29 | * Code and link: will display a link to the verfication page 30 | * URL: will display the verification URL as text (usually for printed certificates where it is not possible to click a link)'; 31 | $string['displaycode'] = 'Code only'; 32 | $string['displaycodelink'] = 'Code with link'; 33 | $string['displayqrcode'] = 'QR Code'; 34 | $string['displayurl'] = 'Verification URL'; 35 | $string['pluginname'] = 'Code'; 36 | $string['privacy:metadata'] = 'The Code plugin does not store any personal data.'; 37 | -------------------------------------------------------------------------------- /element/code/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_code. 19 | * 20 | * @package certificateelement_code 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_code\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_code implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/date/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_date. 19 | * 20 | * @package certificateelement_date 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_date\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_date implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/text/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_text. 19 | * 20 | * @package certificateelement_text 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_text\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_text implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/image/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_image. 19 | * 20 | * @package certificateelement_image 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_image\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_image implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/border/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_border. 19 | * 20 | * @package certificateelement_border 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_border\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_border implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /upload_image.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Handles uploading files 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require('../../../config.php'); 26 | require_once($CFG->libdir.'/adminlib.php'); 27 | 28 | admin_externalpage_setup('tool_certificate/images'); 29 | 30 | $uploadform = new \tool_certificate\upload_image_form(); 31 | 32 | if ($uploadform->is_cancelled()) { 33 | redirect(new moodle_url('/admin/tool/certificate/manage_templates.php')); 34 | } else if ($data = $uploadform->get_data()) { 35 | // Handle file uploads. 36 | \tool_certificate\certificate::upload_files($data->certificateimage, \context_system::instance()->id); 37 | 38 | redirect(new moodle_url('/admin/tool/certificate/upload_image.php'), get_string('changessaved')); 39 | } 40 | 41 | $PAGE->set_heading(get_string('certificateimages', 'tool_certificate')); 42 | echo $OUTPUT->header(); 43 | $uploadform->display(); 44 | echo $OUTPUT->footer(); 45 | -------------------------------------------------------------------------------- /element/userfield/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_userfield. 19 | * 20 | * @package certificateelement_userfield 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_userfield\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_userfield implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/userpicture/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_userpicture. 19 | * 20 | * @package certificateelement_userpicture 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_userpicture\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_userpicture implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/digitalsignature/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_digitalsignature. 19 | * 20 | * @package certificateelement_digitalsignature 21 | * @copyright 2018 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_digitalsignature\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_digitalsignature implementing null_provider. 31 | * 32 | * @copyright 2018 Mark Nelson 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class provider implements \core_privacy\local\metadata\null_provider { 36 | 37 | /** 38 | * Get the language string identifier with the component's language 39 | * file to explain why this plugin stores no data. 40 | * 41 | * @return string 42 | */ 43 | public static function get_reason() : string { 44 | return 'privacy:metadata'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /adminlib.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the classes for the admin settings of the certificate module. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | require_once($CFG->libdir . '/adminlib.php'); 28 | 29 | /** 30 | * Admin page to manage element plugins 31 | * 32 | * @package tool_certificate 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_admin_page_manage_element_plugins extends admin_externalpage { 37 | 38 | /** 39 | * The constructor - calls parent constructor 40 | * 41 | */ 42 | public function __construct() { 43 | $url = new moodle_url('/admin/tool/certificate/adminmanageplugins.php'); 44 | parent::__construct('tool_certificate_manageelementplugins', get_string('manageelementplugins', 'tool_certificate'), $url); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /element/program/classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for certificateelement_program. 19 | * 20 | * @package certificateelement_program 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace certificateelement_program\privacy; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Privacy Subsystem for certificateelement_program implementing null_provider. 31 | * 32 | * @package certificateelement_program 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class provider implements \core_privacy\local\metadata\null_provider { 37 | 38 | /** 39 | * Get the language string identifier with the component's language 40 | * file to explain why this plugin stores no data. 41 | * 42 | * @return string 43 | */ 44 | public static function get_reason() : string { 45 | return 'privacy:metadata'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /element/image/lang/en/certificateelement_image.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_image', language 'en'. 19 | * 20 | * @package certificateelement_image 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['height'] = 'Height'; 26 | $string['height_help'] = 'Height of the image in mm. If equal to zero, it is automatically calculated.'; 27 | $string['imagerequired'] = 'You must either upload an image or select a shared image'; 28 | $string['invalidheight'] = 'The height has to be a valid number greater than or equal to 0.'; 29 | $string['invalidwidth'] = 'The width has to be a valid number greater than or equal to 0.'; 30 | $string['isbackground'] = 'Use as a background image'; 31 | $string['pluginname'] = 'Image'; 32 | $string['privacy:metadata'] = 'The Image plugin does not store any personal data.'; 33 | $string['selectsharedimage'] = 'Select shared image'; 34 | $string['width'] = 'Width'; 35 | $string['width_help'] = 'Width of the image in mm. If equal to zero, it is automatically calculated.'; 36 | -------------------------------------------------------------------------------- /templates/content_heading.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/tab_heading 19 | 20 | Template for showing content heading 21 | 22 | Example context (json): 23 | { 24 | "addbutton": true, 25 | "addbuttontitle": "Add", 26 | "addbuttonicon": true, 27 | "addbuttonurl": "", 28 | "addbuttonclasses": ["disabled", "p-3"], 29 | "addbuttonattrs": [{"name": "data-foo", "value": "bar"}] 30 | } 31 | }} 32 |
33 | {{#addbutton}} 34 | 37 | {{#addbuttonicon}}{{#pix}}t/add, core{{/pix}}{{/addbuttonicon}}{{#addbuttontitle}}{{addbuttontitle}}{{/addbuttontitle}} 38 | 39 | {{/addbutton}} 40 | {{#heading}} 41 |

{{{heading}}}

42 | {{/heading}} 43 |
44 |
45 | -------------------------------------------------------------------------------- /element/userfield/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /classes/persistent/template.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class template 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\persistent; 26 | 27 | use core\persistent; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * Class template 33 | * 34 | * @package tool_certificate 35 | * @copyright 2019 Marina Glancy 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class template extends persistent { 39 | 40 | /** @var string */ 41 | const TABLE = 'tool_certificate_templates'; 42 | 43 | /** 44 | * Return the definition of the properties of this model. 45 | * 46 | * @return array 47 | */ 48 | protected static function define_properties() { 49 | return array( 50 | 'name' => array( 51 | 'type' => PARAM_TEXT 52 | ), 53 | 'contextid' => array( 54 | 'type' => PARAM_INT 55 | ), 56 | 'shared' => array( 57 | 'type' => PARAM_BOOL 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /classes/tool_tenant.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Implementation of multi-tenancy (used only by plugin tool_tenant and nothing else) 19 | * 20 | * @package tool_certificate 21 | * @copyright 2020 Moodle Pty Ltd 22 | * @author 2020 Marina Glancy 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | namespace tool_certificate; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | /** 31 | * Implementation of multi-tenancy (used only by plugin tool_tenant and nothing else) 32 | * 33 | * @package tool_certificate 34 | * @copyright 2020 Moodle Pty Ltd 35 | * @author 2020 Marina Glancy 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class tool_tenant { 39 | 40 | /** 41 | * Callback used by tool_tenant to see which capabilities from this plugin are allowed for the "Tenant administrator" role 42 | * 43 | * @return array 44 | */ 45 | public static function get_tenant_admin_capabilities() { 46 | return [ 47 | 'tool/certificate:issue' => CAP_ALLOW, 48 | 'tool/certificate:viewallcertificates' => CAP_ALLOW, 49 | ]; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /classes/verify_certificate_form.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This files contains the form for verifying a certificate. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate; 26 | 27 | defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); 28 | 29 | require_once($CFG->libdir . '/formslib.php'); 30 | 31 | /** 32 | * The form for verifying a certificate. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2017 Mark Nelson 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class verify_certificate_form extends \moodleform { 39 | 40 | /** 41 | * Form definition. 42 | */ 43 | public function definition() { 44 | $mform =& $this->_form; 45 | 46 | $mform->addElement('text', 'code', get_string('code', 'tool_certificate')); 47 | $mform->setType('code', PARAM_ALPHANUM); 48 | $mform->addRule('code', null, 'required', null, 'client'); 49 | 50 | $mform->addElement('submit', 'verify', get_string('verify', 'tool_certificate')); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /amd/build/issues-list.min.js: -------------------------------------------------------------------------------- 1 | define ("tool_certificate/issues-list",["jquery","tool_certificate/modal_form","core/notification","core/str","core/ajax","core/toast"],function(a,b,c,d,f,g){var h={ADDISSUE:"[data-element='addbutton']",REGENERATEFILE:"[data-action='regenerate']",REVOKEISSUE:"[data-action='revoke']"},i=function(c){c.preventDefault();var e=new b({formClass:"tool_certificate\\form\\certificate_issues",args:{tid:a(c.currentTarget).attr("data-tid")},modalConfig:{title:d.get_string("issuecertificates","tool_certificate"),scrollable:!1},saveButtonText:d.get_string("save"),triggerElement:a(c.currentTarget)});e.onSubmitSuccess=function(a){a=parseInt(a,10);if(a){d.get_strings([{key:"oneissuewascreated",component:"tool_certificate"},{key:"aissueswerecreated",component:"tool_certificate",param:a}]).done(function(b){var c=1. 16 | }} 17 | {{! 18 | @template tool_certificate/verify_certificate_result 19 | 20 | The certificate verification result 21 | 22 | Classes required for JS: 23 | * None 24 | 25 | Data attibutes required for JS: 26 | * All data attributes are required 27 | 28 | Context variables required for this template: 29 | * userprofileurl The URL to the user's profile 30 | * userfullname The fullname of the user 31 | * courseurl The URL of the course 32 | * coursefullname The full name of the course 33 | * certificatename The name of the certificate 34 | 35 | Example context (json): 36 | { 37 | "expired": false, 38 | "table": "
", 39 | "viewurl": "" 40 | } 41 | }} 42 | 46 | {{{table}}} 47 | {{#str}}viewcertificate, tool_certificate{{/str}} 48 | -------------------------------------------------------------------------------- /element/digitalsignature/lang/en/certificateelement_digitalsignature.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Strings for component 'certificateelement_digitalsignature', language 'en'. 19 | * 20 | * @package certificateelement_digitalsignature 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | $string['digitalsignature'] = 'Digital signature'; 26 | $string['errormultipleimages'] = 'You can only select one image (either uploaded or shared)'; 27 | $string['height'] = 'Height'; 28 | $string['height_help'] = 'Height of the element in mm. The value can be automatically calculated for uploaded/shared images if set to 0, otherwise it must be specified'; 29 | $string['pluginname'] = 'Digital signature'; 30 | $string['privacy:metadata'] = 'The Digital signature plugin does not store any personal data.'; 31 | $string['signaturecontactinfo'] = 'Signature contact info'; 32 | $string['signaturelocation'] = 'Signature location'; 33 | $string['signaturename'] = 'Signature name'; 34 | $string['signaturepassword'] = 'Signature password'; 35 | $string['signaturereason'] = 'Signature reason'; 36 | $string['width'] = 'Width'; 37 | $string['width_help'] = 'Width of the element in mm. The value can be automatically calculated for uploaded/shared images if set to 0, otherwise it must be specified'; -------------------------------------------------------------------------------- /classes/observer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class observer for tool_certificate. 19 | * 20 | * @package tool_certificate 21 | * @author 2020 Mikel Martín 22 | * @copyright 2020 Moodle Pty Ltd 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die; 27 | 28 | /** 29 | * Class tool_certificate_observer 30 | * 31 | * @package tool_certificate 32 | * @author 2020 Mikel Martín 33 | * @copyright 2020 Moodle Pty Ltd 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_observer 37 | { 38 | /** 39 | * Course deleted observer 40 | * 41 | * @param \core\event\course_content_deleted $event 42 | */ 43 | public static function on_course_content_deleted(\core\event\course_content_deleted $event): void { 44 | global $DB; 45 | 46 | $fs = get_file_storage(); 47 | $issues = $DB->get_records('tool_certificate_issues', ['courseid' => $event->courseid]); 48 | foreach ($issues as $issue) { 49 | $fs->delete_area_files(context_system::instance()->id, 'tool_certificate', 'issues', $issue->id); 50 | } 51 | 52 | $DB->delete_records('tool_certificate_issues', ['courseid' => $event->courseid]); 53 | 54 | } 55 | } -------------------------------------------------------------------------------- /templates/edit_layout.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/edit_layout 19 | 20 | The certificate edit layout 21 | 22 | Classes required for JS: 23 | * None 24 | 25 | Data attibutes required for JS: 26 | 27 | Context variables required for this template: 28 | 29 | Example context (json): 30 | { 31 | "pages": [ 32 | {"id": 1, "title": "Page 1"}, 33 | { 34 | "id": 2, 35 | "title": "Page 2", 36 | "editlabel": "Edit", 37 | "deletelabel": "Delete", 38 | "pagelayout": "Page layout editor", 39 | "haselements": 1, 40 | "elements": [ 41 | {"name": "Element1", "type": "Type1", "id": 1}, 42 | {"name": "Element2", "type": "Type2", "id": 2}, 43 | {"name": "Element3", "type": "Type3", "id": 3} 44 | ] 45 | }, 46 | {"id": 3, "title": "Page 3"}, 47 | {"id": 4, "title": "Page 4"} 48 | ] 49 | } 50 | }} 51 | {{> tool_certificate/content_heading }} 52 |
53 | {{#pages}} 54 | {{> tool_certificate/edit_layout_page}} 55 | {{/pages}} 56 |
57 | {{#js}} 58 | require(['tool_certificate/template-edit'], 59 | function(T) { 60 | T.init(); 61 | } 62 | ); 63 | {{/js}} 64 | -------------------------------------------------------------------------------- /classes/output/renderer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains renderer class. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\output; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | use plugin_renderer_base; 30 | 31 | /** 32 | * Renderer class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2017 Mark Nelson 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class renderer extends plugin_renderer_base { 39 | 40 | /** 41 | * Renders the verify certificate results. 42 | * 43 | * Defer to template. 44 | * 45 | * @param \tool_certificate\output\verify_certificate_results $page 46 | * @return string html for the page 47 | */ 48 | public function render_verify_certificate_results(verify_certificate_results $page) { 49 | $data = $page->export_for_template($this); 50 | return parent::render_from_template('tool_certificate/verify_certificate_results', $data); 51 | } 52 | 53 | /** 54 | * Renders a table. 55 | * 56 | * @param \table_sql $table 57 | * @return string HTML 58 | */ 59 | public function render_table(\table_sql $table) { 60 | 61 | ob_start(); 62 | $table->out(10, true); 63 | $tablecontents = ob_get_contents(); 64 | ob_end_clean(); 65 | 66 | return $tablecontents; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Certificate manager 2 | =================== 3 | 4 | This plugin allows users to create certificate templates on the system and course category levels. 5 | Certificate templates can have user fields such as user name, profile picture, etc, and also 6 | additional dynamic fields that are added by the issuer (through API). 7 | 8 | The built-in interface allows users to issue certificates manually and browse the issued certificates. 9 | 10 | A verification code / link / QR code can be added to the certificate template. Certificates can be 11 | verified by unauthenticated users even on sites with forced login and no guest access. 12 | 13 | Other plugins can depend on this plugin to issue certificates based on some criteria, for 14 | example **Course certificates (mod_coursecertificate)** is an activity module that will automatically 15 | issue certificates when the student satisfies the access restrictions. The mod_coursecertificate 16 | plugin will send the course name and completion information to the tool_certificate plugin, so 17 | if these fields are included in the template, they will be displayed on the certificate. 18 | 19 | Acknowledgements 20 | ---------------- 21 | 22 | This plugin was originally copied from mod_customcert plugin. Big thanks to Mark Nelson for all the 23 | work on it. 24 | 25 | API 26 | --- 27 | 28 | As mentioned above, this plugin works best in combination with other plugins. For example, in 29 | Moodle Workplace it is used by Dynamic rules to automatically issue certificates on completion 30 | of Programs, Certifications and Courses. Information about those programs, certifications and 31 | courses is added to the issue data. 32 | 33 | Plugins can implement a callback in lib.php: 34 | 35 | function PLUGINNAME_tool_certificate_fields() {} 36 | 37 | In this callback the plugin can define additional fields that the plugin can send. The Certificate 38 | Manager then will make these fields available in the Template designer. You can find an example 39 | of this callback in mod_coursecertificate. 40 | 41 | To retrieve a list of templates available in the context: 42 | 43 | \tool_certificate\permission::get_visible_templates($context) 44 | 45 | To issue certificate: 46 | 47 | $template = \tool_certificate\template::instance($templateid); 48 | $template->issue_certificate(....) 49 | -------------------------------------------------------------------------------- /templates/edit_layout_elementlist.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/edit_layout_elementlist 19 | 20 | The certificate edit layout 21 | 22 | Classes required for JS: 23 | * None 24 | 25 | Data attibutes required for JS: 26 | 27 | Context variables required for this template: 28 | 29 | Example context (json): 30 | { 31 | "haselements": 1, 32 | "elements": [ 33 | {"name": "Element1", "type": "Type1", "id": 1}, 34 | {"name": "Element2", "type": "Type2", "id": 2}, 35 | {"name": "Element3", "type": "Type3", "id": 3} 36 | ] 37 | } 38 | }} 39 | -------------------------------------------------------------------------------- /tests/behat/verify_certificates.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace 2 | Feature: Being able to verify that a certificate is valid or not 3 | In order to ensure that a user can verify a certificate is valid 4 | As an admin and non-user 5 | I need to be able to verify a certificate 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | And the following certificate templates exist: 12 | | name | 13 | | Certificate 1 | 14 | | Certificate 2 | 15 | 16 | Scenario: Verify a certificate as admin 17 | When the following certificate issues exist: 18 | | template | user | 19 | | Certificate 1 | student1 | 20 | | Certificate 2 | student1 | 21 | And I log in as "admin" 22 | And I visit the sites certificates verification url 23 | And I set the field "Code" to "NOTAVALIDCODE" 24 | And I press "Verify" 25 | Then I should see "Not verified" 26 | And I verify the "Certificate 1" site certificate for the user "student1" 27 | And I verify the "Certificate 2" site certificate for the user "student1" 28 | 29 | Scenario: Verify a certificate as a guest using the site-wide URL 30 | And the following certificate issues exist: 31 | | template | user | 32 | | Certificate 1 | student1 | 33 | | Certificate 2 | student1 | 34 | And I log in as "guest" 35 | And I visit the sites certificates verification url 36 | And I set the field "Code" to "NOTAVALIDCODE" 37 | And I press "Verify" 38 | Then I should see "Not verified" 39 | And I verify the "Certificate 1" site certificate for the user "student1" 40 | And I verify the "Certificate 2" site certificate for the user "student1" 41 | 42 | Scenario: Verify certificate of a removed user 43 | And the following certificate issues exist: 44 | | template | user | code | 45 | | Certificate 1 | student1 | aaaaaaaaa | 46 | And I log in as "admin" 47 | And I navigate to "Users > Accounts > Browse list of users" in site administration 48 | And I click on "Delete" "link" in the "Student 1" "table_row" 49 | And I press "Delete" 50 | And I visit the sites certificates verification url 51 | And I verify the site certificate with code "aaaaaaaaa" 52 | And I should see "Student 1" 53 | -------------------------------------------------------------------------------- /tests/fixtures/signature.crt: -------------------------------------------------------------------------------- 1 | Bag Attributes 2 | localKeyID: 7B AB 1B 7A BE 4C 85 C0 1A A6 DC 59 3F 79 48 C3 93 38 68 9C 3 | subject=/CN=TCPDF DEMO/O=TCPDF/OU=DEMO/emailAddress=you@example.com/C=IT 4 | issuer=/CN=TCPDF DEMO/O=TCPDF/OU=DEMO/emailAddress=you@example.com/C=IT 5 | -----BEGIN CERTIFICATE----- 6 | MIIC1TCCAj6gAwIBAgIKkehOL/XGkB5cjjANBgkqhkiG9w0BAQUFADBhMRMwEQYD 7 | VQQDEwpUQ1BERiBERU1PMQ4wDAYDVQQKEwVUQ1BERjENMAsGA1UECxMEREVNTzEe 8 | MBwGCSqGSIb3DQEJARYPeW91QGV4YW1wbGUuY29tMQswCQYDVQQGEwJJVDAeFw0w 9 | OTA4MjExMjU0NDhaFw0xNDA4MjExMjU0NDhaMGExEzARBgNVBAMTClRDUERGIERF 10 | TU8xDjAMBgNVBAoTBVRDUERGMQ0wCwYDVQQLEwRERU1PMR4wHAYJKoZIhvcNAQkB 11 | Fg95b3VAZXhhbXBsZS5jb20xCzAJBgNVBAYTAklUMIGfMA0GCSqGSIb3DQEBAQUA 12 | A4GNADCBiQKBgQDAqIL0uGKmTR98Lxx2vEEE1OGKkMXFo0JViitALe7Onhxxqx0H 13 | XMUDKF5mvEVu1rcvh7/oAnAfrCuEpL/up3u1mQCgBE7WXBnFFE/AE3jCksh9OkS0 14 | Z0Xj9woN5bzxRDsGoPiOu/4xzk5qSEXt8jf2Ep90QuNkqLIRT4swAzpDbwIDAQAB 15 | o4GTMIGQMDcGA1UdEgQwMC6gEQYDVQQDDApUQ1BERiBERU1PoAwGA1UECgwFVENQ 16 | REagCwYDVQQLDARERU1PMDcGA1UdEQQwMC6gEQYDVQQDDApUQ1BERiBERU1PoAwG 17 | A1UECgwFVENQREagCwYDVQQLDARERU1PMA8GCSqGSIb3LwEBCgQCBQAwCwYDVR0P 18 | BAQDAgSQMA0GCSqGSIb3DQEBBQUAA4GBAEhTQfqX3ZNdHmpTLDbIj22RHXii2roE 19 | OavCbu9WsHoWpva0qSd+yIoD594VHvYAd29sfzDfiN+7W0aiZfDhq5jpaSQMVlN8 20 | RGYMupbHY/+a9Gz1wqxnR84mlTtIkZVRYAhsfPwy6M1BEjdMqfdh9h40JIdkdjtb 21 | 8faTCfXPePWQ 22 | -----END CERTIFICATE----- 23 | Bag Attributes 24 | localKeyID: 7B AB 1B 7A BE 4C 85 C0 1A A6 DC 59 3F 79 48 C3 93 38 68 9C 25 | Key Attributes: 26 | -----BEGIN RSA PRIVATE KEY----- 27 | MIICXQIBAAKBgQDAqIL0uGKmTR98Lxx2vEEE1OGKkMXFo0JViitALe7Onhxxqx0H 28 | XMUDKF5mvEVu1rcvh7/oAnAfrCuEpL/up3u1mQCgBE7WXBnFFE/AE3jCksh9OkS0 29 | Z0Xj9woN5bzxRDsGoPiOu/4xzk5qSEXt8jf2Ep90QuNkqLIRT4swAzpDbwIDAQAB 30 | AoGAXc+wNMmz/5Z+RlIKYia44klmqbplEx+0JULqXI4BQsrqvs67i+I4bJkznoL+ 31 | rEIRYSuQ3sCRKFsFtckjTGpxadnxkB+uwGKc6pZChv99BFX6HFR4hgBlT/BBRAQA 32 | hMDlM2JIRr4S4SMVXR7MHwGMUf9mUeanGLR3ZWtU3aXJrIECQQD7OaYUVYNEEnM9 33 | uXyjm22CuHyqyEf5gb13sK0uQty67547yJTMUQZd/sQc9KGwhzBbhrob2LO2jAhh 34 | S+f+NSRnAkEAxFHm3fMI5RgXmswxlGm4QW07a/Ueo7ZJG6xjTkFXluJhd+XHswRD 35 | dQIO3zG9nGjNUoeMrPhXhPvKqFc2F9RDuQJAQBEGin74N77gxqfr4ik79y8nE8J5 36 | oGZ2s/RJZdfFRKLg3mwbjjNHhWb4Ck5UgZkoOt8TzRApXG8/n9hktE5HFwJBALur 37 | M5AueO1Pl5kB489lNJ9OxUQRYUXMxpxuscuoCQwSwmv0O2+0/qtG2WKhUQnI4aYo 38 | L+FV0YwtivBb1jj3T/kCQQDIWOxq8eRowdaMzvJpRUHFgMcf1AVZExKyrugwYOWd 39 | KNsDxC4KaQOsPt8iT/Ulo4g/MJC0HolCOhWibKmR9Ayl 40 | -----END RSA PRIVATE KEY----- 41 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Handles verifying the code for a certificate. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | // This file does not need require_login because capability to verify can be granted to guests, skip codechecker here. 26 | // @codingStandardsIgnoreLine 27 | require_once('../../../config.php'); 28 | 29 | $code = optional_param('code', '', PARAM_ALPHANUM); // The code for the certificate we are verifying. 30 | 31 | if (!\tool_certificate\permission::can_verify()) { 32 | print_error('verifynotallowed', 'tool_certificate'); 33 | } 34 | 35 | 36 | $pageurl = new moodle_url('/admin/tool/certificate/index.php'); 37 | 38 | if ($code) { 39 | $pageurl->param('code', $code); 40 | } 41 | 42 | $heading = get_string('verifycertificates', 'tool_certificate'); 43 | 44 | $PAGE->set_url($pageurl); 45 | $PAGE->set_context(context_system::instance()); 46 | $PAGE->set_title(format_string($heading)); 47 | $PAGE->set_heading($SITE->fullname); 48 | 49 | $PAGE->navbar->add($heading); 50 | 51 | $form = new \tool_certificate\verify_certificate_form($pageurl, null, 'post', '', 52 | ['class' => 'mt-3 mb-5 p-4 bg-light']); 53 | 54 | if ($code) { 55 | $form->set_data(['code' => $code]); 56 | } 57 | 58 | $PAGE->set_heading($heading); 59 | echo $OUTPUT->header(); 60 | $form->display(); 61 | if ($form->get_data()) { 62 | $result = \tool_certificate\certificate::verify($code); 63 | $results = new \tool_certificate\output\verify_certificate_results($result); 64 | $renderer = $PAGE->get_renderer('tool_certificate'); 65 | echo $renderer->render($results); 66 | } 67 | echo $OUTPUT->footer(); 68 | -------------------------------------------------------------------------------- /db/access.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Customcert module capability definition 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $capabilities = array( 28 | 29 | 'tool/certificate:manage' => array( 30 | 31 | 'captype' => 'write', 32 | 'contextlevel' => CONTEXT_COURSE, 33 | 'archetypes' => array( 34 | 'manager' => CAP_ALLOW, 35 | 'editingteacher' => CAP_ALLOW, 36 | ) 37 | ), 38 | 39 | 'tool/certificate:image' => array( 40 | 41 | 'captype' => 'write', 42 | 'contextlevel' => CONTEXT_SYSTEM, 43 | 'clonepermissionsfrom' => 'tool/certificate:imageforalltenants' 44 | ), 45 | 46 | 'tool/certificate:issue' => array( 47 | 48 | 'captype' => 'write', 49 | 'contextlevel' => CONTEXT_COURSE, 50 | 'archetypes' => array( 51 | 'manager' => CAP_ALLOW, 52 | 'teacher' => CAP_ALLOW, 53 | 'editingteacher' => CAP_ALLOW, 54 | ) 55 | ), 56 | 57 | 'tool/certificate:viewallcertificates' => array( 58 | 'captype' => 'read', 59 | 'contextlevel' => CONTEXT_COURSE, 60 | 'archetypes' => array( 61 | 'manager' => CAP_ALLOW, 62 | 'teacher' => CAP_ALLOW, 63 | 'editingteacher' => CAP_ALLOW, 64 | ) 65 | ), 66 | 67 | 'tool/certificate:verify' => array( 68 | 'captype' => 'read', 69 | 'contextlevel' => CONTEXT_SYSTEM, 70 | 'archetypes' => array( 71 | 'guest' => CAP_ALLOW, 72 | 'user' => CAP_ALLOW, 73 | ) 74 | ), 75 | ); 76 | -------------------------------------------------------------------------------- /classes/admin_externalpage.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class admin_externalpage 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | global $CFG; 30 | require_once($CFG->libdir . '/adminlib.php'); 31 | 32 | /** 33 | * Class admin_externalpage 34 | * 35 | * @package tool_certificate 36 | * @copyright 2019 Marina Glancy 37 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 | */ 39 | class admin_externalpage extends \admin_externalpage { 40 | 41 | /** @var callable */ 42 | protected $accesscheckcallback; 43 | 44 | /** 45 | * admin_externalpage constructor. 46 | * 47 | * @param string $name 48 | * @param string $visiblename 49 | * @param string $url 50 | * @param callable $accesscheckcallback a method that will be executed to check if user has permission 51 | * to access this item. The instance of this setting ($this) is passed as an argument to this callback. 52 | * @param bool $hidden 53 | */ 54 | public function __construct(string $name, string $visiblename, string $url, callable $accesscheckcallback, 55 | bool $hidden = false) { 56 | parent::__construct($name, $visiblename, $url, [], $hidden); 57 | $this->accesscheckcallback = $accesscheckcallback; 58 | } 59 | 60 | /** 61 | * see \admin_externalpage 62 | * 63 | * @return bool Returns true for yes false for no 64 | */ 65 | public function check_access() { 66 | $callback = $this->accesscheckcallback; 67 | return $callback($this); 68 | } 69 | } -------------------------------------------------------------------------------- /tests/element_factory_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * File contains the unit tests for the capabilities tests of certicicates and templates. 19 | * 20 | * @package tool_certificate 21 | * @category test 22 | * @copyright 2018 Daniel Neis Araujo 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Unit tests for functions that deals with capabilities. 30 | * 31 | * @package tool_certificate 32 | * @group tool_certificate 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_element_factory_test_testcase extends advanced_testcase { 37 | /** 38 | * Test set up. 39 | */ 40 | public function setUp(): void { 41 | $this->resetAfterTest(); 42 | } 43 | 44 | /** 45 | * Get certificate generator 46 | * @return tool_certificate_generator 47 | */ 48 | protected function get_generator() : tool_certificate_generator { 49 | return $this->getDataGenerator()->get_plugin_generator('tool_certificate'); 50 | } 51 | 52 | /** 53 | * Test render_html 54 | */ 55 | public function test_get_element_instance_with_invalid_element() { 56 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']); 57 | $pageid = $this->get_generator()->create_page($certificate1)->get_id(); 58 | try { 59 | $element = (object)['pageid' => $pageid, 'element' => 'invalidelement']; 60 | \tool_certificate\element::instance(0, $element); 61 | $this->fail('Exception expected'); 62 | } catch (moodle_exception $e) { 63 | null; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /view.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * View issued certificate as pdf. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | 27 | $issuecode = required_param('code', PARAM_TEXT); 28 | $preview = optional_param('preview', false, PARAM_BOOL); 29 | 30 | $PAGE->set_context(context_system::instance()); 31 | $PAGE->set_url(new moodle_url('/admin/tool/certificate/view.php', ['code' => $issuecode])); 32 | 33 | if ($preview) { 34 | $templateid = required_param('templateid', PARAM_INT); 35 | require_login(); 36 | $template = \tool_certificate\template::instance($templateid); 37 | if ($template->can_manage()) { 38 | $template->generate_pdf(true); 39 | } 40 | 41 | } else { 42 | $issue = \tool_certificate\template::get_issue_from_code($issuecode); 43 | $context = \context_course::instance($issue->courseid, IGNORE_MISSING) ?: null; 44 | 45 | $template = $issue ? \tool_certificate\template::instance($issue->templateid) : null; 46 | if ($template && (\tool_certificate\permission::can_verify() || 47 | \tool_certificate\permission::can_view_issue($template, $issue, $context))) { 48 | $file = $template->get_issue_file($issue); 49 | // We add timemodified instead of issue id to prevent caching of changed certificate. 50 | // The callback tool_certificate_pluginfile() ignores the itemid and only takes the code. 51 | $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), 52 | $file->get_timemodified(), $file->get_filepath(), $issue->code . '.pdf'); 53 | redirect($url); 54 | } else { 55 | print_error('notfound'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /classes/output/page_header_button.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class heading_button 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\output; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | use renderer_base; 30 | 31 | /** 32 | * Class heading_button 33 | * 34 | * @package tool_certificate 35 | * @copyright 2019 Marina Glancy 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class page_header_button implements \templatable { 39 | 40 | /** @var string */ 41 | protected $title; 42 | /** @var array */ 43 | protected $attributes; 44 | 45 | /** 46 | * heading_button constructor. 47 | * 48 | * @param string $title 49 | * @param array $attributes 50 | */ 51 | public function __construct(string $title, array $attributes = []) { 52 | $this->title = $title; 53 | $this->attributes = $attributes; 54 | } 55 | 56 | /** 57 | * Export for template 58 | * 59 | * @param renderer_base $output 60 | * @return array|\stdClass 61 | */ 62 | public function export_for_template(renderer_base $output) { 63 | $data = ['title' => $this->title, 'attributes' => []]; 64 | foreach ($this->attributes as $key => $value) { 65 | if ($key === 'class') { 66 | $data['class'] = $value; 67 | } else { 68 | $data['attributes'][] = ['name' => $key, 'value' => $value]; 69 | } 70 | } 71 | return $data; 72 | } 73 | 74 | /** 75 | * Renders the button 76 | * 77 | * @param renderer_base $output 78 | * @return string 79 | */ 80 | public function render(renderer_base $output) : string { 81 | return $output->render_from_template('tool_certificate/page_header_button', $this->export_for_template($output)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /element/border/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 11 | 13 | 14 | 15 | 18 | 19 | 20 | 22 | 23 | 24 | 27 | 28 | 29 | 31 | 32 | 33 | 36 | 37 | 38 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/behat/managing_pages.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace @javascript 2 | Feature: Being able to manage pages in a certificate template 3 | In order to ensure managing pages in a certificate template works as expected 4 | As an admin 5 | I need to manage pages in a certificate template 6 | 7 | Background: 8 | Given the following certificate templates exist: 9 | | name | numberofpages | 10 | | Certificate 1 | 1 | 11 | And I log in as "admin" 12 | And I navigate to "Certificates > Manage certificate templates" in site administration 13 | And I click on "Edit content" "link" 14 | 15 | Scenario: Adding a page to a certificate template 16 | And I wait "1" seconds 17 | When I follow "New page" 18 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 19 | And I should see "Page 1" 20 | And I should see "Page 2" 21 | 22 | Scenario: Deleting a page from a certificate template 23 | When I add the element "User picture" to page "1" of the "Certificate 1" site certificate template 24 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 25 | And I add the element "User field" to page "1" of the "Certificate 1" site certificate template 26 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 27 | And I follow "New page" 28 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 29 | And I should see "Page 1" 30 | And I should see "Page 2" 31 | And I click on "Delete" "link" in the "[data-region=\"page\"]" "css_element" 32 | And I click on "Delete" "button" in the "Confirm" "dialogue" 33 | And I should see "Page 1" 34 | And I should not see "Page 2" 35 | And I should not see "User picture" 36 | And I should not see "User field" 37 | And I log out 38 | 39 | Scenario: Rearrange pages in a certificate template 40 | When I add the element "User picture" to page "1" of the "Certificate 1" site certificate template 41 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 42 | And I follow "New page" 43 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 44 | And I add the element "User field" to page "2" of the "Certificate 1" site certificate template 45 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 46 | And I click on "Move down" "link" in the "//*[@data-region='page'][1]" "xpath_element" 47 | Then "User field" "text" should appear before "User picture" "text" 48 | And I click on "Move up" "link" in the "//*[@data-region='page'][2]" "xpath_element" 49 | Then "User field" "text" should appear after "User picture" "text" 50 | And I log out 51 | -------------------------------------------------------------------------------- /manage_templates.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage certificate templates. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2016 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | require_once($CFG->libdir.'/adminlib.php'); 27 | 28 | $courseid = optional_param('courseid', null, PARAM_INT); 29 | $download = optional_param('download', null, PARAM_ALPHA); 30 | $page = optional_param('page', 0, PARAM_INT); 31 | $perpage = optional_param('perpage', \tool_certificate\certificate::TEMPLATES_PER_PAGE, PARAM_INT); 32 | $pageurl = new moodle_url('/admin/tool/certificate/manage_templates.php', ['page' => $page, 'perpage' => $perpage]); 33 | 34 | $title = get_string('managetemplates', 'tool_certificate'); 35 | admin_externalpage_setup('tool_certificate/managetemplates'); 36 | $context = context_system::instance(); 37 | 38 | if (!\tool_certificate\permission::can_view_admin_tree()) { 39 | print_error('managenotallowed', 'tool_certificate'); 40 | } 41 | 42 | $PAGE->set_title($title); 43 | $PAGE->set_heading($title); 44 | 45 | $table = new \tool_certificate\certificates_list(); 46 | $table->define_baseurl($pageurl); 47 | 48 | if ($table->is_downloading()) { 49 | $table->download(); 50 | exit(); 51 | } 52 | 53 | $renderer = $PAGE->get_renderer('tool_certificate'); 54 | $tablecontents = $renderer->render_table($table); 55 | 56 | $data = ['content' => $tablecontents]; 57 | if (\tool_certificate\permission::can_create()) { 58 | $data += ['addbutton' => true, 'addbuttontitle' => get_string('createtemplate', 'tool_certificate'), 59 | 'addbuttonurl' => null, 'addbuttonattrs' => ['name' => 'data-contextid', 'value' => $context->id], 60 | 'addbuttonicon' => true]; 61 | } 62 | $PAGE->requires->js_call_amd('tool_certificate/templates-list', 'init'); 63 | 64 | echo $OUTPUT->header(); 65 | echo $OUTPUT->render_from_template('tool_certificate/content_with_heading', $data); 66 | echo $OUTPUT->footer(); 67 | -------------------------------------------------------------------------------- /classes/upload_image_form.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the class that handles uploading files. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate; 26 | 27 | defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); 28 | 29 | require_once($CFG->libdir.'/formslib.php'); 30 | 31 | /** 32 | * Handles uploading files. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2013 Mark Nelson 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class upload_image_form extends \moodleform { 39 | 40 | /** @var array the filemanager options */ 41 | protected $filemanageroptions = array(); 42 | 43 | /** 44 | * Form definition. 45 | */ 46 | public function definition() { 47 | global $CFG; 48 | 49 | $mform = $this->_form; 50 | $this->filemanageroptions = array( 51 | 'maxbytes' => $CFG->maxbytes, 52 | 'subdirs' => 1, 53 | 'accepted_types' => 'image'); 54 | $mform->addElement('filemanager', 'certificateimage', get_string('uploadimage', 'tool_certificate'), '', 55 | $this->filemanageroptions); 56 | 57 | $this->add_action_buttons(); 58 | } 59 | 60 | /** 61 | * Fill in the current page data for this certificate. 62 | */ 63 | public function definition_after_data() { 64 | $mform = $this->_form; 65 | 66 | // Editing existing instance - copy existing files into draft area. 67 | $draftitemid = file_get_submitted_draft_itemid('certificateimage'); 68 | file_prepare_draft_area($draftitemid, \context_system::instance()->id, 'tool_certificate', 'image', 0, 69 | $this->filemanageroptions); 70 | $element = $mform->getElement('certificateimage'); 71 | $element->setValue($draftitemid); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /my.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Handles viewing the certificates for a certain user. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2016 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | 27 | $userid = optional_param('userid', 0, PARAM_INT); 28 | $download = optional_param('download', null, PARAM_ALPHA); 29 | $page = optional_param('page', 0, PARAM_INT); 30 | $perpage = optional_param('perpage', \tool_certificate\certificate::ISSUES_PER_PAGE, PARAM_INT); 31 | $pageurl = $url = new moodle_url('/admin/tool/certificate/my.php', array('userid' => $userid, 32 | 'page' => $page, 'perpage' => $perpage)); 33 | 34 | // Requires a login. 35 | require_login(); 36 | 37 | // Check that we have a valid user. 38 | $user = \core_user::get_user($userid ?: $USER->id, '*', MUST_EXIST); 39 | if (!\tool_certificate\permission::can_view_list($user->id)) { 40 | throw new \required_capability_exception(context_system::instance(), 'tool/certificate:viewallcertificates', 41 | 'nopermission', 'error'); 42 | } 43 | 44 | $table = new \tool_certificate\my_certificates_table($user->id, $download); 45 | $table->define_baseurl($pageurl); 46 | 47 | if ($table->is_downloading()) { 48 | $table->download(); 49 | exit(); 50 | } 51 | 52 | $PAGE->set_url($pageurl); 53 | $PAGE->set_context(context_user::instance($user->id)); 54 | $PAGE->navigation->extend_for_user($user); 55 | $PAGE->set_title(get_string('mycertificates', 'tool_certificate')); 56 | 57 | $PAGE->set_pagelayout('standard'); 58 | 59 | $PAGE->navbar->add(get_string('profile'), new moodle_url('/user/profile.php', array('id' => $user->id))); 60 | $PAGE->navbar->add(get_string('mycertificates', 'tool_certificate')); 61 | 62 | echo $OUTPUT->header(); 63 | echo $OUTPUT->heading(get_string('mycertificates', 'tool_certificate')); 64 | echo html_writer::div(get_string('mycertificatesdescription', 'tool_certificate')); 65 | $table->out($perpage, false); 66 | echo $OUTPUT->footer(); 67 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | /* Template editor */ 2 | 3 | #page-admin-tool-certificate-template [data-region="pdf"] { 4 | clear: both; 5 | position: relative; 6 | } 7 | 8 | #page-admin-tool-certificate-template [data-region="pdf"] > * { 9 | position: absolute; 10 | } 11 | 12 | #page-admin-tool-certificate-template [data-region="pdf"] [data-region="pdfelement"] { 13 | display: inline-block; 14 | word-wrap: break-word; 15 | text-decoration: none; 16 | } 17 | 18 | #page-admin-tool-certificate-template [data-region="pdf"]:not(.recalculated) [data-region="pdfelement"], 19 | #page-admin-tool-certificate-template [data-region="pdf"]:not(.recalculated) * { 20 | opacity: 0; 21 | } 22 | 23 | #page-admin-tool-certificate-template [data-region="template"] .ws-toggle .collapsed-icon-container { 24 | display: none; 25 | } 26 | #page-admin-tool-certificate-template [data-region="template"] .ws-toggle .expanded-icon-container { 27 | display: inline-block; 28 | } 29 | #page-admin-tool-certificate-template [data-region="template"] .ws-toggle.collapsed .collapsed-icon-container { 30 | display: inline-block; 31 | } 32 | #page-admin-tool-certificate-template [data-region="template"] .ws-toggle.collapsed .expanded-icon-container { 33 | display: none; 34 | } 35 | 36 | /* Elements refpoint */ 37 | 38 | #page-admin-tool-certificate-template [data-region="pdf"] [data-region="pdfelement"][data-refpoint]:before { 39 | background-image: url([[pix:tool_certificate|target]]); 40 | background-repeat: no-repeat; 41 | content: ""; 42 | display: block; 43 | float: left; 44 | height: 9px; 45 | width: 100%; 46 | background-position: left top; 47 | margin: -4px -5px -5px -4px; 48 | } 49 | 50 | #page-admin-tool-certificate-template [data-region="pdf"] [data-region="pdfelement"][data-refpoint="1"]:before { 51 | background-position: center top; 52 | margin: -4px 0 -5px 0; 53 | } 54 | 55 | #page-admin-tool-certificate-template [data-region="pdf"] [data-region="pdfelement"][data-refpoint="2"]:before { 56 | background-position: right top; 57 | margin: -4px -5px -5px 4px; 58 | } 59 | 60 | /* Page margins */ 61 | 62 | #page-admin-tool-certificate-template [data-region="pdf"] .verticalline { 63 | width: 1px; 64 | } 65 | 66 | #page-admin-tool-certificate-template [data-region="pdf"] .horizontalline { 67 | height: 1px; 68 | } 69 | 70 | #page-admin-tool-certificate-template [data-region="pdf"] .dottedline { 71 | border-left: 1px dotted black; 72 | } 73 | 74 | #page-admin-tool-certificate-template [data-region="pdf"] .solidline { 75 | border-left: 1px solid black; 76 | border-top: 1px solid black; 77 | line-height: normal; 78 | } 79 | 80 | #page-admin-tool-certificate-template #region-main { 81 | overflow: visible; 82 | } 83 | 84 | #page-admin-tool-certificate-template .modal-dialog .modal-header [data-action="hide"] { 85 | display: none; 86 | } -------------------------------------------------------------------------------- /classes/persistent/page.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class page 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\persistent; 26 | 27 | use core\persistent; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * Class page 33 | * 34 | * @package tool_certificate 35 | * @copyright 2019 Marina Glancy 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class page extends persistent { 39 | 40 | /** @var string */ 41 | const TABLE = 'tool_certificate_pages'; 42 | 43 | /** 44 | * Return the definition of the properties of this model. 45 | * 46 | * @return array 47 | */ 48 | protected static function define_properties() { 49 | return array( 50 | 'templateid' => array( 51 | 'type' => PARAM_INT 52 | ), 53 | 'width' => array( 54 | 'type' => PARAM_INT, 55 | 'default' => 297, 56 | ), 57 | 'height' => array( 58 | 'type' => PARAM_INT, 59 | 'default' => 210, 60 | ), 61 | 'leftmargin' => array( 62 | 'type' => PARAM_INT, 63 | 'default' => 0, 64 | ), 65 | 'rightmargin' => array( 66 | 'type' => PARAM_INT, 67 | 'default' => 0, 68 | ), 69 | 'sequence' => array( 70 | 'type' => PARAM_INT, 71 | 'default' => 0 72 | ), 73 | ); 74 | } 75 | 76 | /** 77 | * Magic setter for pageid 78 | * 79 | * @param int $value 80 | * @return element 81 | * @throws \coding_exception 82 | */ 83 | protected function set_templateid($value) { 84 | if ($this->get('id') && $this->get('templateid') && (int)$value != $this->get('templateid')) { 85 | throw new \coding_exception('Template of existing page can not be changed'); 86 | } 87 | return $this->raw_set('templateid', $value); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /element/image/tests/element_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Unit tests for image element. 19 | * 20 | * @package certificateelement_image 21 | * @category test 22 | * @copyright 2018 Daniel Neis Araujo 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Unit tests for image element. 30 | * 31 | * @package certificateelement_image 32 | * @group tool_certificate 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_image_element_test_testcase extends advanced_testcase { 37 | 38 | /** 39 | * Test set up. 40 | */ 41 | public function setUp(): void { 42 | $this->resetAfterTest(); 43 | } 44 | 45 | /** 46 | * Get certificate generator 47 | * @return tool_certificate_generator 48 | */ 49 | protected function get_generator() : tool_certificate_generator { 50 | return $this->getDataGenerator()->get_plugin_generator('tool_certificate'); 51 | } 52 | 53 | public function test_render_html_content() { 54 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']); 55 | $pageid = $this->get_generator()->create_page($certificate1)->get_id(); 56 | $e = $this->get_generator()->create_element($pageid, 'image'); 57 | // TODO: make a better test. 58 | $this->assertNotEmpty($e->render_html()); 59 | 60 | // Generate PDF for preview. 61 | $filecontents = $this->get_generator()->generate_pdf($certificate1, true); 62 | $filesize = core_text::strlen($filecontents); 63 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 64 | 65 | // Generate PDF for issue. 66 | $issue = $this->get_generator()->issue($certificate1, $this->getDataGenerator()->create_user(), time() + YEARSECS); 67 | $filecontents = $this->get_generator()->generate_pdf($certificate1, false, $issue); 68 | $filesize = core_text::strlen($filecontents); 69 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /templates/edit_layout_pdf.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of the tool_certificate plugin for Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template tool_certificate/edit_layout 19 | 20 | The certificate edit layout 21 | 22 | Classes required for JS: 23 | * snapdraggable 24 | 25 | Data attibutes required for JS: 26 | * All data- attributes 27 | 28 | Context variables required for this template: 29 | 30 | Example context (json): 31 | { 32 | "elements": [ 33 | {"name": "Element1", "type": "Type1", "id": 1}, 34 | {"name": "Element2", "type": "Type2", "id": 2}, 35 | {"name": "Element3", "type": "Type3", "id": 3} 36 | ], 37 | "leftmargin": 10, 38 | "rightmargin": 10, 39 | "width": 200, 40 | "height": 100 41 | } 42 | }} 43 |
44 |
45 |
46 | {{#elements}} 47 | 50 | {{{html}}} 51 | 52 | {{/elements}} 53 | {{#leftmargin}} 54 |
55 | {{/leftmargin}} 56 | {{#rightmargin}} 57 |
58 | {{/rightmargin}} 59 |
60 |
61 |
62 |
63 |
-------------------------------------------------------------------------------- /amd/build/templates-list.min.js: -------------------------------------------------------------------------------- 1 | define ("tool_certificate/templates-list",["jquery","tool_certificate/modal_form","core/notification","core/str","core/ajax","core/toast"],function(a,b,c,d,e,f){var g=function(a,c,e){var f=new b({formClass:"tool_certificate\\form\\details",args:e,modalConfig:{title:c},saveButtonText:d.get_string("save"),triggerElement:a});return f},h=function(b){var c=a(b.currentTarget).data("contextid");b.preventDefault();var e=g(a(b.currentTarget),d.get_string("createtemplate","tool_certificate"),{id:0,contextid:c});e.onSubmitSuccess=function(a){window.location.href=a}},i=function(b){b.preventDefault();var c=a(b.currentTarget),e=c.attr("data-id"),f=c.attr("data-name"),h=g(c,d.get_string("editcertificate","tool_certificate",f),{id:e});h.onSubmitSuccess=function(){window.location.reload()}},j=function(c){c.preventDefault();var e=a(c.currentTarget),g=new b({formClass:"tool_certificate\\form\\certificate_issues",args:{tid:e.attr("data-tid")},modalConfig:{title:d.get_string("issuecertificates","tool_certificate"),scrollable:!1},saveButtonText:d.get_string("save"),triggerElement:e});g.onSubmitSuccess=function(a){a=parseInt(a,10);if(a){d.get_strings([{key:"oneissuewascreated",component:"tool_certificate"},{key:"aissueswerecreated",component:"tool_certificate",param:a}]).done(function(b){var c=1. 16 | 17 | /** 18 | * Unit tests for digitalsignature element. 19 | * 20 | * @package certificateelement_digitalsignature 21 | * @category test 22 | * @copyright 2018 Daniel Neis Araujo 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Unit tests for digitalsignature element. 30 | * 31 | * @package certificateelement_digitalsignature 32 | * @group tool_certificate 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_digitalsignature_element_test_testcase extends advanced_testcase { 37 | 38 | /** 39 | * Test set up. 40 | */ 41 | public function setUp(): void { 42 | $this->resetAfterTest(); 43 | } 44 | 45 | /** 46 | * Get certificate generator 47 | * @return tool_certificate_generator 48 | */ 49 | protected function get_generator() : tool_certificate_generator { 50 | return $this->getDataGenerator()->get_plugin_generator('tool_certificate'); 51 | } 52 | 53 | public function test_render_html_content() { 54 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']); 55 | $pageid = $this->get_generator()->create_page($certificate1)->get_id(); 56 | $e = $this->get_generator()->create_element($pageid, 'digitalsignature'); 57 | // TODO: make a better test. 58 | $this->assertNotEmpty($e->render_html()); 59 | 60 | // Generate PDF for preview. 61 | $filecontents = $this->get_generator()->generate_pdf($certificate1, true); 62 | $filesize = core_text::strlen($filecontents); 63 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 64 | 65 | // Generate PDF for issue. 66 | $issue = $this->get_generator()->issue($certificate1, $this->getDataGenerator()->create_user(), time() + YEARSECS); 67 | $filecontents = $this->get_generator()->generate_pdf($certificate1, false, $issue); 68 | $filesize = core_text::strlen($filecontents); 69 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /settings.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Creates a link to the upload form on the settings page. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die; 26 | 27 | require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/certificate/adminlib.php'); 28 | 29 | if ($hassiteconfig || \tool_certificate\permission::can_view_admin_tree()) { 30 | 31 | $ADMIN->add('root', new admin_category('certificates', new lang_string('certificates', 'tool_certificate')), 32 | 'location'); 33 | 34 | $ADMIN->add('certificates', new \tool_certificate\admin_externalpage('tool_certificate/managetemplates', 35 | get_string('managetemplates', 'tool_certificate'), 36 | new moodle_url('/admin/tool/certificate/manage_templates.php'), function() { 37 | return \tool_certificate\permission::can_view_admin_tree(); 38 | } 39 | )); 40 | 41 | $ADMIN->add('certificates', new \tool_certificate\admin_externalpage('tool_certificate/verify', 42 | get_string('verifycertificates', 'tool_certificate'), 43 | new moodle_url('/admin/tool/certificate/index.php'), function() { 44 | return \tool_certificate\permission::can_verify(); 45 | } 46 | )); 47 | 48 | $ADMIN->add('certificates', new \tool_certificate\admin_externalpage('tool_certificate/images', 49 | get_string('certificateimages', 'tool_certificate'), 50 | new moodle_url('/admin/tool/certificate/upload_image.php'), function() { 51 | return \tool_certificate\permission::can_manage_images(); 52 | } 53 | )); 54 | } 55 | 56 | if ($hassiteconfig) { 57 | $ADMIN->add('tools', new tool_certificate_admin_page_manage_element_plugins()); 58 | $ADMIN->add('certificates', 59 | new admin_externalpage('tool_certificate_customfield', 60 | new lang_string('certificate_customfield', 'tool_certificate'), 61 | new moodle_url('/admin/tool/certificate/customfield.php'), 62 | 'moodle/site:config', 63 | true // This item is hidden. 64 | ) 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /classes/output/verify_certificate_results.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains class used to prepare verification results for display. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2017 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\output; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | use renderable; 30 | use templatable; 31 | 32 | /** 33 | * Class to prepare verification results for display. 34 | * 35 | * @package tool_certificate 36 | * @copyright 2017 Mark Nelson 37 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 | */ 39 | class verify_certificate_results implements templatable, renderable { 40 | 41 | /** 42 | * @var bool Was the code successfully verified? 43 | */ 44 | public $success; 45 | 46 | /** 47 | * @var string The message to display. 48 | */ 49 | public $message; 50 | 51 | /** 52 | * @var array The certificates issued with the matching code. 53 | */ 54 | public $issues; 55 | 56 | /** 57 | * Constructor. 58 | * 59 | * @param \stdClass $result 60 | */ 61 | public function __construct($result) { 62 | $this->success = $result->success; 63 | if ($this->success) { 64 | $this->issue = $result->issue; 65 | $this->message = get_string('verified', 'tool_certificate'); 66 | } else { 67 | $this->message = get_string('notverified', 'tool_certificate'); 68 | } 69 | } 70 | 71 | /** 72 | * Function to export the renderer data in a format that is suitable for a mustache template. 73 | * 74 | * @param \renderer_base $output Used to do a final render of any components that need to be rendered for export. 75 | * @return \stdClass|array 76 | */ 77 | public function export_for_template(\renderer_base $output) { 78 | $result = new \stdClass(); 79 | $result->success = $this->success; 80 | $result->message = $this->message; 81 | if (isset($this->issue)) { 82 | $resultissue = new verify_certificate_result($this->issue); 83 | $result->issue = $resultissue->export_for_template($output); 84 | } 85 | return $result; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /classes/event/template_deleted.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate template created event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate template created event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class template_deleted extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'd'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_templates'; 49 | } 50 | 51 | /** 52 | * Returns description of what happened. 53 | * 54 | * @return string 55 | */ 56 | public function get_description() { 57 | return "The user with id '$this->userid' has deleted the template with id '$this->objectid'."; 58 | } 59 | 60 | /** 61 | * Return localised event name. 62 | * 63 | * @return string 64 | */ 65 | public static function get_name() { 66 | return get_string('eventtemplatedeleted', 'tool_certificate'); 67 | } 68 | 69 | /** 70 | * Get URL related to the action 71 | * 72 | * @return \moodle_url 73 | */ 74 | public function get_url() { 75 | return new \moodle_url('/admin/tool/certificate/manage_templates.php'); 76 | } 77 | 78 | /** 79 | * Create instance of event. 80 | * 81 | * @param template $template 82 | * @return template_deleted 83 | */ 84 | public static function create_from_template(template $template) : template_deleted { 85 | $data = array( 86 | 'context' => $template->get_context(), 87 | 'objectid' => $template->get_id(), 88 | ); 89 | $event = self::create($data); 90 | $event->add_record_snapshot('tool_certificate_templates', $template->to_record()); 91 | return $event; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /classes/event/template_created.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate template created event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate template created event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class template_created extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'c'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_templates'; 49 | } 50 | 51 | /** 52 | * Returns description of what happened. 53 | * 54 | * @return string 55 | */ 56 | public function get_description() { 57 | return "The user with id '$this->userid' has created the template with id '$this->objectid'."; 58 | } 59 | 60 | /** 61 | * Return localised event name. 62 | * 63 | * @return string 64 | */ 65 | public static function get_name() { 66 | return get_string('eventtemplatecreated', 'tool_certificate'); 67 | } 68 | 69 | /** 70 | * Create instance of event. 71 | * 72 | * @param template $template 73 | * @return template_created 74 | */ 75 | public static function create_from_template(template $template) : template_created { 76 | $data = array( 77 | 'context' => $template->get_context(), 78 | 'objectid' => $template->get_id(), 79 | ); 80 | $event = self::create($data); 81 | $event->add_record_snapshot('tool_certificate_templates', $template->to_record()); 82 | return $event; 83 | } 84 | 85 | /** 86 | * Get URL related to the action 87 | * 88 | * @return \moodle_url 89 | */ 90 | public function get_url() { 91 | return new \moodle_url('/admin/tool/certificate/template.php', array('id' => $this->objectid)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /classes/event/template_updated.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate template created event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate template created event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class template_updated extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'u'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_templates'; 49 | } 50 | 51 | /** 52 | * Returns description of what happened. 53 | * 54 | * @return string 55 | */ 56 | public function get_description() { 57 | return "The user with id '$this->userid' has updated the template with id '$this->objectid'."; 58 | } 59 | 60 | /** 61 | * Return localised event name. 62 | * 63 | * @return string 64 | */ 65 | public static function get_name() { 66 | return get_string('eventtemplateupdated', 'tool_certificate'); 67 | } 68 | 69 | /** 70 | * Get URL related to the action 71 | * 72 | * @return \moodle_url 73 | */ 74 | public function get_url() { 75 | return new \moodle_url('/admin/tool/certificate/template.php', array('id' => $this->objectid)); 76 | } 77 | 78 | /** 79 | * Create instance of event. 80 | * 81 | * @param template $template 82 | * @return template_updated 83 | */ 84 | public static function create_from_template(template $template): template_updated { 85 | $data = array( 86 | 'context' => $template->get_context(), 87 | 'objectid' => $template->get_id(), 88 | ); 89 | $event = self::create($data); 90 | $event->add_record_snapshot('tool_certificate_templates', $template->to_record()); 91 | return $event; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /certificates.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage issued certificates for a given templateid. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once('../../../config.php'); 26 | require_once($CFG->libdir.'/adminlib.php'); 27 | 28 | $download = optional_param('download', null, PARAM_ALPHA); 29 | $templateid = required_param('templateid', PARAM_INT); 30 | 31 | $confirm = optional_param('confirm', 0, PARAM_INT); 32 | 33 | $page = optional_param('page', 0, PARAM_INT); 34 | $perpage = optional_param('perpage', \tool_certificate\certificate::ISSUES_PER_PAGE, PARAM_INT); 35 | 36 | $pageurl = $url = new moodle_url('/admin/tool/certificate/certificates.php', array('templateid' => $templateid)); 37 | $PAGE->set_url($pageurl); 38 | $template = \tool_certificate\template::instance($templateid); 39 | if ($coursecontext = $template->get_context()->get_course_context(false)) { 40 | require_login($coursecontext->instanceid); 41 | } else { 42 | admin_externalpage_setup('tool_certificate/managetemplates', '', null, $pageurl); 43 | } 44 | 45 | if (!$template->can_view_issues()) { 46 | print_error('issueormanagenotallowed', 'tool_certificate'); 47 | } 48 | 49 | $heading = get_string('certificates', 'tool_certificate'); 50 | 51 | $PAGE->set_title("$SITE->shortname: " . $heading); 52 | $PAGE->navbar->add($heading); 53 | $PAGE->set_heading($heading); 54 | 55 | $table = new \tool_certificate\issues_list($template); 56 | $table->define_baseurl($pageurl); 57 | 58 | if ($table->is_downloading()) { 59 | $table->download(); 60 | exit(); 61 | } 62 | 63 | $renderer = $PAGE->get_renderer('tool_certificate'); 64 | $tablecontents = $renderer->render_table($table); 65 | $data = ['content' => $tablecontents, 'heading' => format_string($template->get_name())]; 66 | if ($template->can_issue_to_anybody()) { 67 | $data += ['addbutton' => true, 'addbuttontitle' => get_string('issuecertificates', 'tool_certificate'), 68 | 'addbuttonurl' => null, 'addbuttonattrs' => ['name' => 'data-tid', 'value' => $template->get_id()], 69 | 'addbuttonicon' => true]; 70 | } 71 | $PAGE->requires->js_call_amd('tool_certificate/issues-list', 'init'); 72 | 73 | echo $OUTPUT->header(); 74 | echo $OUTPUT->render_from_template('tool_certificate/content_with_heading', $data); 75 | echo $OUTPUT->footer(); 76 | -------------------------------------------------------------------------------- /classes/event/certificate_issued.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate certificate issued event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate certificate issued event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class certificate_issued extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'c'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_issues'; 49 | } 50 | 51 | /** 52 | * Create instance of event. 53 | * 54 | * @param \stdClass $issue 55 | * @return certificate_issued 56 | */ 57 | public static function create_from_issue(\stdClass $issue) { 58 | $data = [ 59 | 'context' => \context_system::instance(), 60 | 'objectid' => $issue->id, 61 | 'relateduserid' => $issue->userid, 62 | 'other' => [ 63 | 'code' => $issue->code 64 | ] 65 | ]; 66 | $event = self::create($data); 67 | $event->add_record_snapshot('tool_certificate_issues', $issue); 68 | return $event; 69 | } 70 | 71 | /** 72 | * Returns description of what happened. 73 | * 74 | * @return string 75 | */ 76 | public function get_description() { 77 | return "The certificate issue with id '$this->objectid' has been created for user with id '$this->relateduserid'."; 78 | } 79 | 80 | /** 81 | * Return localised event name. 82 | * 83 | * @return string 84 | */ 85 | public static function get_name() { 86 | return get_string('eventcertificateissued', 'tool_certificate'); 87 | } 88 | 89 | /** 90 | * Get URL related to the action 91 | * 92 | * @return \moodle_url 93 | */ 94 | public function get_url() { 95 | return template::view_url($this->other['code']); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /classes/event/certificate_revoked.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate certificate issued event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate certificate revoked event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class certificate_revoked extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'd'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_issues'; 49 | } 50 | 51 | /** 52 | * Returns description of what happened. 53 | * 54 | * @return string 55 | */ 56 | public function get_description() { 57 | return "The user with '$this->userid' has revoked certificate issue with id '$this->objectid'". 58 | " from user with id '$this->relateduserid'."; 59 | } 60 | 61 | /** 62 | * Return localised event name. 63 | * 64 | * @return string 65 | */ 66 | public static function get_name() { 67 | return get_string('eventcertificaterevoked', 'tool_certificate'); 68 | } 69 | 70 | /** 71 | * Get URL related to the action 72 | * 73 | * @return \moodle_url 74 | */ 75 | public function get_url() { 76 | return template::view_url($this->other['code']); 77 | } 78 | 79 | /** 80 | * Create instance of event. 81 | * 82 | * @param \stdClass $issue 83 | * @return certificate_revoked 84 | */ 85 | public static function create_from_issue(\stdClass $issue) { 86 | $data = [ 87 | 'context' => \context_system::instance(), 88 | 'objectid' => $issue->id, 89 | 'relateduserid' => $issue->userid, 90 | 'other' => [ 91 | 'code' => $issue->code 92 | ] 93 | ]; 94 | $event = self::create($data); 95 | $event->add_record_snapshot('tool_certificate_issues', $issue); 96 | return $event; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /element/text/pix/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | Asset 23 9 | 10 | 19 | 28 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /classes/event/certificate_verified.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The tool_certificate certificate issued event. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2018 Daniel Neis Araujo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace tool_certificate\event; 26 | 27 | use tool_certificate\template; 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | /** 32 | * The tool_certificate certificate issued event class. 33 | * 34 | * @package tool_certificate 35 | * @copyright 2018 Daniel Neis Araujo 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class certificate_verified extends \core\event\base { 39 | 40 | /** 41 | * Init method. 42 | * 43 | * @return void 44 | */ 45 | protected function init() { 46 | $this->data['crud'] = 'r'; 47 | $this->data['edulevel'] = self::LEVEL_OTHER; 48 | $this->data['objecttable'] = 'tool_certificate_issues'; 49 | } 50 | 51 | /** 52 | * Returns description of what happened. 53 | * 54 | * @return string 55 | */ 56 | public function get_description() { 57 | return "The user with id '$this->userid' verified the certificate issue with id '$this->objectid'". 58 | " issued to user with id '$this->relateduserid'."; 59 | } 60 | 61 | /** 62 | * Return localised event name. 63 | * 64 | * @return string 65 | */ 66 | public static function get_name() { 67 | return get_string('eventcertificateverified', 'tool_certificate'); 68 | } 69 | 70 | /** 71 | * Get URL related to the action 72 | * 73 | * @return \moodle_url 74 | */ 75 | public function get_url() { 76 | return template::verification_url($this->other['code']); 77 | } 78 | 79 | /** 80 | * Create instance of event. 81 | * 82 | * @param \stdClass $issue 83 | * @return certificate_issued 84 | */ 85 | public static function create_from_issue(\stdClass $issue) { 86 | $data = array( 87 | 'context' => \context_system::instance(), 88 | 'objectid' => $issue->id, 89 | 'relateduserid' => $issue->userid, 90 | 'other' => [ 91 | 'code' => $issue->code 92 | ] 93 | ); 94 | $event = self::create($data); 95 | $event->add_record_snapshot('tool_certificate_issues', $issue); 96 | return $event; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /classes/plugininfo/certificateelement.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Subplugin info class. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | namespace tool_certificate\plugininfo; 25 | 26 | use core\plugininfo\base; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | /** 31 | * Subplugin info class. 32 | * 33 | * @package tool_certificate 34 | * @copyright 2013 Mark Nelson 35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 | */ 37 | class certificateelement extends base { 38 | 39 | /** 40 | * Do not allow users to uninstall these plugins as it could cause certificates to break. 41 | * 42 | * @return bool 43 | */ 44 | public function is_uninstall_allowed() { 45 | return true; 46 | } 47 | 48 | /** 49 | * Loads plugin settings to the settings tree. 50 | * 51 | * @param \part_of_admin_tree $adminroot 52 | * @param string $parentnodename 53 | * @param bool $hassiteconfig whether the current user has moodle/site:config capability 54 | */ 55 | public function load_settings(\part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) { 56 | global $CFG, $USER, $DB, $OUTPUT, $PAGE; 57 | $ADMIN = $adminroot; 58 | $plugininfo = $this; 59 | 60 | if (!$this->is_installed_and_upgraded()) { 61 | return; 62 | } 63 | 64 | if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) { 65 | return; 66 | } 67 | 68 | $section = $this->get_settings_section_name(); 69 | $settings = new \admin_settingpage($section, $this->displayname, 'moodle/site:config', false); 70 | 71 | include($this->full_path('settings.php')); 72 | $ADMIN->add($parentnodename, $settings); 73 | } 74 | 75 | /** 76 | * Get the settings section name. 77 | * 78 | * @return null|string the settings section name. 79 | */ 80 | public function get_settings_section_name() { 81 | if (file_exists($this->full_path('settings.php'))) { 82 | return 'certificateelement_' . $this->name; 83 | } else { 84 | return null; 85 | } 86 | } 87 | 88 | /** 89 | * Return true if a plugin is enabled. 90 | * 91 | * @return bool 92 | */ 93 | public function is_enabled() { 94 | if ($disabled = get_config('certificateelement_' . $this->name, 'disabled')) { 95 | return $disabled == 0; 96 | } 97 | return true; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /includes/colourpicker.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the form element for handling the colour picker. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2013 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); 26 | 27 | require_once($CFG->dirroot . '/lib/form/editor.php'); 28 | 29 | /** 30 | * Form element for handling the colour picker. 31 | * 32 | * @package tool_certificate 33 | * @copyright 2013 Mark Nelson 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class moodlequickform_tool_certificate_colourpicker extends moodlequickform_editor { 37 | 38 | /** 39 | * Sets the value of the form element 40 | * 41 | * @param string $value 42 | */ 43 | public function setvalue($value) { 44 | $this->updateAttributes(array('value' => $value)); 45 | } 46 | 47 | /** 48 | * Gets the value of the form element 49 | */ 50 | public function getvalue() { 51 | return $this->getAttribute('value'); 52 | } 53 | 54 | /** 55 | * Returns the html string to display this element. 56 | * 57 | * @return string 58 | */ 59 | public function tohtml() { 60 | global $PAGE, $OUTPUT; 61 | 62 | $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->getAttribute('id'), null)); 63 | $content = ''; 64 | $content .= html_writer::start_tag('div', array('class' => 'form-colourpicker defaultsnext')); 65 | $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', 66 | array('class' => 'loadingicon')), array('class' => 'admin_colourpicker clearfix')); 67 | $content .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $this->getAttribute('id'), 68 | 'name' => $this->getName(), 'value' => $this->getValue(), 'size' => '12')); 69 | $content .= html_writer::end_tag('div'); 70 | 71 | return $content; 72 | } 73 | 74 | /** 75 | * Function to export the renderer data in a format that is suitable for a mustache template. 76 | * 77 | * @param \renderer_base $output Used to do a final render of any components that need to be rendered for export. 78 | * @return \stdClass|array 79 | */ 80 | public function export_for_template(renderer_base $output) { 81 | $context = $this->export_for_template_base($output); 82 | $context['html'] = $this->toHtml(); 83 | 84 | return $context; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/observer_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * File containing tests for functions in observer.php 19 | * 20 | * @package tool_certificate 21 | * @category test 22 | * @copyright 2020 Mikel Martín 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Tests for functions in observer.php 30 | * 31 | * @package tool_certificate 32 | * @copyright 2020 Mikel Martín 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | */ 35 | class tool_certificate_observer_testcase extends advanced_testcase { 36 | /** 37 | * Test setup 38 | */ 39 | public function setUp(): void { 40 | $this->resetAfterTest(); 41 | } 42 | 43 | /** 44 | * Get certificate generator 45 | * @return tool_certificate_generator 46 | */ 47 | protected function get_generator() : tool_certificate_generator { 48 | return $this->getDataGenerator()->get_plugin_generator('tool_certificate'); 49 | } 50 | 51 | /** 52 | * Test issues with courseid are removed when course is deleted. 53 | * 54 | * @return void 55 | */ 56 | public function test_course_deleted() { 57 | global $DB; 58 | 59 | $course1 = $this->getDataGenerator()->create_course(); 60 | $course2 = $this->getDataGenerator()->create_course(); 61 | 62 | $user1 = $this->getDataGenerator()->create_and_enrol($course1); 63 | $user2 = $this->getDataGenerator()->create_and_enrol($course1); 64 | 65 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Template 01']); 66 | $certificate2 = $this->get_generator()->create_template((object)['name' => 'Template 02']); 67 | // Using dummy component name. 68 | $certificate1->issue_certificate($user1->id, null, [], 'mod_myawesomecert', $course1->id); 69 | $certificate2->issue_certificate($user1->id, null, [], 'mod_myawesomecert', $course1->id); 70 | $certificate2->issue_certificate($user2->id, null, [], 'mod_myawesomecert', $course1->id); 71 | 72 | $certificate1->issue_certificate($user1->id, null, [], 'mod_myawesomecert', $course2->id); 73 | 74 | $this->assertEquals(3, $DB->count_records('tool_certificate_issues', ['courseid' => $course1->id])); 75 | $this->assertEquals(1, $DB->count_records('tool_certificate_issues', ['courseid' => $course2->id])); 76 | 77 | ob_start(); 78 | delete_course($course1); 79 | ob_end_clean(); 80 | 81 | $this->assertEmpty($DB->count_records('tool_certificate_issues', ['courseid' => $course1->id])); 82 | $this->assertEquals(1, $DB->count_records('tool_certificate_issues', ['courseid' => $course2->id])); 83 | } 84 | } -------------------------------------------------------------------------------- /db/services.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Web service for tool certificate. 19 | * 20 | * @package tool_certificate 21 | * @copyright 2016 Mark Nelson 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $functions = [ 28 | 'tool_certificate_revoke_issue' => [ 29 | 'classname' => \tool_certificate\external\issues::class, 30 | 'methodname' => 'revoke_issue', 31 | 'classpath' => '', 32 | 'description' => 'Revoke an issue for a certificate', 33 | 'type' => 'write', 34 | 'ajax' => true, 35 | 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) 36 | ], 37 | 'tool_certificate_regenerate_issue_file' => [ 38 | 'classname' => \tool_certificate\external\issues::class, 39 | 'methodname' => 'regenerate_issue_file', 40 | 'description' => 'Regenerates an issue file', 41 | 'type' => 'write', 42 | 'ajax' => true, 43 | ], 44 | 'tool_certificate_duplicate_template' => [ 45 | 'classname' => \tool_certificate\external\templates::class, 46 | 'methodname' => 'duplicate_template', 47 | 'description' => 'Duplicates a template', 48 | 'type' => 'write', 49 | 'ajax' => true, 50 | ], 51 | 'tool_certificate_delete_template' => [ 52 | 'classname' => \tool_certificate\external\templates::class, 53 | 'methodname' => 'delete_template', 54 | 'description' => 'Deletes a template', 55 | 'type' => 'write', 56 | 'ajax' => true, 57 | ], 58 | 'tool_certificate_delete_element' => [ 59 | 'classname' => \tool_certificate\external\elements::class, 60 | 'methodname' => 'delete_element', 61 | 'description' => 'Deletes an element', 62 | 'type' => 'write', 63 | 'ajax' => true, 64 | ], 65 | 'tool_certificate_update_element' => [ 66 | 'classname' => \tool_certificate\external\elements::class, 67 | 'methodname' => 'update_element', 68 | 'description' => 'Updates an element', 69 | 'type' => 'write', 70 | 'ajax' => true, 71 | ], 72 | 'tool_certificate_modal_form' => [ 73 | 'classname' => \tool_certificate\external\modal_form::class, 74 | 'methodname' => 'execute', 75 | 'description' => 'process submission of a modal form', 76 | 'type' => 'write', 77 | 'ajax' => true, 78 | ], 79 | 'tool_certificate_potential_users_selector' => [ 80 | 'classname' => \tool_certificate\external\issues::class, 81 | 'methodname' => 'potential_users_selector', 82 | 'description' => 'get list of users', 83 | 'type' => 'read', 84 | 'ajax' => true, 85 | ], 86 | ]; 87 | -------------------------------------------------------------------------------- /element/border/tests/element_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Unit tests for border element. 19 | * 20 | * @package certificateelement_border 21 | * @category test 22 | * @copyright 2018 Daniel Neis Araujo 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * Unit tests for border element. 30 | * 31 | * @package certificateelement_border 32 | * @group tool_certificate 33 | * @copyright 2018 Daniel Neis Araujo 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class tool_certificate_border_element_test_testcase extends advanced_testcase { 37 | 38 | /** 39 | * Test set up. 40 | */ 41 | public function setUp(): void { 42 | $this->resetAfterTest(); 43 | } 44 | 45 | /** 46 | * Get certificate generator 47 | * @return tool_certificate_generator 48 | */ 49 | protected function get_generator() : tool_certificate_generator { 50 | return $this->getDataGenerator()->get_plugin_generator('tool_certificate'); 51 | } 52 | 53 | /** 54 | * Test render_html 55 | */ 56 | public function test_render_html() { 57 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']); 58 | $pageid = $this->get_generator()->create_page($certificate1)->get_id(); 59 | $e = $this->get_generator()->create_element($pageid, 'border'); 60 | $this->assertNotEmpty($e->render_html()); 61 | 62 | // Generate PDF for preview. 63 | $filecontents = $this->get_generator()->generate_pdf($certificate1, true); 64 | $filesize = core_text::strlen($filecontents); 65 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 66 | 67 | // Generate PDF for issue. 68 | $issue = $this->get_generator()->issue($certificate1, $this->getDataGenerator()->create_user()); 69 | $filecontents = $this->get_generator()->generate_pdf($certificate1, false, $issue); 70 | $filesize = core_text::strlen($filecontents); 71 | $this->assertTrue($filesize > 30000 && $filesize < 70000); 72 | } 73 | 74 | /** 75 | * Test save_unique_data 76 | */ 77 | public function test_save_unique_data() { 78 | global $DB; 79 | $certificate1 = $this->get_generator()->create_template((object)['name' => 'Certificate 1']); 80 | $pageid = $this->get_generator()->create_page($certificate1)->get_id(); 81 | $e = $this->get_generator()->new_element($pageid, 'border'); 82 | $newdata = (object)['width' => 300]; 83 | $e->save_form_data($newdata); 84 | $el = $DB->get_record('tool_certificate_elements', ['id' => $e->get_id()]); 85 | $this->assertEquals($newdata->width, $el->data); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /template.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Edit certificate template 19 | * 20 | * @package tool_certificate 21 | * @copyright 2019 Marina Glancy 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | require_once(__DIR__ . '/../../../config.php'); 26 | require_once($CFG->libdir . '/adminlib.php'); 27 | 28 | $pageid = optional_param('pageid', 0, PARAM_INT); 29 | $action = optional_param('action', null, PARAM_ALPHANUMEXT); 30 | if ($pageid && $action) { 31 | $page = \tool_certificate\page::instance($pageid); 32 | $template = $page->get_template(); 33 | } else { 34 | $templateid = required_param('id', PARAM_INT); 35 | $template = \tool_certificate\template::instance($templateid); 36 | } 37 | 38 | $pageurl = new moodle_url('/admin/tool/certificate/template.php', array('id' => $template->get_id())); 39 | if ($template->get_context()->contextlevel == CONTEXT_COURSE) { 40 | $courseid = $template->get_context()->instanceid; 41 | require_login($courseid); 42 | $manageurl = new moodle_url('/admin/tool/certificate/manage_templates.php', array('courseid' => $courseid)); 43 | $PAGE->navbar->add(get_string('managetemplates', 'tool_certificate'), $manageurl); 44 | $PAGE->set_url($pageurl); 45 | } else { 46 | admin_externalpage_setup('tool_certificate/managetemplates', '', null, $pageurl); 47 | } 48 | 49 | $template->require_can_manage(); 50 | 51 | if ($action && $pageid) { 52 | require_sesskey(); 53 | if ($action === 'moveuppage') { 54 | $template->move_page($pageid, -1); 55 | } else if ($action === 'movedownpage') { 56 | $template->move_page($pageid, 1); 57 | } else if ($action === 'deletepage') { 58 | $template->delete_page($pageid); 59 | } 60 | redirect($pageurl); 61 | } 62 | 63 | $heading = $title = $template->get_formatted_name(); 64 | // If 'formatstringstriptags' config is enabled, we can't show a styled badge, so we avoid showing 'shared' string. 65 | // When MDL-69464 lands formatstringstriptags check won't be needed. 66 | if ($template->get_shared() && empty($CFG->formatstringstriptags)) { 67 | $heading .= html_writer::tag('div', get_string('shared', 'tool_certificate'), 68 | ['class' => 'badge badge-secondary ml-2', 'style' => 'font-size: 40%; vertical-align: middle;']); 69 | } 70 | $PAGE->navbar->add($title, $pageurl); 71 | 72 | $PAGE->set_title($title); 73 | $PAGE->set_heading($heading); 74 | 75 | $output = $PAGE->get_renderer('tool_certificate'); 76 | $edit = new \tool_certificate\output\page_header_button(get_string('editdetails', 'tool_certificate'), 77 | ['data-action' => 'editdetails', 'data-id' => $template->get_id(), 'data-name' => $template->get_formatted_name()]); 78 | $PAGE->set_button($edit->render($output) . $PAGE->button); 79 | 80 | echo $OUTPUT->header(); 81 | 82 | $data = $template->get_exporter()->export($OUTPUT); 83 | echo $OUTPUT->render_from_template('tool_certificate/edit_layout', $data); 84 | echo $OUTPUT->footer(); 85 | -------------------------------------------------------------------------------- /tests/behat/admin_tree.feature: -------------------------------------------------------------------------------- 1 | @tool @tool_certificate @moodleworkplace 2 | Feature: View links on admin tree 3 | In order to manage certificate 4 | As a manager 5 | I need to be able to view, manage, issue and verify certificates 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | user1 | User | One | one@example.com | 11 | | manager | Max | Manager | man@example.com | 12 | And the following "role assigns" exist: 13 | | user | role | contextlevel | reference | 14 | | manager | manager | System | | 15 | And the following certificate templates exist: 16 | | name | 17 | | Certificate 1 | 18 | 19 | Scenario: Options available for default to manager 20 | When I log in as "manager" 21 | And I am on site homepage 22 | And I follow "Site administration" 23 | Then I should see "Manage certificate templates" 24 | And I should see "Verify certificates" 25 | 26 | Scenario: Manager without manage capability should not see option to add certificate template 27 | And the following "permission overrides" exist: 28 | | capability | permission | role | contextlevel | reference | 29 | | tool/certificate:manage | Prevent | manager | System | | 30 | And I log in as "manager" 31 | And I am on site homepage 32 | And I follow "Site administration" 33 | Then I should see "Manage certificate templates" 34 | And I should see "Verify certificates" 35 | And I should not see "Certificate images" 36 | And I should not see "Add certificate template" 37 | 38 | Scenario: Manager without manage and image capabilities should not see option to manage images 39 | And the following "permission overrides" exist: 40 | | capability | permission | role | contextlevel | reference | 41 | | tool/certificate:manage | Prevent | manager | System | | 42 | And I log in as "manager" 43 | And I am on site homepage 44 | And I follow "Site administration" 45 | Then I should see "Manage certificate templates" 46 | And I should not see "Certificate images" 47 | 48 | @javascript 49 | Scenario: Issue new certificate as manager without manage capability 50 | And the following "permission overrides" exist: 51 | | capability | permission | role | contextlevel | reference | 52 | | tool/certificate:manage | Prevent | manager | System | | 53 | And I log in as "manager" 54 | And I am on site homepage 55 | When I navigate to "Certificates > Manage certificate templates" in site administration 56 | And I wait "2" seconds 57 | And I click on "Issue certificates from this template" "link" 58 | And I wait "2" seconds 59 | And I open the autocomplete suggestions list 60 | And I click on "User One" item in the autocomplete list 61 | And I press key "27" in the field "Select users to issue certificate to" 62 | And I click on "Save" "button" in the ".modal.show .modal-footer" "css_element" 63 | And I click on "Certificates issued" "link" in the "Certificate 1" "table_row" 64 | Then "User One" "text" should exist in the "tool-certificate-issues" "table" 65 | And I log out 66 | 67 | Scenario: Manager without issue capability 68 | And the following "permission overrides" exist: 69 | | capability | permission | role | contextlevel | reference | 70 | | tool/certificate:issue | Prohibit | manager | System | | 71 | And I log in as "manager" 72 | And I am on site homepage 73 | When I navigate to "Certificates > Manage certificate templates" in site administration 74 | Then I should not see "Issue certificates from this template" 75 | --------------------------------------------------------------------------------