From 63160279f5c0dedc12b298b998f990a9f754fdf9 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 27 Nov 2020 16:02:07 +0800 Subject: [PATCH 01/40] Add missing full-stop to comment --- tests/email_certificate_task_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/email_certificate_task_test.php b/tests/email_certificate_task_test.php index 285acd6..65fa021 100644 --- a/tests/email_certificate_task_test.php +++ b/tests/email_certificate_task_test.php @@ -55,7 +55,7 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc // Create a custom certificate with no elements. $this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]); - // Enrol the user as a student + // Enrol the user as a student. $this->getDataGenerator()->enrol_user($user1->id, $course->id); // Run the task. From 26e72d770cf34ca5e6fa8d4c583704a6510365e6 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 27 Nov 2020 17:10:11 +0800 Subject: [PATCH 02/40] Update .travis.yml --- .travis.yml | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d18d67..ee125a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ language: php -# For javascript behat tests we need sudo +# For javascript behat tests we need sudo. sudo: true -dist: trusty cache: directories: @@ -10,28 +9,30 @@ cache: - $HOME/.npm php: - - 7.2 - - 7.4 + - 7.2 + - 7.4 addons: - firefox: 47.0.1 - postgresql: 9.5 - apt: - packages: - - openjdk-8-jre-headless + firefox: 47.0.1 + postgresql: "9.6" + apt: + packages: + - openjdk-8-jre-headless + +services: + - mysql + - postgresql env: - global: - - MOODLE_BRANCH=MOODLE_39_STABLE - - IGNORE_NAMES=mobile_*.mustache # Mobile mustache has specific syntax, ignore their templates - matrix: - - DB=pgsql - - DB=mysqli + global: + - MOODLE_BRANCH=MOODLE_39_STABLE + - IGNORE_NAMES=mobile_*.mustache # Mobile mustache has specific syntax, ignore their templates + matrix: + - DB=pgsql + - DB=mysqli before_install: - phpenv config-rm xdebug.ini - - nvm install 14.0 - - nvm use 14.0 - cd ../.. - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" @@ -47,6 +48,7 @@ script: - moodle-plugin-ci validate - moodle-plugin-ci savepoints - moodle-plugin-ci mustache - - moodle-plugin-ci grunt -t stylelint:css -t js + - moodle-plugin-ci grunt + # - moodle-plugin-ci phpdoc # Complains about missing PHPDocs when they exist in parent class. - moodle-plugin-ci phpunit - moodle-plugin-ci behat From 698b4563d1baceb5e2e94cf5c4e85a09218e802f Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 27 Nov 2020 20:02:35 +0800 Subject: [PATCH 03/40] Fix PHPDocs for the method get_course_field_value() --- element/coursefield/classes/element.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/element/coursefield/classes/element.php b/element/coursefield/classes/element.php index 8b81092..71e3f21 100644 --- a/element/coursefield/classes/element.php +++ b/element/coursefield/classes/element.php @@ -123,7 +123,7 @@ class element extends \mod_customcert\element { /** * Helper function that returns the field value in a human-readable format. * - * @param \stdClass $user the user we are rendering this for + * @param \stdClass $course the course we are rendering this for * @param bool $preview Is this a preview? * @return string */ From 4c8564a9b4724d056bd7cf3aad05ac8da21cc130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20F=C3=B6rster?= Date: Fri, 19 Mar 2021 17:31:17 +0100 Subject: [PATCH 04/40] Allow managers to download certificates (#412) Currently, it is not possible for editing teachers and managers to download certificates for users because we only check for $canreceive. --- view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view.php b/view.php index 2486b5f..fe16158 100644 --- a/view.php +++ b/view.php @@ -158,7 +158,7 @@ if (!$downloadown && !$downloadissue) { } echo $OUTPUT->footer($course); exit(); -} else if ($canreceive) { // Output to pdf. +} else if ($canreceive || $canmanage) { // Output to pdf. // Set the userid value of who we are downloading the certificate for. $userid = $USER->id; if ($downloadown) { From dfea4af2b6ed6340bd3d9ebeb327710117d46fed Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Tue, 9 Feb 2021 13:56:42 +0100 Subject: [PATCH 05/40] Add github actions (#407) --- .github/workflows/moodle-ci.yml | 120 ++++++++++++++++++ ...restore_customcert_activity_task.class.php | 4 +- classes/event/course_module_viewed.php | 10 ++ tests/behat/behat_mod_customcert.php | 2 +- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/moodle-ci.yml diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml new file mode 100644 index 0000000..2f59ba0 --- /dev/null +++ b/.github/workflows/moodle-ci.yml @@ -0,0 +1,120 @@ +name: Moodle Plugin CI + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-18.04 + + services: + postgres: + image: postgres:9.6 + env: + POSTGRES_USER: 'postgres' + POSTGRES_HOST_AUTH_METHOD: 'trust' + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + mariadb: + image: mariadb:10 + env: + MYSQL_USER: 'root' + MYSQL_ALLOW_EMPTY_PASSWORD: "true" + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 + + strategy: + fail-fast: false + matrix: + include: + - php: '7.4' + moodle-branch: 'MOODLE_310_STABLE' + database: pgsql + - php: '7.4' + moodle-branch: 'MOODLE_310_STABLE' + database: mariadb + - php: '7.2' + moodle-branch: 'MOODLE_310_STABLE' + database: pgsql + - php: '7.2' + moodle-branch: 'MOODLE_310_STABLE' + database: mariadb + + steps: + - name: Check out repository code + uses: actions/checkout@v2 + with: + path: plugin + + - name: Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + + - name: Initialise moodle-plugin-ci + run: | + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 + echo $(cd ci/bin; pwd) >> $GITHUB_PATH + echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH + sudo locale-gen en_AU.UTF-8 + echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV + + - name: Install moodle-plugin-ci + run: moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 + env: + DB: ${{ matrix.database }} + MOODLE_BRANCH: ${{ matrix.moodle-branch }} + MUSTACHE_IGNORE_NAMES: 'mobile_*.mustache' + + - name: PHP Lint + if: ${{ always() }} + run: moodle-plugin-ci phplint + + - name: PHP Copy/Paste Detector + continue-on-error: true # This step will show errors but will not fail + if: ${{ always() }} + run: moodle-plugin-ci phpcpd + + - name: PHP Mess Detector + continue-on-error: true # This step will show errors but will not fail + if: ${{ always() }} + run: moodle-plugin-ci phpmd + + - name: Moodle Code Checker + if: ${{ always() }} + run: moodle-plugin-ci codechecker --max-warnings 0 + + - name: Moodle PHPDoc Checker + if: ${{ always() }} + run: moodle-plugin-ci phpdoc + + - name: Validating + if: ${{ always() }} + run: moodle-plugin-ci validate + + - name: Check upgrade savepoints + if: ${{ always() }} + run: moodle-plugin-ci savepoints + + - name: Mustache Lint + if: ${{ always() }} + run: moodle-plugin-ci mustache + + - name: Grunt + if: ${{ always() }} + run: moodle-plugin-ci grunt --max-lint-warnings 0 + + - name: PHPUnit tests + if: ${{ always() }} + run: | + moodle-plugin-ci phpunit + cd moodle + vendor/bin/phpunit --fail-on-risky --disallow-test-output -v admin/tool/dataprivacy/tests/metadata_registry_test.php + vendor/bin/phpunit --fail-on-risky --disallow-test-output -v lib/tests/externallib_test.php + vendor/bin/phpunit --fail-on-risky --disallow-test-output -v privacy/tests/provider_test.php + + - name: Behat features + if: ${{ always() }} + run: moodle-plugin-ci behat --profile chrome diff --git a/backup/moodle2/restore_customcert_activity_task.class.php b/backup/moodle2/restore_customcert_activity_task.class.php index dbb58f2..39e6657 100644 --- a/backup/moodle2/restore_customcert_activity_task.class.php +++ b/backup/moodle2/restore_customcert_activity_task.class.php @@ -75,8 +75,8 @@ class restore_customcert_activity_task extends restore_activity_task { } /** - * Define the restore log rules that will be applied by the {@link restore_logs_processor} when restoring - * customcert logs. It must return one array of {@link restore_log_rule} objects. + * Define the restore log rules that will be applied by the {@see restore_logs_processor} when restoring + * customcert logs. It must return one array of {@see restore_log_rule} objects. * * @return array the restore log rules */ diff --git a/classes/event/course_module_viewed.php b/classes/event/course_module_viewed.php index c1ff0c4..2393192 100644 --- a/classes/event/course_module_viewed.php +++ b/classes/event/course_module_viewed.php @@ -43,10 +43,20 @@ class course_module_viewed extends \core\event\course_module_viewed { parent::init(); } + /** + * {@inheritdoc} + * + * @return string[] + */ public static function get_objectid_mapping() { return array('db' => 'customcert', 'restore' => 'customcert'); } + /** + * {@inheritdoc} + * + * @return bool + */ public static function get_other_mapping() { // No need to map. return false; diff --git a/tests/behat/behat_mod_customcert.php b/tests/behat/behat_mod_customcert.php index 8f2d6a6..f210962 100644 --- a/tests/behat/behat_mod_customcert.php +++ b/tests/behat/behat_mod_customcert.php @@ -40,7 +40,7 @@ class behat_mod_customcert extends behat_base { /** * Adds an element to the specified page of a template. * - * @codingStandardsIgnoreLine + * phpcs:ignore * @Given /^I add the element "(?P(?:[^"]|\\")*)" to page "(?P\d+)" of the "(?P(?:[^"]|\\")*)" certificate template$/ * @param string $elementname * @param int $pagenum From 89516bf17d69414b81cb0cac58eb4b88c41e239a Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sat, 3 Apr 2021 10:13:53 +0800 Subject: [PATCH 06/40] Set for version 3.9 (#407) --- .github/workflows/moodle-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 2f59ba0..ab75d55 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -29,16 +29,16 @@ jobs: matrix: include: - php: '7.4' - moodle-branch: 'MOODLE_310_STABLE' + moodle-branch: 'MOODLE_39_STABLE' database: pgsql - php: '7.4' - moodle-branch: 'MOODLE_310_STABLE' + moodle-branch: 'MOODLE_39_STABLE' database: mariadb - php: '7.2' - moodle-branch: 'MOODLE_310_STABLE' + moodle-branch: 'MOODLE_39_STABLE' database: pgsql - php: '7.2' - moodle-branch: 'MOODLE_310_STABLE' + moodle-branch: 'MOODLE_39_STABLE' database: mariadb steps: From 7df31f16fb58dd4402af74a680915114360d1a43 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sat, 3 Apr 2021 10:37:15 +0800 Subject: [PATCH 07/40] Add ability to show description on course page (#406) --- lib.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib.php b/lib.php index 4633d62..db784ee 100644 --- a/lib.php +++ b/lib.php @@ -264,6 +264,8 @@ function customcert_supports($feature) { return true; case FEATURE_MOD_INTRO: return true; + case FEATURE_SHOW_DESCRIPTION: + return true; case FEATURE_COMPLETION_TRACKS_VIEWS: return true; case FEATURE_BACKUP_MOODLE2: From 05b523eaa6a3919f9373d0efedf98be442d6053c Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sat, 3 Apr 2021 11:28:17 +0800 Subject: [PATCH 08/40] Updated CHANGES.md --- CHANGES.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4ecc8de..9653c93 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169. +## [3.9.1] - 2021-XX-YY + +### Added +- Usage of github actions (#407). +- The ability to show the description on the course page (#406). + +### Fixed +- Managers are now able to download their students' certificates (#412). + ## [3.8.5] - 2020-11-26 ### Added From 8e2e1a233629bdbdcaab1fd0105757d9a028d16f Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 5 Apr 2021 16:22:33 +0800 Subject: [PATCH 09/40] Add ability to choose how to deliver the certificate (#401) --- classes/certificate.php | 10 ++++++++++ classes/template.php | 20 +++++++++++++------- db/install.xml | 1 + db/upgrade.php | 12 ++++++++++++ lang/en/customcert.php | 3 +++ mod_form.php | 27 +++++++++++++-------------- version.php | 2 +- 7 files changed, 53 insertions(+), 22 deletions(-) diff --git a/classes/certificate.php b/classes/certificate.php index 0dd842e..39168dd 100644 --- a/classes/certificate.php +++ b/classes/certificate.php @@ -37,6 +37,16 @@ defined('MOODLE_INTERNAL') || die(); */ class certificate { + /** + * Send the file inline to the browser. + */ + const DELIVERY_OPTION_INLINE = 'I'; + + /** + * Send to the browser and force a file download + */ + const DELIVERY_OPTION_DOWNLOAD = 'D'; + /** * @var string the print protection variable */ diff --git a/classes/template.php b/classes/template.php index 6bf8ac0..10be74c 100644 --- a/classes/template.php +++ b/classes/template.php @@ -253,7 +253,7 @@ class template { * @param bool $return Do we want to return the contents of the PDF? * @return string|void Can return the PDF in string format if specified. */ - public function generate_pdf($preview = false, $userid = null, $return = false) { + public function generate_pdf(bool $preview = false, int $userid = null, bool $return = false) { global $CFG, $DB, $USER; if (empty($userid)) { @@ -269,12 +269,18 @@ class template { // Create the pdf object. $pdf = new \pdf(); + $customcert = $DB->get_record('customcert', ['templateid' => $this->id]); + // If the template belongs to a certificate then we need to check what permissions we set for it. - if ($protection = $DB->get_field('customcert', 'protection', array('templateid' => $this->id))) { - if (!empty($protection)) { - $protection = explode(', ', $protection); - $pdf->SetProtection($protection); - } + $protection = $customcert->protection; + if (!empty($protection)) { + $protection = explode(', ', $protection); + $pdf->SetProtection($protection); + } + + $deliveryoption = $customcert->deliveryoption; + if (empty($deliveryoption)) { + $deliveryoption = certificate::DELIVERY_OPTION_INLINE; } $pdf->setPrintHeader(false); @@ -320,7 +326,7 @@ class template { return $pdf->Output('', 'S'); } - $pdf->Output($filename, 'I'); + $pdf->Output($filename, $deliveryoption); } } diff --git a/db/install.xml b/db/install.xml index f6ac796..22fe3ec 100644 --- a/db/install.xml +++ b/db/install.xml @@ -14,6 +14,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index 57d2b4f..bbb684f 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -166,5 +166,17 @@ function xmldb_customcert_upgrade($oldversion) { upgrade_mod_savepoint(true, 2019111803, 'customcert'); } + if ($oldversion < 2020061501) { + $table = new xmldb_table('customcert'); + $field = new xmldb_field('deliveryoption', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'verifyany'); + + // Conditionally launch add field. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + upgrade_mod_savepoint(true, 2020061501, 'customcert'); + } + return true; } diff --git a/lang/en/customcert.php b/lang/en/customcert.php index 8e2fc43..7ed7b9a 100644 --- a/lang/en/customcert.php +++ b/lang/en/customcert.php @@ -57,6 +57,9 @@ $string['deleteissueconfirm'] = 'Are you sure you want to delete this certificat $string['deleteissuedcertificates'] = 'Delete issued certificates'; $string['deletepageconfirm'] = 'Are you sure you want to delete this certificate page?'; $string['deletetemplateconfirm'] = 'Are you sure you want to delete this certificate template?'; +$string['deliveryoptiondownload'] = 'Send to the browser and force a file download'; +$string['deliveryoptioninline'] = 'Send the file inline to the browser'; +$string['deliveryoptions'] = 'Delivery options'; $string['description'] = 'Description'; $string['duplicate'] = 'Duplicate'; $string['duplicateconfirm'] = 'Duplicate confirmation'; diff --git a/mod_form.php b/mod_form.php index fb023a4..e82c4a5 100644 --- a/mod_form.php +++ b/mod_form.php @@ -22,6 +22,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use mod_customcert\certificate; + defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); require_once($CFG->dirroot.'/course/moodleform_mod.php'); @@ -55,14 +57,20 @@ class mod_customcert_mod_form extends moodleform_mod { $this->standard_intro_elements(get_string('description', 'customcert')); - $optionsheader = $mform->createElement('header', 'options', get_string('options', 'customcert')); + $mform->addElement('header', 'options', get_string('options', 'customcert')); + + $deliveryoptions = [ + certificate::DELIVERY_OPTION_INLINE => get_string('deliveryoptioninline', 'customcert'), + certificate::DELIVERY_OPTION_DOWNLOAD => get_string('deliveryoptiondownload', 'customcert') + ]; + $mform->addElement('select', 'deliveryoption', get_string('deliveryoptions', 'customcert'), $deliveryoptions); + $mform->setDefault('deliveryoption', certificate::DELIVERY_OPTION_INLINE); if (has_capability('mod/customcert:manageemailstudents', $this->get_context())) { $mform->addElement('selectyesno', 'emailstudents', get_string('emailstudents', 'customcert')); $mform->setDefault('emailstudents', get_config('customcert', 'emailstudents')); $mform->addHelpButton('emailstudents', 'emailstudents', 'customcert'); $mform->setType('emailstudents', PARAM_INT); - $firstoption = 'emailstudents'; } if (has_capability('mod/customcert:manageemailteachers', $this->get_context())) { @@ -70,7 +78,6 @@ class mod_customcert_mod_form extends moodleform_mod { $mform->setDefault('emailteachers', get_config('customcert', 'emailteachers')); $mform->addHelpButton('emailteachers', 'emailteachers', 'customcert'); $mform->setType('emailteachers', PARAM_INT); - $firstoption = empty($firstoption) ? 'emailteachers' : $firstoption; } if (has_capability('mod/customcert:manageemailothers', $this->get_context())) { @@ -78,7 +85,6 @@ class mod_customcert_mod_form extends moodleform_mod { $mform->addHelpButton('emailothers', 'emailothers', 'customcert'); $mform->setDefault('emailothers', get_config('customcert', 'emailothers')); $mform->setType('emailothers', PARAM_TEXT); - $firstoption = empty($firstoption) ? 'emailothers' : $firstoption; } if (has_capability('mod/customcert:manageverifyany', $this->get_context())) { @@ -86,7 +92,6 @@ class mod_customcert_mod_form extends moodleform_mod { $mform->addHelpButton('verifyany', 'verifycertificateanyone', 'customcert'); $mform->setDefault('verifyany', get_config('customcert', 'verifyany')); $mform->setType('verifyany', PARAM_INT); - $firstoption = empty($firstoption) ? 'verifyany' : $firstoption; } if (has_capability('mod/customcert:managerequiredtime', $this->get_context())) { @@ -94,7 +99,6 @@ class mod_customcert_mod_form extends moodleform_mod { $mform->addHelpButton('requiredtime', 'coursetimereq', 'customcert'); $mform->setDefault('requiredtime', get_config('customcert', 'requiredtime')); $mform->setType('requiredtime', PARAM_INT); - $firstoption = empty($firstoption) ? 'requiredtime' : $firstoption; } if (has_capability('mod/customcert:manageprotection', $this->get_context())) { @@ -106,11 +110,6 @@ class mod_customcert_mod_form extends moodleform_mod { $mform->setType('protection_print', PARAM_BOOL); $mform->setType('protection_modify', PARAM_BOOL); $mform->setType('protection_copy', PARAM_BOOL); - $firstoption = empty($firstoption) ? 'protection_print' : $firstoption; - } - - if (!empty($firstoption)) { - $mform->insertElementBefore($optionsheader, $firstoption); } $this->standard_coursemodule_elements(); @@ -227,13 +226,13 @@ class mod_customcert_mod_form extends moodleform_mod { $protection = explode(', ', $protection); - if (in_array(\mod_customcert\certificate::PROTECTION_PRINT, $protection)) { + if (in_array(certificate::PROTECTION_PRINT, $protection)) { $data->protection_print = 1; } - if (in_array(\mod_customcert\certificate::PROTECTION_MODIFY, $protection)) { + if (in_array(certificate::PROTECTION_MODIFY, $protection)) { $data->protection_modify = 1; } - if (in_array(\mod_customcert\certificate::PROTECTION_COPY, $protection)) { + if (in_array(certificate::PROTECTION_COPY, $protection)) { $data->protection_copy = 1; } diff --git a/version.php b/version.php index fcaff51..9d85f62 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); -$plugin->version = 2020061500; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2020061501; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2020061500; // Requires this Moodle version (3.9). $plugin->cron = 0; // Period for cron to check this module (secs). $plugin->component = 'mod_customcert'; From 4881963650da2390fa54bf13fc5e32e8063d6566 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 5 Apr 2021 16:50:25 +0800 Subject: [PATCH 10/40] Updated CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 9653c93..bef7ca2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Added - Usage of github actions (#407). - The ability to show the description on the course page (#406). +- The ability to choose how to deliver the certificate (#401) ### Fixed - Managers are now able to download their students' certificates (#412). From 00e9eaba4ddcd7fa776184c5e4c9b23d36dfb270 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 5 Apr 2021 19:50:39 +0800 Subject: [PATCH 11/40] Fix get_course_time() allowing users to view certificate early (#403) --- CHANGES.md | 3 ++- classes/certificate.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bef7ca2..d1a61b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,10 +9,11 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Added - Usage of github actions (#407). - The ability to show the description on the course page (#406). -- The ability to choose how to deliver the certificate (#401) +- The ability to choose how to deliver the certificate (#401). ### Fixed - Managers are now able to download their students' certificates (#412). +- Users being able to view the certificate before the required time set (#403). ## [3.8.5] - 2020-11-26 diff --git a/classes/certificate.php b/classes/certificate.php index 39168dd..c525ef2 100644 --- a/classes/certificate.php +++ b/classes/certificate.php @@ -227,7 +227,7 @@ class certificate { $totaltime = 0; } $delay = $log->$timefield - $lasthit; - if ($delay > ($CFG->sessiontimeout * 60)) { + if ($delay > $CFG->sessiontimeout) { // The difference between the last log and the current log is more than // the timeout Register session value so that we have found a session! $login = $log->$timefield; From 54be90f5c470c9f8e80b134afb3b81ff1d9c5b84 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 5 Apr 2021 20:08:25 +0800 Subject: [PATCH 12/40] Use instance of moodle_url() in the function notice() --- view.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/view.php b/view.php index fe16158..9b8af82 100644 --- a/view.php +++ b/view.php @@ -56,7 +56,8 @@ if ($customcert->requiredtime && !$canmanage) { if (\mod_customcert\certificate::get_course_time($course->id) < ($customcert->requiredtime * 60)) { $a = new stdClass; $a->requiredtime = $customcert->requiredtime; - notice(get_string('requiredtimenotmet', 'customcert', $a), "$CFG->wwwroot/course/view.php?id=$course->id"); + $url = new moodle_url('/course/view.php', ['id' => $course->id]); + notice(get_string('requiredtimenotmet', 'customcert', $a), $url); die; } } From 52be3400f7bdf2ce3bc9431db61119197ca2e1fa Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 5 Apr 2021 20:11:02 +0800 Subject: [PATCH 13/40] Add type hinting to get_course_time() --- classes/certificate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/certificate.php b/classes/certificate.php index c525ef2..bbc633f 100644 --- a/classes/certificate.php +++ b/classes/certificate.php @@ -175,7 +175,7 @@ class certificate { * @param int $userid * @return int the total time spent in seconds */ - public static function get_course_time($courseid, $userid = 0) { + public static function get_course_time(int $courseid, int $userid = 0): int { global $CFG, $DB, $USER; if (empty($userid)) { From 29deb01aaf49a9750510a3013f20b869fba9037d Mon Sep 17 00:00:00 2001 From: Mikhail Golenkov Date: Thu, 15 Apr 2021 14:54:11 +1000 Subject: [PATCH 14/40] Fix the issue with displaying PDF when debugging is ON (#420) --- classes/template.php | 10 +++++----- my_certificates.php | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/classes/template.php b/classes/template.php index 10be74c..de1424c 100644 --- a/classes/template.php +++ b/classes/template.php @@ -272,15 +272,15 @@ class template { $customcert = $DB->get_record('customcert', ['templateid' => $this->id]); // If the template belongs to a certificate then we need to check what permissions we set for it. - $protection = $customcert->protection; - if (!empty($protection)) { - $protection = explode(', ', $protection); + if (!empty($customcert->protection)) { + $protection = explode(', ', $customcert->protection); $pdf->SetProtection($protection); } - $deliveryoption = $customcert->deliveryoption; - if (empty($deliveryoption)) { + if (empty($customcert->deliveryoption)) { $deliveryoption = certificate::DELIVERY_OPTION_INLINE; + } else { + $deliveryoption = $customcert->deliveryoption; } $pdf->setPrintHeader(false); diff --git a/my_certificates.php b/my_certificates.php index 3312c12..5ac04ea 100644 --- a/my_certificates.php +++ b/my_certificates.php @@ -52,6 +52,12 @@ if (($userid != $USER->id) && !has_capability('mod/customcert:viewallcertificate print_error('You are not allowed to view these certificates'); } +$PAGE->set_url($pageurl); +$PAGE->set_context(context_user::instance($userid)); +$PAGE->set_title(get_string('mycertificates', 'customcert')); +$PAGE->set_pagelayout('standard'); +$PAGE->navigation->extend_for_user($user); + // Check if we requested to download a certificate. if ($downloadcert) { $template = $DB->get_record('customcert_templates', array('id' => $customcert->templateid), '*', MUST_EXIST); @@ -68,12 +74,6 @@ if ($table->is_downloading()) { exit(); } -$PAGE->set_url($pageurl); -$PAGE->set_context(context_user::instance($userid)); -$PAGE->set_title(get_string('mycertificates', 'customcert')); -$PAGE->set_pagelayout('standard'); -$PAGE->navigation->extend_for_user($user); - // Additional page setup. $PAGE->navbar->add(get_string('profile'), new moodle_url('/user/profile.php', array('id' => $userid))); $PAGE->navbar->add(get_string('mycertificates', 'customcert')); From 810c4b2fcfba30ab27a291b053217a2513c7d677 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 16 Apr 2021 14:41:30 +0800 Subject: [PATCH 15/40] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index d1a61b0..617991d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Fixed - Managers are now able to download their students' certificates (#412). - Users being able to view the certificate before the required time set (#403). +- Fixed the issue with displaying PDF when debugging is ON (#420). ## [3.8.5] - 2020-11-26 From 0f66037b8f90b9bc0ea8f239e724d6f3ab93f23b Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Thu, 27 May 2021 18:24:01 +0800 Subject: [PATCH 16/40] Fix Moodle Code Checker complaints --- backup/moodle2/backup_customcert_activity_task.class.php | 2 +- backup/moodle2/restore_customcert_activity_task.class.php | 6 +++--- classes/element.php | 4 ++-- my_certificates.php | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backup/moodle2/backup_customcert_activity_task.class.php b/backup/moodle2/backup_customcert_activity_task.class.php index a071cc3..a4f2ae6 100644 --- a/backup/moodle2/backup_customcert_activity_task.class.php +++ b/backup/moodle2/backup_customcert_activity_task.class.php @@ -56,7 +56,7 @@ class backup_customcert_activity_task extends backup_activity_task { * @param string $content * @return mixed|string */ - static public function encode_content_links($content) { + public static function encode_content_links($content) { global $CFG; $base = preg_quote($CFG->wwwroot, "/"); diff --git a/backup/moodle2/restore_customcert_activity_task.class.php b/backup/moodle2/restore_customcert_activity_task.class.php index 39e6657..d21228e 100644 --- a/backup/moodle2/restore_customcert_activity_task.class.php +++ b/backup/moodle2/restore_customcert_activity_task.class.php @@ -53,7 +53,7 @@ class restore_customcert_activity_task extends restore_activity_task { /** * Define the contents in the activity that must be processed by the link decoder. */ - static public function define_decode_contents() { + public static function define_decode_contents() { $contents = array(); $contents[] = new restore_decode_content('customcert', array('intro'), 'customcert'); @@ -64,7 +64,7 @@ class restore_customcert_activity_task extends restore_activity_task { /** * Define the decoding rules for links belonging to the activity to be executed by the link decoder. */ - static public function define_decode_rules() { + public static function define_decode_rules() { $rules = array(); $rules[] = new restore_decode_rule('CUSTOMCERTVIEWBYID', '/mod/customcert/view.php?id=$1', 'course_module'); @@ -80,7 +80,7 @@ class restore_customcert_activity_task extends restore_activity_task { * * @return array the restore log rules */ - static public function define_restore_log_rules() { + public static function define_restore_log_rules() { $rules = array(); $rules[] = new restore_log_rule('customcert', 'add', 'view.php?id={course_module}', '{customcert}'); diff --git a/classes/element.php b/classes/element.php index 4d1c8e0..b812639 100644 --- a/classes/element.php +++ b/classes/element.php @@ -377,7 +377,7 @@ abstract class element { * @param bool $preview true if it is a preview, false otherwise * @param \stdClass $user the user we are rendering this for */ - public abstract function render($pdf, $preview, $user); + abstract public function render($pdf, $preview, $user); /** * Render the element in html. @@ -389,7 +389,7 @@ abstract class element { * * @return string the html */ - public abstract function render_html(); + abstract public function render_html(); /** * Handles deleting any data this element may have introduced. diff --git a/my_certificates.php b/my_certificates.php index 5ac04ea..71332aa 100644 --- a/my_certificates.php +++ b/my_certificates.php @@ -49,7 +49,7 @@ $user = \core_user::get_user($userid, '*', MUST_EXIST); // If we are viewing certificates that are not for the currently logged in user then do a capability check. if (($userid != $USER->id) && !has_capability('mod/customcert:viewallcertificates', context_system::instance())) { - print_error('You are not allowed to view these certificates'); + throw new moodle_exception('You are not allowed to view these certificates'); } $PAGE->set_url($pageurl); From 39e2bdd95df40dd18f4bbd4bfd861f3d00677442 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Thu, 27 May 2021 19:21:57 +0800 Subject: [PATCH 17/40] Removed .travis.yml file --- .travis.yml | 54 ----------------------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ee125a0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,54 +0,0 @@ -language: php - -# For javascript behat tests we need sudo. -sudo: true - -cache: - directories: - - $HOME/.composer/cache - - $HOME/.npm - -php: - - 7.2 - - 7.4 - -addons: - firefox: 47.0.1 - postgresql: "9.6" - apt: - packages: - - openjdk-8-jre-headless - -services: - - mysql - - postgresql - -env: - global: - - MOODLE_BRANCH=MOODLE_39_STABLE - - IGNORE_NAMES=mobile_*.mustache # Mobile mustache has specific syntax, ignore their templates - matrix: - - DB=pgsql - - DB=mysqli - -before_install: - - phpenv config-rm xdebug.ini - - cd ../.. - - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 - - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" - -install: - - moodle-plugin-ci install - -script: - - moodle-plugin-ci phplint - # - moodle-plugin-ci phpcpd # subplugins often have similar code and cause "duplicated code" errors - # - moodle-plugin-ci phpmd # too much noise from this check, maybe, some day... - - moodle-plugin-ci codechecker - - moodle-plugin-ci validate - - moodle-plugin-ci savepoints - - moodle-plugin-ci mustache - - moodle-plugin-ci grunt - # - moodle-plugin-ci phpdoc # Complains about missing PHPDocs when they exist in parent class. - - moodle-plugin-ci phpunit - - moodle-plugin-ci behat From 135630487c04d40c309cd7bbebc55f69ec24732a Mon Sep 17 00:00:00 2001 From: hieuvu Date: Mon, 31 May 2021 08:26:05 +0700 Subject: [PATCH 18/40] Add actions title to elements table (#425) --- classes/edit_form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/edit_form.php b/classes/edit_form.php index 50f642c..f091998 100644 --- a/classes/edit_form.php +++ b/classes/edit_form.php @@ -247,7 +247,7 @@ class edit_form extends \moodleform { // Create a table to display these elements. $table = new \html_table(); $table->attributes = array('class' => 'generaltable elementstable'); - $table->head = array(get_string('name', 'customcert'), get_string('type', 'customcert'), ''); + $table->head = array(get_string('name', 'customcert'), get_string('type', 'customcert'), get_string('actions')); $table->align = array('left', 'left', 'left'); // Loop through and add the elements to the table. foreach ($elements as $element) { From 8a80ab82d83dc954fd4f0b59372ecec227b5653d Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sun, 13 Jun 2021 13:32:11 +0800 Subject: [PATCH 19/40] Set proper context when sending emails (#402) --- CHANGES.md | 3 ++- classes/task/email_certificate_task.php | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 617991d..d8ead16 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169. -## [3.9.1] - 2021-XX-YY +## [3.9.1] - 2021-06-13 ### Added - Usage of github actions (#407). @@ -15,6 +15,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g - Managers are now able to download their students' certificates (#412). - Users being able to view the certificate before the required time set (#403). - Fixed the issue with displaying PDF when debugging is ON (#420). +- Using incorrect context when sending emails (#402). ## [3.8.5] - 2020-11-26 diff --git a/classes/task/email_certificate_task.php b/classes/task/email_certificate_task.php index fb27769..e0906dd 100644 --- a/classes/task/email_certificate_task.php +++ b/classes/task/email_certificate_task.php @@ -84,6 +84,9 @@ class email_certificate_task extends \core\task\scheduled_task { // Get the context. $context = \context::instance_by_id($customcert->contextid); + // Set the $PAGE context - this ensure settings, such as language, are kept and don't default to the site settings. + $PAGE->set_context($context); + // Get the person we are going to send this email on behalf of. $userfrom = \core_user::get_noreply_user(); From c3a9172d8d22dbd2883aeba43e1a985a0bbdcf41 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sun, 13 Jun 2021 14:04:18 +0800 Subject: [PATCH 20/40] Use 'cron_setup_user' when sending emails (#414) --- CHANGES.md | 1 + classes/task/email_certificate_task.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index d8ead16..a2c514a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g - Users being able to view the certificate before the required time set (#403). - Fixed the issue with displaying PDF when debugging is ON (#420). - Using incorrect context when sending emails (#402). +- Use `cron_setup_user` when sending emails (#414). ## [3.8.5] - 2020-11-26 diff --git a/classes/task/email_certificate_task.php b/classes/task/email_certificate_task.php index e0906dd..a4ac712 100644 --- a/classes/task/email_certificate_task.php +++ b/classes/task/email_certificate_task.php @@ -179,6 +179,9 @@ class email_certificate_task extends \core\task\scheduled_task { // Now, email the people we need to. foreach ($issuedusers as $user) { + // Set up the user. + cron_setup_user($user); + $userfullname = fullname($user); $info->userfullname = $userfullname; From 8effac9d93e3adbf860ceae647e19c5d3f9ba126 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sun, 13 Jun 2021 14:08:48 +0800 Subject: [PATCH 21/40] Bump version --- version.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.php b/version.php index 9d85f62..f515de5 100644 --- a/version.php +++ b/version.php @@ -24,10 +24,10 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); -$plugin->version = 2020061501; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2020061502; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2020061500; // Requires this Moodle version (3.9). $plugin->cron = 0; // Period for cron to check this module (secs). $plugin->component = 'mod_customcert'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = "3.9.0"; // User-friendly version number. +$plugin->release = "3.9.1"; // User-friendly version number. From e99d25a18b612dc6822d3ae8c1fff7ec2d1c4088 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 18 Jun 2021 09:13:56 +0200 Subject: [PATCH 22/40] Adapt mobile app code to Ionic 5 (#431) --- classes/output/mobile.php | 10 +- ...mobile_view_activity_page_ionic3.mustache} | 0 .../mobile_view_activity_page_latest.mustache | 169 ++++++++++++++++++ 3 files changed, 176 insertions(+), 3 deletions(-) rename templates/{mobile_view_activity_page.mustache => mobile_view_activity_page_ionic3.mustache} (100%) create mode 100644 templates/mobile_view_activity_page_latest.mustache diff --git a/classes/output/mobile.php b/classes/output/mobile.php index 5e480c7..e4d3eda 100644 --- a/classes/output/mobile.php +++ b/classes/output/mobile.php @@ -44,9 +44,10 @@ class mobile { global $OUTPUT, $DB, $USER; $args = (object) $args; + $versionname = $args->appversioncode >= 3950 ? 'latest' : 'ionic3'; $cmid = $args->cmid; - $groupid = empty($args->group) ? 0 : $args->group; // By default, group 0. + $groupid = empty($args->group) ? 0 : (int) $args->group; // By default, group 0. // Capabilities check. $cm = get_coursemodule_from_id('customcert', $cmid); @@ -114,6 +115,7 @@ class mobile { 'showreport' => $showreport, 'hasrecipients' => !empty($recipients), 'recipients' => array_values($recipients), + 'numrecipients' => count($recipients), 'currenttimestamp' => time() ]; @@ -121,11 +123,13 @@ class mobile { 'templates' => [ [ 'id' => 'main', - 'html' => $OUTPUT->render_from_template('mod_customcert/mobile_view_activity_page', $data), + 'html' => $OUTPUT->render_from_template("mod_customcert/mobile_view_activity_page_$versionname", $data), ], ], 'javascript' => '', - 'otherdata' => '' + 'otherdata' => [ + 'group' => $groupid, + ] ]; } diff --git a/templates/mobile_view_activity_page.mustache b/templates/mobile_view_activity_page_ionic3.mustache similarity index 100% rename from templates/mobile_view_activity_page.mustache rename to templates/mobile_view_activity_page_ionic3.mustache diff --git a/templates/mobile_view_activity_page_latest.mustache b/templates/mobile_view_activity_page_latest.mustache new file mode 100644 index 0000000..6018c2e --- /dev/null +++ b/templates/mobile_view_activity_page_latest.mustache @@ -0,0 +1,169 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template mod_customcert/mobile_view_activity_page + + The main page to view the custom certificate activity + + Classes required for JS: + * None + + Data attibutes required for JS: + * All data attributes are required + + Context variables required for this template: + * certificate + * cmid + * hasissues + * issues + * showgroups + * groups + * canmanage + * requiredtimemet + * hasrecipients + * recipients + * fileurl + * showreport + * currenttimestamp + + Example context (json): + { + "certificate": { + "id": "1", + "course": "2", + "name": "A rad certificate name!", + "intro": "A certificate", + "requiredtime": "60" + }, + "cmid": "25", + "issue": { + "timecreated": "1528370177" + }, + "showgroups": "true", + "groups": [ + { + "id": "2", + "selected": "false", + "name": "Group A" + } + ], + "canmanage": "true", + "requiredtimemet": "true", + "fileurl": "http://yoursite.com/mod/customcert/mobile/pluginfile.php?id=4", + "showreport": "true", + "hasrecipients": "true", + "recipients": [ + { + "id": "2", + "issueid": "3", + "displayname": "Michaelangelo (Mickey)", + "fileurl": "http://yoursite.com/mod/customcert/mobile/pluginfile.php?id=4", + "timecreated": "1528370177" + } + ], + "currenttimestamp": "1528370177" + } +}} +{{=<% %>=}} + + +<%^canmanage%> + <%#requiredtimemet%> + + + {{ 'plugin.mod_customcert.receiveddate' | translate }} +
+
+ <%#issue%> + {{ <% timecreated %> | coreToLocaleString }} + <%/issue%> + <%^issue%> + {{ 'plugin.mod_customcert.notissued' | translate }} + <%/issue%> +
+
+
+ + + +
+
+ <%/requiredtimemet%> + <%^requiredtimemet%> + + +

{{ 'plugin.mod_customcert.requiredtimenotmet' | translate: {$a: { requiredtime: <% certificate.requiredtime %>} } }}

+
+
+ <%/requiredtimemet%> +<%/canmanage%> +<%#canmanage%> + + + {{ 'plugin.mod_customcert.getcustomcert' | translate }} + +<%/canmanage%> +<%#showreport%> + + + {{ 'plugin.mod_customcert.listofissues' | translate: { $a: <% numrecipients %> } }} + + + <%#showgroups%> + + {{ 'plugin.mod_customcert.selectagroup' | translate }} + + <%#groups%> + <% name %> + <%/groups%> + + + <%/showgroups%> + <%#hasrecipients%> + <%#recipients%> + + + <% displayname %> +
+
{{ <% timecreated %> | coreToLocaleString }}
+
+
+ + + + <%#canmanage%> + + + + <%/canmanage%> +
+
+ <%/recipients%> + <%/hasrecipients%> + <%^hasrecipients%> + + + {{ 'plugin.mod_customcert.nothingtodisplay' | translate }} + + + <%/hasrecipients%> +<%/showreport%> +
From 3024bf1516b060b2bc7a0978d3c9738ce0347846 Mon Sep 17 00:00:00 2001 From: Michael Milette Date: Tue, 29 Jun 2021 21:10:52 +0000 Subject: [PATCH 23/40] Fix for multi-language issues (#433). - Filename of PDF when viewing/previewing PDF. - Page title tag when viewing/previewing PDF. - List of available templates. - Template Load dropdown list. --- classes/load_template_form.php | 4 ++++ classes/manage_templates_table.php | 3 ++- classes/template.php | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/classes/load_template_form.php b/classes/load_template_form.php index 48a3390..34ab93c 100644 --- a/classes/load_template_form.php +++ b/classes/load_template_form.php @@ -60,6 +60,10 @@ class load_template_form extends \moodleform { $templates = $DB->get_records_menu('customcert_templates', array('contextid' => \context_system::instance()->id), 'name ASC', 'id, name'); if ($templates) { + $context = \context_system::instance()->id; + foreach ($templates as $key => $template) { + $templates[$key] = format_string($template, true, ['context' => $context]); + } $group = array(); $group[] = $mform->createElement('select', 'ltid', '', $templates); $group[] = $mform->createElement('submit', 'loadtemplatesubmit', get_string('load', 'customcert')); diff --git a/classes/manage_templates_table.php b/classes/manage_templates_table.php index 8aad21c..b72a2d1 100644 --- a/classes/manage_templates_table.php +++ b/classes/manage_templates_table.php @@ -24,6 +24,7 @@ namespace mod_customcert; + defined('MOODLE_INTERNAL') || die; global $CFG; @@ -77,7 +78,7 @@ class manage_templates_table extends \table_sql { * @return string */ public function col_name($template) { - return $template->name; + return format_string($template->name, true, ['context' => $this->context]); } /** diff --git a/classes/template.php b/classes/template.php index de1424c..ded8163 100644 --- a/classes/template.php +++ b/classes/template.php @@ -283,12 +283,13 @@ class template { $deliveryoption = $customcert->deliveryoption; } + // Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename. + $filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.'); + $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); - $pdf->SetTitle($this->name); + $pdf->SetTitle($filename); $pdf->SetAutoPageBreak(true, 0); - // Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename. - $filename = rtrim($this->name, '.'); // This is the logic the TCPDF library uses when processing the name. This makes names // such as 'الشهادة' become empty, so set a default name in these cases. From a07c81a409a10448f84affdccea7729acadbaa4e Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Aug 2021 16:28:39 +0800 Subject: [PATCH 24/40] Minor changes and CHANGES.md note (#433) --- CHANGES.md | 5 +++++ classes/load_template_form.php | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a2c514a..7a6cd3b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169. +## [3.9.2] - 2021-??-?? + +### Fixed +- Fix places not using the multi-language filter (#433). + ## [3.9.1] - 2021-06-13 ### Added diff --git a/classes/load_template_form.php b/classes/load_template_form.php index 34ab93c..ef9a8d7 100644 --- a/classes/load_template_form.php +++ b/classes/load_template_form.php @@ -47,21 +47,21 @@ class load_template_form extends \moodleform { // Get the context. $context = $this->_customdata['context']; + $syscontext = \context_system::instance(); $mform->addElement('header', 'loadtemplateheader', get_string('loadtemplate', 'customcert')); // Display a link to the manage templates page. - if ($context->contextlevel != CONTEXT_SYSTEM && has_capability('mod/customcert:manage', \context_system::instance())) { + if ($context->contextlevel != CONTEXT_SYSTEM && has_capability('mod/customcert:manage', $syscontext)) { $link = \html_writer::link(new \moodle_url('/mod/customcert/manage_templates.php'), get_string('managetemplates', 'customcert')); $mform->addElement('static', 'managetemplates', '', $link); } - $templates = $DB->get_records_menu('customcert_templates', - array('contextid' => \context_system::instance()->id), 'name ASC', 'id, name'); - if ($templates) { - $context = \context_system::instance()->id; - foreach ($templates as $key => $template) { + $arrtemplates = $DB->get_records_menu('customcert_templates', ['contextid' => $syscontext->id], 'name ASC', 'id, name'); + if ($arrtemplates) { + $templates = []; + foreach ($arrtemplates as $key => $template) { $templates[$key] = format_string($template, true, ['context' => $context]); } $group = array(); From af28f5bad1c748893f6f4d4bed99a666069bf99b Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Aug 2021 16:53:24 +0800 Subject: [PATCH 25/40] Remove unnecessary new line --- classes/manage_templates_table.php | 1 - 1 file changed, 1 deletion(-) diff --git a/classes/manage_templates_table.php b/classes/manage_templates_table.php index b72a2d1..58b8acb 100644 --- a/classes/manage_templates_table.php +++ b/classes/manage_templates_table.php @@ -24,7 +24,6 @@ namespace mod_customcert; - defined('MOODLE_INTERNAL') || die; global $CFG; From b20eafe22f8124f19b03f1057b67c91e798d08b9 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Aug 2021 17:39:34 +0800 Subject: [PATCH 26/40] Add new lines at end of files --- ajax.php | 2 +- classes/admin_setting_link.php | 2 +- load_template.php | 2 +- tests/email_certificate_task_test.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ajax.php b/ajax.php index 4857859..b5b454d 100644 --- a/ajax.php +++ b/ajax.php @@ -54,4 +54,4 @@ foreach ($values as $value) { $element->posx = $value->posx; $element->posy = $value->posy; $DB->update_record('customcert_elements', $element); -} \ No newline at end of file +} diff --git a/classes/admin_setting_link.php b/classes/admin_setting_link.php index 19de718..f06090a 100644 --- a/classes/admin_setting_link.php +++ b/classes/admin_setting_link.php @@ -80,4 +80,4 @@ class admin_setting_link extends \admin_setting_configtext { return format_admin_setting($this, $this->visiblename, \html_writer::link($this->link, $this->linkname), $this->description, true, '', null, $query); } -} \ No newline at end of file +} diff --git a/load_template.php b/load_template.php index 2daa771..3e4bcce 100644 --- a/load_template.php +++ b/load_template.php @@ -97,4 +97,4 @@ $PAGE->navbar->add(get_string('loadtemplate', 'customcert')); echo $OUTPUT->header(); echo $OUTPUT->heading($heading); echo $OUTPUT->confirm(get_string('loadtemplatemsg', 'customcert'), $yesurl, $nourl); -echo $OUTPUT->footer(); \ No newline at end of file +echo $OUTPUT->footer(); diff --git a/tests/email_certificate_task_test.php b/tests/email_certificate_task_test.php index 65fa021..bcfe4cd 100644 --- a/tests/email_certificate_task_test.php +++ b/tests/email_certificate_task_test.php @@ -416,4 +416,4 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc // Confirm no emails were sent. $this->assertCount(0, $emails); } -} \ No newline at end of file +} From 227b1627215455d7d81298b16cd86dba1195ca6f Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Aug 2021 17:56:52 +0800 Subject: [PATCH 27/40] GHA: ROW_FORMAT=COMPRESSED deprecated in MariaDB 10.6 See MDL-72131. --- .github/workflows/moodle-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index ab75d55..e72c421 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -16,7 +16,7 @@ jobs: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 mariadb: - image: mariadb:10 + image: mariadb:10.5 env: MYSQL_USER: 'root' MYSQL_ALLOW_EMPTY_PASSWORD: "true" From d6d10d21acbcb8693e970d945d4a89e7a8b6d240 Mon Sep 17 00:00:00 2001 From: Sameer Ahmed Date: Tue, 6 Jul 2021 11:15:24 -0500 Subject: [PATCH 28/40] Display the course short name (#415) - Added a new select box to choose from course name or short description to display. --- element/coursename/classes/element.php | 72 +++++++++++++++++-- .../lang/en/customcertelement_coursename.php | 4 ++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/element/coursename/classes/element.php b/element/coursename/classes/element.php index 87a1764..c88c242 100644 --- a/element/coursename/classes/element.php +++ b/element/coursename/classes/element.php @@ -35,6 +35,33 @@ defined('MOODLE_INTERNAL') || die(); */ class element extends \mod_customcert\element { + /** + * This function renders the form elements when adding a customcert element. + * + * @param \MoodleQuickForm $mform the edit_form instance + */ + public function render_form_elements($mform) { + + // The course name display options. + $mform->addElement('select', 'coursenamedisplay', get_string('coursenamedisplay', 'customcertelement_coursename'), + self::get_course_name_display_options()); + $mform->setType('coursenamedisplay', PARAM_ALPHA); + $mform->addHelpButton('coursenamedisplay', 'coursenamedisplay', 'customcertelement_coursename'); + + parent::render_form_elements($mform); + } + + /** + * This will handle how form data will be saved into the data column in the + * customcert_elements table. + * + * @param \stdClass $data the form data + * @return string the text + */ + public function save_unique_data($data) { + return $data->coursenamedisplay; + } + /** * Handles rendering the element on the pdf. * @@ -43,7 +70,7 @@ class element extends \mod_customcert\element { * @param \stdClass $user the user we are rendering this for */ public function render($pdf, $preview, $user) { - \mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name()); + \mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name_detail()); } /** @@ -55,19 +82,54 @@ class element extends \mod_customcert\element { * @return string the html */ public function render_html() { - return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name()); + return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name_detail()); } /** - * Helper function that returns the category name. + * Sets the data on the form when editing an element. + * + * @param \MoodleQuickForm $mform the edit_form instance + */ + public function definition_after_data($mform) { + if (!empty($this->get_data())) { + $element = $mform->getElement('coursenamedisplay'); + $element->setValue($this->get_data()); + } + parent::definition_after_data($mform); + } + + /** + * Helper function that returns the selected course name detail (i.e. name or short description) for display. * * @return string */ - protected function get_course_name() : string { + protected function get_course_name_detail() : string { $courseid = \mod_customcert\element_helper::get_courseid($this->get_id()); $course = get_course($courseid); $context = \mod_customcert\element_helper::get_context($this->get_id()); - return format_string($course->fullname, true, ['context' => $context]); + // The name field to display. + $field = $this->get_data(); + // The name value to display. + $value = $course->fullname; + if ($field == 'courseshortdescription') { + $value = $course->shortname; + } + + return format_string($value, true, ['context' => $context]); + } + + /** + * Helper function to return all the possible name display options. + * + * @return array returns an array of name options + */ + public static function get_course_name_display_options() { + $coursenamedisplayoptions = array( + 'coursename' => get_string('coursename', 'customcertelement_coursename'), + 'courseshortdescription' => get_string('courseshortdescription', 'customcertelement_coursename') + ); + + return $coursenamedisplayoptions; } } diff --git a/element/coursename/lang/en/customcertelement_coursename.php b/element/coursename/lang/en/customcertelement_coursename.php index 48781e4..df10703 100644 --- a/element/coursename/lang/en/customcertelement_coursename.php +++ b/element/coursename/lang/en/customcertelement_coursename.php @@ -24,3 +24,7 @@ $string['pluginname'] = 'Course name'; $string['privacy:metadata'] = 'The Course name plugin does not store any personal data.'; +$string['coursenamedisplay'] = 'Course name / short description'; +$string['coursenamedisplay_help'] = 'Course name or short description you wish to display on certificate.'; +$string['coursename'] = 'Course name'; +$string['courseshortdescription'] = 'Course short description'; From c0c6bd1d47d0fd7d2423477572eb9fd93e8ebd3f Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Aug 2021 19:21:07 +0800 Subject: [PATCH 29/40] Minor code changes (#415) --- element/coursename/classes/element.php | 29 ++++++++++++------- .../lang/en/customcertelement_coursename.php | 9 +++--- tests/behat/managing_elements.feature | 22 +++++++------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/element/coursename/classes/element.php b/element/coursename/classes/element.php index c88c242..a5b274d 100644 --- a/element/coursename/classes/element.php +++ b/element/coursename/classes/element.php @@ -35,17 +35,26 @@ defined('MOODLE_INTERNAL') || die(); */ class element extends \mod_customcert\element { + /** + * The course short name. + */ + const COURSE_SHORT_NAME = 1; + + /** + * The course fullname. + */ + const COURSE_FULL_NAME = 2; + /** * This function renders the form elements when adding a customcert element. * * @param \MoodleQuickForm $mform the edit_form instance */ public function render_form_elements($mform) { - // The course name display options. $mform->addElement('select', 'coursenamedisplay', get_string('coursenamedisplay', 'customcertelement_coursename'), self::get_course_name_display_options()); - $mform->setType('coursenamedisplay', PARAM_ALPHA); + $mform->setType('coursenamedisplay', PARAM_INT); $mform->addHelpButton('coursenamedisplay', 'coursenamedisplay', 'customcertelement_coursename'); parent::render_form_elements($mform); @@ -103,7 +112,7 @@ class element extends \mod_customcert\element { * * @return string */ - protected function get_course_name_detail() : string { + protected function get_course_name_detail(): string { $courseid = \mod_customcert\element_helper::get_courseid($this->get_id()); $course = get_course($courseid); $context = \mod_customcert\element_helper::get_context($this->get_id()); @@ -112,7 +121,7 @@ class element extends \mod_customcert\element { $field = $this->get_data(); // The name value to display. $value = $course->fullname; - if ($field == 'courseshortdescription') { + if ($field == self::COURSE_SHORT_NAME) { $value = $course->shortname; } @@ -124,12 +133,10 @@ class element extends \mod_customcert\element { * * @return array returns an array of name options */ - public static function get_course_name_display_options() { - $coursenamedisplayoptions = array( - 'coursename' => get_string('coursename', 'customcertelement_coursename'), - 'courseshortdescription' => get_string('courseshortdescription', 'customcertelement_coursename') - ); - - return $coursenamedisplayoptions; + public static function get_course_name_display_options(): array { + return [ + self::COURSE_FULL_NAME => get_string('coursefullname', 'customcertelement_coursename'), + self::COURSE_SHORT_NAME => get_string('courseshortname', 'customcertelement_coursename') + ]; } } diff --git a/element/coursename/lang/en/customcertelement_coursename.php b/element/coursename/lang/en/customcertelement_coursename.php index df10703..d6b80d3 100644 --- a/element/coursename/lang/en/customcertelement_coursename.php +++ b/element/coursename/lang/en/customcertelement_coursename.php @@ -22,9 +22,10 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['coursenamedisplay'] = 'Type'; +$string['coursenamedisplay_help'] = 'Display the course full name or short name?'; +$string['coursefullname'] = 'Full name'; +$string['courseshortname'] = 'Short name'; $string['pluginname'] = 'Course name'; $string['privacy:metadata'] = 'The Course name plugin does not store any personal data.'; -$string['coursenamedisplay'] = 'Course name / short description'; -$string['coursenamedisplay_help'] = 'Course name or short description you wish to display on certificate.'; -$string['coursename'] = 'Course name'; -$string['courseshortdescription'] = 'Course short description'; + diff --git a/tests/behat/managing_elements.feature b/tests/behat/managing_elements.feature index 54bd0b6..f734eb3 100644 --- a/tests/behat/managing_elements.feature +++ b/tests/behat/managing_elements.feature @@ -100,20 +100,22 @@ Feature: Being able to manage elements in a certificate template # Course name. And I add the element "Course name" to page "1" of the "Custom certificate 1" certificate template And I set the following fields to these values: - | Font | Helvetica | - | Size | 20 | - | Colour | #045ECD | - | Width | 20 | - | Reference point location | Top left | + | Font | Helvetica | + | Type | Short name | + | Size | 20 | + | Colour | #045ECD | + | Width | 20 | + | Reference point location | Top left | And I press "Save changes" And I should see "Course name" in the "elementstable" "table" And I click on ".edit-icon" "css_element" in the "Course name" "table_row" And the following fields match these values: - | Font | Helvetica | - | Size | 20 | - | Colour | #045ECD | - | Width | 20 | - | Reference point location | Top left | + | Font | Helvetica | + | Type | Short name | + | Size | 20 | + | Colour | #045ECD | + | Width | 20 | + | Reference point location | Top left | And I press "Save changes" # Date. And I add the element "Date" to page "1" of the "Custom certificate 1" certificate template From 471b5cce73611a263c0ac927bdf9fc403d056328 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 4 Aug 2021 11:36:43 +0800 Subject: [PATCH 30/40] Update CHANGES.md --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7a6cd3b..0d9af38 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,9 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Fixed - Fix places not using the multi-language filter (#433). +### Added +- You can now choose the course short or full name to display (#415). + ## [3.9.1] - 2021-06-13 ### Added From 32b255cb0de12b63d1ee16ebfcfd0de8f534d412 Mon Sep 17 00:00:00 2001 From: Andrew Madden Date: Fri, 6 Aug 2021 12:31:04 +1000 Subject: [PATCH 31/40] Closes #449 The user id should be mapped to the equivalent user id in new sites during activity restore As the userid in the customcert_issues table were using the userid from the site where the activity was backed up, emails were being sent to those that had already received them. Theoretically there wwere also users who should have received an email who didn't get one. --- backup/moodle2/restore_customcert_stepslib.php | 1 + 1 file changed, 1 insertion(+) diff --git a/backup/moodle2/restore_customcert_stepslib.php b/backup/moodle2/restore_customcert_stepslib.php index ae9f40d..92afa28 100644 --- a/backup/moodle2/restore_customcert_stepslib.php +++ b/backup/moodle2/restore_customcert_stepslib.php @@ -159,6 +159,7 @@ class restore_customcert_activity_structure_step extends restore_activity_struct $data->customcertid = $this->get_new_parentid('customcert'); $data->timecreated = $this->apply_date_offset($data->timecreated); + $data->userid = $this->get_mappingid('user', $data->userid); $newitemid = $DB->insert_record('customcert_issues', $data); $this->set_mapping('customcert_issue', $oldid, $newitemid); From 56bdfdea6aebacba428ef6fc1484358fe9ab8e3e Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 6 Aug 2021 10:56:43 +0800 Subject: [PATCH 32/40] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0d9af38..f93a054 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Fixed - Fix places not using the multi-language filter (#433). +- Fix user IDs in the issue table not being mapped during restore (#449). ### Added - You can now choose the course short or full name to display (#415). From c3942c3b756df0b2a894c6b041be3799c0d749bc Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 28 Sep 2021 22:07:21 +0800 Subject: [PATCH 33/40] Do not encode html entities in emails (#457) --- CHANGES.md | 1 + classes/task/email_certificate_task.php | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f93a054..0d11822 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Fixed - Fix places not using the multi-language filter (#433). - Fix user IDs in the issue table not being mapped during restore (#449). +- Fix emails displaying HTML entities encoded (#457). ### Added - You can now choose the course short or full name to display (#415). diff --git a/classes/task/email_certificate_task.php b/classes/task/email_certificate_task.php index a4ac712..f3cc2a3 100644 --- a/classes/task/email_certificate_task.php +++ b/classes/task/email_certificate_task.php @@ -211,7 +211,8 @@ class email_certificate_task extends \core\task\scheduled_task { $subject = get_string('emailstudentsubject', 'customcert', $info); $message = $textrenderer->render($renderable); $messagehtml = $htmlrenderer->render($renderable); - email_to_user($user, fullname($userfrom), $subject, $message, $messagehtml, $tempfile, $filename); + email_to_user($user, fullname($userfrom), html_entity_decode($subject), $message, $messagehtml, + $tempfile, $filename); } if ($customcert->emailteachers) { @@ -222,8 +223,8 @@ class email_certificate_task extends \core\task\scheduled_task { $message = $textrenderer->render($renderable); $messagehtml = $htmlrenderer->render($renderable); foreach ($teachers as $teacher) { - email_to_user($teacher, fullname($userfrom), $subject, $message, $messagehtml, $tempfile, - $filename); + email_to_user($teacher, fullname($userfrom), html_entity_decode($subject), $message, $messagehtml, + $tempfile, $filename); } } @@ -242,8 +243,8 @@ class email_certificate_task extends \core\task\scheduled_task { $emailuser = new \stdClass(); $emailuser->id = -1; $emailuser->email = $email; - email_to_user($emailuser, fullname($userfrom), $subject, $message, $messagehtml, $tempfile, - $filename); + email_to_user($emailuser, fullname($userfrom), html_entity_decode($subject), $message, + $messagehtml, $tempfile, $filename); } } } From 29779a32f2f946101747489ec476e46897783d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Alonso=20Abad?= Date: Tue, 27 Oct 2020 11:08:08 +0100 Subject: [PATCH 34/40] Added elements alignment support (#121) --- classes/element.php | 50 ++++++++++++++++++++++++++++++++++++- classes/element_factory.php | 1 + classes/element_helper.php | 20 ++++++++++++++- db/install.xml | 1 + db/upgrade.php | 9 +++++++ lang/en/customcert.php | 5 ++++ rearrange.php | 12 +++++++++ styles.css | 12 +++++++++ version.php | 2 +- 9 files changed, 109 insertions(+), 3 deletions(-) diff --git a/classes/element.php b/classes/element.php index b812639..f19793e 100644 --- a/classes/element.php +++ b/classes/element.php @@ -37,6 +37,21 @@ defined('MOODLE_INTERNAL') || die(); */ abstract class element { + /** + * @var string The left alignment constant. + */ + const ALIGN_LEFT = 'L'; + + /** + * @var string The centered alignment constant. + */ + const ALIGN_CENTER = 'C'; + + /** + * @var string The right alignment constant. + */ + const ALIGN_RIGHT = 'R'; + /** * @var \stdClass $element The data for the element we are adding - do not use, kept for legacy reasons. */ @@ -97,6 +112,11 @@ abstract class element { */ protected $refpoint; + /** + * @var string The alignment. + */ + protected $alignment; + /** * @var bool $showposxy Show position XY form elements? */ @@ -130,6 +150,7 @@ abstract class element { $this->width = $element->width; $this->refpoint = $element->refpoint; $this->showposxy = isset($showposxy) && $showposxy; + $this->set_alignment(isset($element->alignment) ? $element->alignment : element::ALIGN_LEFT); } /** @@ -231,6 +252,30 @@ abstract class element { return $this->refpoint; } + /** + * Returns the alignment. + * + * @return string The current alignment value. + */ + public function get_alignment() { + return isset($this->alignment) ? $this->alignment : element::ALIGN_LEFT; + } + + /** + * Sets the alignment. + * + * @param string $alignment The new alignment. + * + * @throws InvalidArgumentException if the provided new alignment is not valid. + */ + protected function set_alignment($alignment) { + $valid_values = array(element::ALIGN_LEFT, element::ALIGN_CENTER, element::ALIGN_RIGHT); + if (!in_array($alignment, $valid_values)) { + throw new \InvalidArgumentException("'$alignment' is not a valid alignment value. It has to be one of " . implode(', ', $valid_values)); + } + $this->alignment = $alignment; + } + /** * This function renders the form elements when adding a customcert element. * Can be overridden if more functionality is needed. @@ -246,6 +291,7 @@ abstract class element { } element_helper::render_form_element_width($mform); element_helper::render_form_element_refpoint($mform); + element_helper::render_form_element_alignment($mform); } /** @@ -265,7 +311,8 @@ abstract class element { 'posx' => $this->posx, 'posy' => $this->posy, 'width' => $this->width, - 'refpoint' => $this->refpoint + 'refpoint' => $this->refpoint, + 'alignment' => $this->get_alignment() ]; foreach ($properties as $property => $value) { if (!is_null($value) && $mform->elementExists($property)) { @@ -320,6 +367,7 @@ abstract class element { } $element->width = (isset($data->width)) ? $data->width : null; $element->refpoint = (isset($data->refpoint)) ? $data->refpoint : null; + $element->alignment = (isset($data->alignment)) ? $data->alignment : element::ALIGN_LEFT; $element->timemodified = time(); // Check if we are updating, or inserting a new element. diff --git a/classes/element_factory.php b/classes/element_factory.php index caac848..5e43591 100644 --- a/classes/element_factory.php +++ b/classes/element_factory.php @@ -59,6 +59,7 @@ class element_factory { $data->posy = $element->posy ?? null; $data->width = $element->width ?? null; $data->refpoint = $element->refpoint ?? null; + $data->alignment = $element->alignment ?? null; // Ensure the necessary class exists. if (class_exists($classname)) { diff --git a/classes/element_helper.php b/classes/element_helper.php index c3d5a1d..39438c2 100644 --- a/classes/element_helper.php +++ b/classes/element_helper.php @@ -74,6 +74,7 @@ class element_helper { $w = $element->get_width(); $refpoint = $element->get_refpoint(); $actualwidth = $pdf->GetStringWidth($content); + $alignment = $element->get_alignment(); if ($w and $w < $actualwidth) { $actualwidth = $w; @@ -104,7 +105,7 @@ class element_helper { $w += 0.0001; } $pdf->setCellPaddings(0, 0, 0, 0); - $pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true); + $pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true, $alignment); } /** @@ -205,6 +206,23 @@ class element_helper { $mform->addHelpButton('refpoint', 'refpoint', 'customcert'); } + /** + * Helper function to render the alignment form element. + * + * @param \MoodleQuickForm $mform the edit_form instance. + */ + public static function render_form_element_alignment($mform) { + $alignmentoptions = array(); + $alignmentoptions[element::ALIGN_LEFT] = get_string('alignleft', 'customcert'); + $alignmentoptions[element::ALIGN_CENTER] = get_string('aligncenter', 'customcert'); + $alignmentoptions[element::ALIGN_RIGHT] = get_string('alignright', 'customcert'); + + $mform->addElement('select', 'alignment', get_string('alignment', 'customcert'), $alignmentoptions); + $mform->setType('alignment', PARAM_ALPHA); + $mform->setDefault('alignment', element::ALIGN_LEFT); + $mform->addHelpButton('alignment', 'alignment', 'customcert'); + } + /** * Helper function to performs validation on the colour element. * diff --git a/db/install.xml b/db/install.xml index 22fe3ec..f6368b3 100644 --- a/db/install.xml +++ b/db/install.xml @@ -85,6 +85,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index bbb684f..659e4f4 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -178,5 +178,14 @@ function xmldb_customcert_upgrade($oldversion) { upgrade_mod_savepoint(true, 2020061501, 'customcert'); } + if ($oldversion < 2020061503) { + $table = new xmldb_table('customcert_elements'); + $field = new xmldb_field('alignment', XMLDB_TYPE_CHAR, '1', null, XMLDB_NOTNULL, null, 'L', 'refpoint'); + + $dbman->add_field($table, $field); + + upgrade_mod_savepoint(true, 2020061503, 'customcert'); // Replace with the actual version number. + } + return true; } diff --git a/lang/en/customcert.php b/lang/en/customcert.php index 7ed7b9a..fbc5464 100644 --- a/lang/en/customcert.php +++ b/lang/en/customcert.php @@ -25,6 +25,11 @@ $string['activity'] = 'Activity'; $string['addcertpage'] = 'Add page'; $string['addelement'] = 'Add element'; +$string['aligncenter'] = 'Centered'; +$string['alignleft'] = 'Left alignment'; +$string['alignment'] = 'Alignment'; +$string['alignment_help'] = 'This property sets the horizontal alignment of the element. Some elements may not support this, while the behaviour of others may differ.'; +$string['alignright'] = 'Right alignment'; $string['awardedto'] = 'Awarded to'; $string['cannotverifyallcertificates'] = 'You do not have the permission to verify all certificates on the site.'; $string['certificate'] = 'Certificate'; diff --git a/rearrange.php b/rearrange.php index 7483953..2c612cc 100644 --- a/rearrange.php +++ b/rearrange.php @@ -112,6 +112,18 @@ if ($elements) { default: $class = 'element refpoint-left'; } + switch ($element->alignment) { + case \mod_customcert\element::ALIGN_CENTER: + $class .= ' align-center'; + break; + case \mod_customcert\element::ALIGN_RIGHT: + $class .= ' align-right'; + break; + case \mod_customcert\element::ALIGN_LEFT: + default: + $class .= ' align-left'; + break; + } $html .= html_writer::tag('div', $e->render_html(), array('class' => $class, 'data-refpoint' => $element->refpoint, 'id' => 'element-' . $element->id)); } diff --git a/styles.css b/styles.css index 9fbe30b..3f98cdf 100644 --- a/styles.css +++ b/styles.css @@ -57,6 +57,18 @@ margin: -4px -5px -5px 4px; } +#page-mod-customcert-rearrange .element.align-left { + text-align: left; +} + +#page-mod-customcert-rearrange .element.align-center { + text-align: center; +} + +#page-mod-customcert-rearrange .element.align-right { + text-align: right; +} + #page-mod-customcert-rearrange #pdf { border-style: solid; border-width: 1px; diff --git a/version.php b/version.php index f515de5..b0b7aaf 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); -$plugin->version = 2020061502; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2020061503; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2020061500; // Requires this Moodle version (3.9). $plugin->cron = 0; // Period for cron to check this module (secs). $plugin->component = 'mod_customcert'; From 904a83e2b98eceef3e939e5432d32c60f6a6ee75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Alonso=20Abad?= Date: Tue, 1 Dec 2020 08:55:50 +0100 Subject: [PATCH 35/40] Added alignment to activity backup/cloning (#121) --- backup/moodle2/backup_customcert_stepslib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/moodle2/backup_customcert_stepslib.php b/backup/moodle2/backup_customcert_stepslib.php index e6bf617..7c01ee0 100644 --- a/backup/moodle2/backup_customcert_stepslib.php +++ b/backup/moodle2/backup_customcert_stepslib.php @@ -59,7 +59,7 @@ class backup_customcert_activity_structure_step extends backup_activity_structur $element = new backup_nested_element('element', array('id'), array( 'pageid', 'name', 'element', 'data', 'font', 'fontsize', 'colour', 'posx', 'posy', 'width', 'refpoint', 'sequence', - 'timecreated', 'timemodified')); + 'alignment', 'timecreated', 'timemodified')); // The issues. $issues = new backup_nested_element('issues'); From f3050a3ebf2264b530410b5a41bb720c563c8736 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 25 Oct 2021 16:14:18 +0800 Subject: [PATCH 36/40] Updated CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0d11822..4c972a3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Added - You can now choose the course short or full name to display (#415). +- You can now select the alignment for all text elements ## [3.9.1] - 2021-06-13 From 62d1bbdedc645d02e8cef83436ac22c6b360ce53 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 27 Oct 2021 12:23:50 +0800 Subject: [PATCH 37/40] Add issue number to CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 4c972a3..7c91ba5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g ### Added - You can now choose the course short or full name to display (#415). -- You can now select the alignment for all text elements +- You can now select the alignment for all text elements (#121). ## [3.9.1] - 2021-06-13 From fae09fbadf2695f162d22e0e3171b98eff9eff03 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 27 Oct 2021 13:09:10 +0800 Subject: [PATCH 38/40] Changes to make GHA happy and added usages of the coalescing operator (#121) --- classes/element.php | 39 +++++++++++++++++++------------------- classes/element_helper.php | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/classes/element.php b/classes/element.php index f19793e..ea77e4a 100644 --- a/classes/element.php +++ b/classes/element.php @@ -51,7 +51,7 @@ abstract class element { * @var string The right alignment constant. */ const ALIGN_RIGHT = 'R'; - + /** * @var \stdClass $element The data for the element we are adding - do not use, kept for legacy reasons. */ @@ -150,7 +150,7 @@ abstract class element { $this->width = $element->width; $this->refpoint = $element->refpoint; $this->showposxy = isset($showposxy) && $showposxy; - $this->set_alignment(isset($element->alignment) ? $element->alignment : element::ALIGN_LEFT); + $this->set_alignment($element->alignment ?? self::ALIGN_LEFT); } /** @@ -254,24 +254,25 @@ abstract class element { /** * Returns the alignment. - * + * * @return string The current alignment value. */ public function get_alignment() { - return isset($this->alignment) ? $this->alignment : element::ALIGN_LEFT; + return $this->alignment ?? self::ALIGN_LEFT; } /** * Sets the alignment. - * + * * @param string $alignment The new alignment. - * - * @throws InvalidArgumentException if the provided new alignment is not valid. + * + * @throws \InvalidArgumentException if the provided new alignment is not valid. */ - protected function set_alignment($alignment) { - $valid_values = array(element::ALIGN_LEFT, element::ALIGN_CENTER, element::ALIGN_RIGHT); - if (!in_array($alignment, $valid_values)) { - throw new \InvalidArgumentException("'$alignment' is not a valid alignment value. It has to be one of " . implode(', ', $valid_values)); + protected function set_alignment(string $alignment) { + $validvalues = array(self::ALIGN_LEFT, self::ALIGN_CENTER, self::ALIGN_RIGHT); + if (!in_array($alignment, $validvalues)) { + throw new \InvalidArgumentException("'$alignment' is not a valid alignment value. It has to be one of " . + implode(', ', $validvalues)); } $this->alignment = $alignment; } @@ -358,16 +359,16 @@ abstract class element { $element = new \stdClass(); $element->name = $data->name; $element->data = $this->save_unique_data($data); - $element->font = (isset($data->font)) ? $data->font : null; - $element->fontsize = (isset($data->fontsize)) ? $data->fontsize : null; - $element->colour = (isset($data->colour)) ? $data->colour : null; + $element->font = $data->font ?? null; + $element->fontsize = $data->fontsize ?? null; + $element->colour = $data->colour ?? null; if ($this->showposxy) { - $element->posx = (isset($data->posx)) ? $data->posx : null; - $element->posy = (isset($data->posy)) ? $data->posy : null; + $element->posx = $data->posx ?? null; + $element->posy = $data->posy ?? null; } - $element->width = (isset($data->width)) ? $data->width : null; - $element->refpoint = (isset($data->refpoint)) ? $data->refpoint : null; - $element->alignment = (isset($data->alignment)) ? $data->alignment : element::ALIGN_LEFT; + $element->width = $data->width ?? null; + $element->refpoint = $data->refpoint ?? null; + $element->alignment = $data->alignment ?? self::ALIGN_LEFT; $element->timemodified = time(); // Check if we are updating, or inserting a new element. diff --git a/classes/element_helper.php b/classes/element_helper.php index 39438c2..7053dc5 100644 --- a/classes/element_helper.php +++ b/classes/element_helper.php @@ -216,7 +216,7 @@ class element_helper { $alignmentoptions[element::ALIGN_LEFT] = get_string('alignleft', 'customcert'); $alignmentoptions[element::ALIGN_CENTER] = get_string('aligncenter', 'customcert'); $alignmentoptions[element::ALIGN_RIGHT] = get_string('alignright', 'customcert'); - + $mform->addElement('select', 'alignment', get_string('alignment', 'customcert'), $alignmentoptions); $mform->setType('alignment', PARAM_ALPHA); $mform->setDefault('alignment', element::ALIGN_LEFT); From a6a7b24898b98182233c53262e34b00592904175 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 27 Oct 2021 16:44:49 +0800 Subject: [PATCH 39/40] Respect multiple languages in manage template page title (#467) --- manage_templates.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manage_templates.php b/manage_templates.php index 42d223d..e57a72b 100644 --- a/manage_templates.php +++ b/manage_templates.php @@ -47,7 +47,6 @@ require_login(); require_capability('mod/customcert:manage', $context); $title = $SITE->fullname; -$heading = $title; // Set up the page. $pageurl = new moodle_url('/mod/customcert/manage_templates.php'); @@ -61,6 +60,8 @@ if ($tid && $action && confirm_sesskey()) { $PAGE->navbar->add(get_string('managetemplates', 'customcert')); } +$heading = format_string($title, true, ['context' => $context]); + if ($tid) { if ($action && confirm_sesskey()) { $nourl = new moodle_url('/mod/customcert/manage_templates.php'); From 68b53cf67bac8a7196411ed6a016582bcb18062d Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 27 Oct 2021 16:48:05 +0800 Subject: [PATCH 40/40] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 7c91ba5..5630ead 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g - Fix places not using the multi-language filter (#433). - Fix user IDs in the issue table not being mapped during restore (#449). - Fix emails displaying HTML entities encoded (#457). +- Respect multiple languages in manage template page title (#467). ### Added - You can now choose the course short or full name to display (#415).