Compare commits

...

100 commits

Author SHA1 Message Date
Mark Nelson e25ebd6420 Fixed size of 'Changed' in CHANGES.md 2020-11-26 23:31:52 +08:00
Mark Nelson 02f9ed9b49 Bumped version 2020-11-26 23:06:53 +08:00
Mark Nelson 3b0b1298d5 Update CHANGES.md (#390) 2020-11-26 22:09:50 +08:00
uvigo-atic 850c19f588 Added username to userfield form element (#390) 2020-11-26 22:09:42 +08:00
Mark Nelson a08c880c04 Updated CHANGES.md (#276) 2020-11-26 21:43:06 +08:00
Mark Nelson 7a309f506f Update 'emailteachers_help' and 'emailothers_help' language strings (#276) 2020-11-26 21:35:50 +08:00
Mark Nelson d778424a92 Do not email out certificates with no elements (#276) 2020-11-26 21:13:50 +08:00
Mark Nelson f1c67c7134 Use null coalescing operator in element factory 2020-11-26 18:22:57 +08:00
Mark Nelson e45e6e21cf Update 'emailstudents_help' language string (#276) 2020-11-26 17:55:58 +08:00
Mark Nelson 7b523100b7 Bump .travis.yml to use v3 of moodle-plugin-ci 2020-11-09 16:29:16 +01:00
Mark Nelson a1d19bf84d Update repo used by Travis 2020-11-09 16:28:57 +01:00
Mark Nelson 512bbad3c4 Update CHANGES.md 2020-11-04 19:32:54 +01:00
Brendan Heywood ebfc1c029d PDFs should be inline not attachments #153 2020-11-04 19:16:26 +01:00
Mark Nelson 75dbbf661d Add CSS class for mobile app (#378) 2020-10-12 13:36:39 +02:00
Mark Nelson be08afb7b4 Removed multiple empty lines 2020-09-20 16:00:59 +02:00
Mark Nelson 0223518bf9 Updated CHANGES.md 2020-09-20 15:55:09 +02:00
Mark Nelson cb5b5d7465 Fixed issue with PDF being generated without a name (#333) 2020-09-20 15:41:09 +02:00
Mark Nelson 2e9bc44bf3 Fixed exception loading template image that has no image selected (#369) 2020-09-20 14:58:22 +02:00
Mark Nelson e7e238aaf7 Do not email those who can manage the certificate (#376) 2020-09-20 14:29:35 +02:00
Guillermo Gomez a20285a947 Implement get_objectid_mapping (#374) 2020-09-20 14:17:11 +02:00
Mark Nelson f82258c78a Updated CHANGES.md 2020-08-08 19:39:40 +02:00
Mark Nelson b7b33ebd8c Changed 'enrollment' to 'enrolment' to conform to Moodle core (#328)
Also minor changes like ordering strings alphabetically and adding
full-stops.
2020-08-08 19:38:43 +02:00
Sergey Evstegneiev c4b21153eb Adding enrollment start & end date options (#328) 2020-08-08 19:38:29 +02:00
Mark Nelson e6b640c0cf Fix stale file warning 2020-08-08 18:11:07 +02:00
Mark Nelson 3bd09923c4 Ignore multiple certificate codes (#363) 2020-08-08 15:53:10 +02:00
Mark Nelson 8125a5e9ff Remove trailing spaces 2020-08-08 15:47:04 +02:00
Thong Bui 69123d230b Fix get position when browser shrinking (#343) 2020-08-08 15:28:40 +02:00
Mark Nelson 133852af7c Updated CHANGES.md 2020-06-28 18:38:13 +02:00
Mark Nelson 1d4434ed15 Update node version used in .travis.yml 2020-05-30 13:37:18 +02:00
Mark Nelson 4a45b5ab81 Mark certificates as viewed in mobile app (#342) 2020-05-30 13:10:22 +02:00
Mark Nelson 476f292d73 Refactor element_helper::get_grade_items() to be nicer to read 2020-05-08 21:24:16 +02:00
Mark Nelson 684af9de0f Fix docs in Grade element name 2020-05-08 17:50:39 +02:00
Mark Nelson 42645287d7 The Grade item name element works with all grade items (#346) 2020-05-08 17:27:49 +02:00
Mark Nelson 9badf60f91 Extend unit test (#329) 2020-05-08 17:23:31 +02:00
Mark Nelson c992d7a376 Add the ability to select Outcomes in the Grade element (#329) 2020-05-08 17:23:24 +02:00
Mark Nelson a5d51f2478 Removed 'exampledata' string 2020-05-08 16:57:31 +02:00
Mark Nelson cd9cf91769 Added capability to determine who can receive a certificate (#270) 2020-04-19 13:53:07 +02:00
Mark Nelson f00a0d739d Update CHANGES.md 2020-04-19 13:52:31 +02:00
Mark Nelson 3ecfaf69f4 Fix foreign key violation (#331) 2020-04-17 17:06:39 +02:00
Mark Nelson b480cf3c68 Fixed broken logic (#298) 2020-04-17 16:52:07 +02:00
Mark Nelson 48c83d34df Loading templates copies system images to the course (#298)
Before it would just reference the system images. However, this meant
backup/restore was broken as it did not include the images the template
was using.
2020-04-17 16:52:04 +02:00
Mark Nelson 8a2b7290af Added extra Behat steps for new elements (#309) 2020-04-17 16:28:17 +02:00
Sergey 4db2148886 Fix of showing names of custom user fields (#326)
Show normal human-readable name of custom user profile fields instead of internal shortname
2020-04-17 16:27:54 +02:00
Mark Nelson e76705315c Fixed typo in Behat file name 2020-04-17 16:26:32 +02:00
Mark Nelson 7f62e6eaec Re-add code column (#264) 2020-04-17 16:26:32 +02:00
Arnaud Trouvé d37cc22135 Add userfullname variable for email subject (#316) 2020-04-17 16:26:32 +02:00
Mark Nelson 7492fd1686 Changed references to old github name 2020-04-17 16:26:32 +02:00
Mark Nelson 7336a21df7 Downgrade version.php for qrcode element 2020-04-17 16:09:39 +02:00
Mark Nelson e6ddaa5b30 Do not allow '0' as a value for width or height in QR code (#321) 2020-04-17 16:03:33 +02:00
Mark Nelson 20cfbdf9c3 Fix complaints found by local_moodlecheck 2020-04-17 16:03:26 +02:00
Mark Nelson 1bfceb6794 Incorrect PHPDocs for render_form_elements and co (#271) 2020-04-17 16:03:16 +02:00
Mark Nelson b16bf5ccb6 Added QR code element (#146) 2020-04-17 16:03:07 +02:00
Mark Nelson 7532606ffa Downgrade version.php for daterange element 2020-04-17 15:47:33 +02:00
Mark Nelson 5da5b675ab Add ability to specify the current date for date related elements (#289) 2020-04-17 15:42:36 +02:00
Mark Nelson d2f12c859c String improvements for date range element
Also added a help button to reduce the wall
of text.
2020-04-17 15:42:30 +02:00
Mark Nelson 50e8374596 Fixed PHPDoc reference to edit_element_form 2020-04-17 15:42:25 +02:00
Mark Nelson 0652441d45 Use negative numbers for constants in date range element
The reason being that we may have a module that has
an id matching one of these values.
2020-04-17 15:42:18 +02:00
Mark Nelson 8c03508a40 Fix complaints found by local_moodlecheck 2020-04-17 15:42:08 +02:00
Mark Nelson 4c639bbe3e Minor changes (#185) 2020-04-17 15:41:32 +02:00
Dmitrii Metelkin 4d62cde7f3 Use repeat form element for date ranges (#185) 2020-04-17 15:41:24 +02:00
Dmitrii Metelkin 2866aa7c6b Remove empty line (#185) 2020-04-17 15:41:18 +02:00
Dmitrii Metelkin 9021794049 Add new placeholders and update help description (#185) 2020-04-17 15:41:10 +02:00
Dmitrii Metelkin 8f006a2600 Rename first_year and last_year placeholders (#185) 2020-04-17 15:41:06 +02:00
Dmitrii Metelkin 71b0a8bd0e Update description string (#185) 2020-04-17 15:40:59 +02:00
Dmitrii Metelkin 9874a2bd0d Add tests to support functionality (#185) 2020-04-17 15:40:54 +02:00
Dmitrii Metelkin ea868e3cd3 Improve the logic of recurring ranges (#185) 2020-04-17 15:40:49 +02:00
Dmitrii Metelkin 82aa988db4 Recursively check recurring date ranges (#185) 2020-04-17 15:40:43 +02:00
Dmitrii Metelkin 3cd85428df Add an empty line to the end of styles.css (#185) 2020-04-17 15:40:37 +02:00
Dmitrii Metelkin 48024d2b77 Update lang strings (#185) 2020-04-17 15:40:31 +02:00
Dmitrii Metelkin 0eb96e3605 Be more strict about 12 months limit (#185) 2020-04-17 15:40:23 +02:00
Dmitrii Metelkin 36ec9188fa Modify recurring dateranges (#185) 2020-04-17 15:40:16 +02:00
Dmitrii Metelkin 2852683dff Add range related placeholders (#185) 2020-04-17 15:40:11 +02:00
Dmitrii Metelkin 3e69898988 Get rid of useless css rule (#185) 2020-04-17 15:40:06 +02:00
Dmitrii Metelkin 92b15ecb06 Change a way of displaying date ranges on the edit element page (#185) 2020-04-17 15:40:00 +02:00
Dmitrii Metelkin 057cf92f03 Add recurring option to dateranges (#185) 2020-04-17 15:39:55 +02:00
Dmitrii Metelkin 59fe72c7ca Use element name in the preview mode (#185) 2020-04-17 15:39:49 +02:00
Mark Nelson e0cdcb07b9 Bump date range element version numbers (#185) 2020-04-17 15:39:41 +02:00
Dmitrii Metelkin d91639e4ed Add date range element (#185) 2020-04-17 15:39:34 +02:00
mwithheld 6d0c4160f7 Do not fail if multiple certificate issues (#304)
Fix another location of this problem.
2020-04-07 13:46:29 +02:00
mwithheld db81b49608 Do not fail if multiple certificate issues (#295)
Ignore multiple matches for a user-customcert combo in the customcert_issues table.
In our case, the scheduled task died when:
$issueid = $DB->get_field('customcert_issues', 'id', array('userid' => $enroluser->id, 'customcertid' => $customcert->id));
returned 2 rows, which shouldn't happen, but did anyway.

This means in rare circumstances (i.e. the race condition) the user may get multiple certificates (e.g. one via the UI, one by email) but that is better than not getting one at all and the whole job dying.
2020-04-01 15:11:33 +02:00
Mark Nelson 3c3902ab9d Specify OS in travis 2019-05-29 00:19:42 +08:00
Mark Nelson b1b6af3e65 Bump version 2019-05-28 17:49:23 +08:00
Mark Nelson aacf541621 Updated CHANGES.md 2019-05-28 17:49:23 +08:00
Mark Nelson 4f583679d0 Check that a certificate issue exists (#269) 2019-05-28 14:36:21 +08:00
Mark Nelson 01e427cf57 Make travis happy (#282) 2019-05-28 14:36:15 +08:00
Sagar Ghimire bb2ed945fa Fix failing test_get_grades (#282) 2019-05-28 14:36:10 +08:00
Mark Nelson 5a7e1ee98d Use openjdk-8-jre-headless instead of oracle-java8 in .travis.yml 2019-05-28 14:36:00 +08:00
Mark Nelson 13ec235c2d Readded number of certificates issued (#266) 2019-05-28 14:35:55 +08:00
Mark Nelson d42cbc9a16 Removed unnecessary inclusion 2019-05-28 14:35:51 +08:00
Mark Nelson f91a54ebc9 Specify grades' decimal places in unit test (#277) 2019-05-28 14:35:46 +08:00
Mark Nelson fc0fb240fd Always send emails from 'noreplyuser' (#165) 2019-05-28 14:35:41 +08:00
Mark Nelson 92e0029623 Incorrect PHPDocs for render_form_elements and co (#271) 2019-05-28 14:35:30 +08:00
Nicolas Roeser 322abdbba3 Add vertical spacing after certificate download button
Increase the vertical spacing after the single button for downloading
user’s own certificate. This makes the page look better.
2019-02-04 14:46:46 +08:00
Mark Nelson 59f9bfcc78 Bumped version 2018-12-31 10:45:22 +08:00
Mark Nelson 577a997960 Updated CHANGES.md 2018-12-31 10:44:01 +08:00
Mark Nelson 1b756fbd5b Make it clear what element values are just an example (#144) 2018-12-31 10:16:58 +08:00
Mark Nelson d12e752d1a Use course module context when calling format_string/text (#200) 2018-12-28 15:09:40 +08:00
Mark Nelson 961a3f02f0 Prevent exception when adding 'teachername' element to site template (#261) 2018-12-27 09:08:31 +08:00
Mark Nelson 9f844368fd Added missing details to CHANGES.md 2018-12-27 07:42:37 +08:00
Mark Nelson a3f159dfaf Added missing implementation for privacy provider (#260) 2018-12-27 07:42:32 +08:00
58 changed files with 2453 additions and 334 deletions

View file

@ -2,6 +2,7 @@ language: php
# For javascript behat tests we need sudo
sudo: true
dist: trusty
cache:
directories:
@ -17,8 +18,7 @@ addons:
postgresql: 9.3
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
- openjdk-8-jre-headless
env:
global:
@ -30,10 +30,10 @@ env:
before_install:
- phpenv config-rm xdebug.ini
- nvm install 8.9
- nvm use 8.9
- nvm install 14.0
- nvm use 14.0
- cd ../..
- composer create-project -n --no-dev --prefer-dist blackboard-open-source/moodle-plugin-ci ci ^2
- 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:

View file

@ -2,7 +2,84 @@
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/markn86/moodle-mod_customcert/issues/169.
Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169.
## [3.5.9] - 2020-11-26
### Added
- Added ability to select outcomes in the Grade element (#329).
- The Grade Item Name element now works with all grade items, whereas before it was just activities (#346).
- Added enrolment start and end dates to the date element (#328).
- Added username to userfield form element (#390).
### Changed
- Removed unnecessary and confusing 'exampledata' string.
- Do not email those who can manage the certificate (#376).
- Do not force the PDF to be downloaded, instead send the file inline to the browser (#153).
- Updated the 'emailstudents_help', 'emailteachers_help' and 'emailothers_help' strings to warn users about prematurely emailing the certificate (#276).
- Do not email out certificates that contain no elements (#276).
### Fixed
- Certificates now get marked as viewed via the mobile app (#342).
- Fix repositioning elements page when resizing the browser (#343).
- Prevent error when duplicate issues exist when using the code element (#363).
- Implemented get_objectid_mapping for the course_module_viewed.php event to avoid warning (#374).
- Fixed exception being thrown when loading a template that has an image element but no image selected (#369).
- Fixed issue with PDF being generated without a name (#333).
## [3.5.8] - 2020-04-19
### Added
- Added extra Behat steps for new elements (#309).
- Re-added 'code' column to user report (#264).
- Add 'userfullname' variable for email subject (#316).
- Added ability to specify the current date for date related elements (#289).
- Added QR code element (#146).
- Added Date range element (#185).
- Added new capability to control who can be issued a certificate (#270).
### Changed
- When copying a site template the site images are also copied to the course context and then those copied images are used.
Before, the elements would simply point to the site images. However, this meant when performing a backup/restore the
images were not stored in the backup file (#298).
### Fixed
- Fixed the displaying of names of a custom user field (#326).
- Fixed foreign key violation (#331).
- Do not fail if multiple certificate issues (#304) and (#295).
## [3.5.7] - 2019-05-28
### Changed
- Always send emails from the 'noreplyuser' (#165).
### Added
- Added the number of certificates issued above the report (#266).
### Fixed
- Failures when running unit tests for multiple activities (#282).
- Check that a certificate is issued before downloading on 'My certificates' page (#269).
## [3.5.6] - 2018-12-31
### Changed
- Make it clear what element values are just an example when previewing the PDF (#144).
### Fixed
- Missing implementation for privacy provider (#260).
- Use course module context when calling format_string/text (#200).
- Exception being thrown when adding the 'teachername' element to site template (#261).
## [3.5.5] - 2018-12-20
### Added
@ -20,12 +97,15 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
- Allow verification of deleted users (#159).
- The 'element' field in the 'customcert_elements' table has been changed from a Text field to varchar(255) (#241).
- The 'Completion date' option in the 'date' element is only displayed when completion is enabled (#160).
- Instead of assuming 2 decimal points for percentages, we now make use of the decimal value setting, which the
function `grade_format_gradevalue` does by default if no decimal value is passed.
### Fixed
- Issue with scales not displaying correctly (#242).
- The report now respects the setting 'Show user identity' (#224).
- Removed incorrect course reset logic (#223).
- Description strings referring to the wrong setting (#254).
## [3.5.4] - 2018-07-13
### Fixed

View file

@ -15,7 +15,7 @@ This requires Git being installed. If you do not have Git installed, please visi
Once you have Git installed, simply visit your Moodle mod directory and clone the repository using the following command.
```
git clone https://github.com/markn86/moodle-mod_customcert.git customcert
git clone https://github.com/mdjnelson/moodle-mod_customcert.git customcert
```
Then checkout the branch corresponding to the version of Moodle you are using with the following command. Make sure to replace MOODLE_32_STABLE with the version of Moodle you are using.

View file

@ -64,6 +64,7 @@ class edit_element_form extends \moodleform {
$mform->addHelpButton('name', 'elementname', 'customcert');
$this->element = \mod_customcert\element_factory::get_element_instance($element);
$this->element->set_edit_element_form($this);
$this->element->render_form_elements($mform);
$this->add_action_buttons(true);

View file

@ -102,6 +102,11 @@ abstract class element {
*/
protected $showposxy;
/**
* @var edit_element_form Element edit form instance.
*/
private $editelementform;
/**
* Constructor.
*
@ -230,7 +235,7 @@ abstract class element {
* This function renders the form elements when adding a customcert element.
* Can be overridden if more functionality is needed.
*
* @param edit_element_form $mform the edit_form instance.
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public function render_form_elements($mform) {
// Render the common elements.
@ -240,6 +245,7 @@ abstract class element {
element_helper::render_form_element_position($mform);
}
element_helper::render_form_element_width($mform);
element_helper::render_form_element_refpoint($mform);
}
/**
@ -421,4 +427,27 @@ abstract class element {
return $this->element->$name;
}
}
/**
* Set edit form instance for the custom cert element.
*
* @param \mod_customcert\edit_element_form $editelementform
*/
public function set_edit_element_form(edit_element_form $editelementform) {
$this->editelementform = $editelementform;
}
/**
* Get edit form instance for the custom cert element.
*
* @return \mod_customcert\edit_element_form
*/
public function get_edit_element_form() {
if (empty($this->editelementform)) {
throw new \coding_exception('Edit element form instance is not set.');
}
return $this->editelementform;
}
}

View file

@ -47,18 +47,18 @@ class element_factory {
$classname = '\\customcertelement_' . $element->element . '\\element';
$data = new \stdClass();
$data->id = isset($element->id) ? $element->id : null;
$data->pageid = isset($element->pageid) ? $element->pageid : null;
$data->name = isset($element->name) ? $element->name : get_string('pluginname', 'customcertelement_' . $element->element);
$data->id = $element->id ?? null;
$data->pageid = $element->pageid ?? null;
$data->name = $element->name ?? get_string('pluginname', 'customcertelement_' . $element->element);
$data->element = $element->element;
$data->data = isset($element->data) ? $element->data : null;
$data->font = isset($element->font) ? $element->font : null;
$data->fontsize = isset($element->fontsize) ? $element->fontsize : null;
$data->colour = isset($element->colour) ? $element->colour : null;
$data->posx = isset($element->posx) ? $element->posx : null;
$data->posy = isset($element->posy) ? $element->posy : null;
$data->width = isset($element->width) ? $element->width : null;
$data->refpoint = isset($element->refpoint) ? $element->refpoint : null;
$data->data = $element->data ?? null;
$data->font = $element->font ?? null;
$data->fontsize = $element->fontsize ?? null;
$data->colour = $element->colour ?? null;
$data->posx = $element->posx ?? null;
$data->posy = $element->posy ?? null;
$data->width = $element->width ?? null;
$data->refpoint = $element->refpoint ?? null;
// Ensure the necessary class exists.
if (class_exists($classname)) {

View file

@ -134,7 +134,7 @@ class element_helper {
/**
* Helper function to render the font elements.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance.
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public static function render_form_element_font($mform) {
$mform->addElement('select', 'font', get_string('font', 'customcert'), \mod_customcert\certificate::get_fonts());
@ -151,7 +151,7 @@ class element_helper {
/**
* Helper function to render the colour elements.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance.
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public static function render_form_element_colour($mform) {
$mform->addElement('customcert_colourpicker', 'colour', get_string('fontcolour', 'customcert'));
@ -163,7 +163,7 @@ class element_helper {
/**
* Helper function to render the position elements.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance.
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public static function render_form_element_position($mform) {
$mform->addElement('text', 'posx', get_string('posx', 'customcert'), array('size' => 10));
@ -179,17 +179,26 @@ class element_helper {
/**
* Helper function to render the width element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance.
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public static function render_form_element_width($mform) {
$mform->addElement('text', 'width', get_string('elementwidth', 'customcert'), array('size' => 10));
$mform->setType('width', PARAM_INT);
$mform->setDefault('width', 0);
$mform->addHelpButton('width', 'elementwidth', 'customcert');
}
/**
* Helper function to render the refpoint element.
*
* @param \MoodleQuickForm $mform the edit_form instance.
*/
public static function render_form_element_refpoint($mform) {
$refpointoptions = array();
$refpointoptions[self::CUSTOMCERT_REF_POINT_TOPLEFT] = get_string('topleft', 'customcert');
$refpointoptions[self::CUSTOMCERT_REF_POINT_TOPCENTER] = get_string('topcenter', 'customcert');
$refpointoptions[self::CUSTOMCERT_REF_POINT_TOPRIGHT] = get_string('topright', 'customcert');
$mform->addElement('select', 'refpoint', get_string('refpoint', 'customcert'), $refpointoptions);
$mform->setType('refpoint', PARAM_INT);
$mform->setDefault('refpoint', self::CUSTOMCERT_REF_POINT_TOPCENTER);
@ -383,6 +392,27 @@ class element_helper {
}
}
/**
* Helper function that returns the context for this element.
*
* @param int $elementid The element id
* @return \context The context
*/
public static function get_context(int $elementid) : \context {
global $DB;
$sql = "SELECT ct.contextid
FROM {customcert_templates} ct
INNER JOIN {customcert_pages} cp
ON ct.id = cp.templateid
INNER JOIN {customcert_elements} ce
ON cp.id = ce.pageid
WHERE ce.id = :elementid";
$contextid = $DB->get_field_sql($sql, array('elementid' => $elementid), MUST_EXIST);
return \context::instance_by_id($contextid);
}
/**
* Return the list of possible elements to add.
*
@ -432,70 +462,40 @@ class element_helper {
* @return array the array of gradeable items in the course
*/
public static function get_grade_items($course) {
global $DB;
// Array to store the grade items.
$modules = array();
// Collect course modules data.
$modinfo = get_fast_modinfo($course);
$mods = $modinfo->get_cms();
$sections = $modinfo->get_section_info_all();
// Create the section label depending on course format.
$sectionlabel = get_string('section');
if ($course->format == 'topics') {
$sectionlabel = get_string('topic');
} else if ($course->format == 'weeks') {
$sectionlabel = get_string('week');
}
// Loop through each course section.
for ($i = 0; $i <= count($sections) - 1; $i++) {
// Confirm the index exists, should always be true.
if (isset($sections[$i])) {
// Get the individual section.
$section = $sections[$i];
// Get the mods for this section.
$sectionmods = explode(",", $section->sequence);
// Loop through the section mods.
foreach ($sectionmods as $sectionmod) {
// Should never happen unless DB is borked.
if (empty($mods[$sectionmod])) {
continue;
}
$mod = $mods[$sectionmod];
$instance = $DB->get_record($mod->modname, array('id' => $mod->instance));
// Get the grade items for this activity.
if ($gradeitems = grade_get_grade_items_for_activity($mod)) {
$moditem = grade_get_grades($course->id, 'mod', $mod->modname, $mod->instance);
$gradeitem = reset($moditem->items);
if (isset($gradeitem->grademax)) {
$modules[$mod->id] = $sectionlabel . ' ' . $section->section . ' : ' . $instance->name;
}
}
}
}
}
$arrgradeitems = array();
// Get other non-module related grade items.
if ($gradeitems = \grade_item::fetch_all(['courseid' => $course->id])) {
$arrgradeitems = [];
foreach ($gradeitems as $gi) {
// Skip the course and mod items since we already have them.
if ($gi->itemtype == 'mod' || $gi->itemtype == 'course') {
continue;
if ($gi->is_course_item()) {
continue; // Skipping for legacy reasons - this was added to individual elements.
}
if ($gi->is_external_item()) {
$cm = get_coursemodule_from_instance($gi->itemmodule, $gi->iteminstance, $course->id);
$modcontext = \context_module::instance($cm->id);
$modname = format_string($cm->name, true, array('context' => $modcontext));
}
if ($gi->is_external_item() && !$gi->is_outcome_item()) {
// Due to legacy reasons we are storing the course module ID here rather than the grade item id.
// If we were to change we would need to provide upgrade steps to convert cm->id to gi->id.
$arrgradeitems[$cm->id] = get_string('activity', 'mod_customcert') . ' : ' . $gi->get_name();
} else if ($gi->is_external_item() && $gi->is_outcome_item()) {
// Get the name of the activity.
$optionname = get_string('gradeoutcome', 'mod_customcert') . ' : ' . $modname . " - " . $gi->get_name();
$arrgradeitems['gradeitem:' . $gi->id] = $optionname;
} else {
$arrgradeitems['gradeitem:' . $gi->id] = get_string('gradeitem', 'grades') . ' : ' . $gi->get_name(true);
}
$arrgradeitems['gradeitem:' . $gi->id] = get_string('gradeitem', 'grades') . ' : ' . $gi->get_name(true);
}
// Alphabetise this.
asort($arrgradeitems);
// Merge results.
$modules = $modules + $arrgradeitems;
}
return $modules;
return $arrgradeitems;
}
/**

View file

@ -42,4 +42,13 @@ class course_module_viewed extends \core\event\course_module_viewed {
$this->data['objecttable'] = 'customcert';
parent::init();
}
public static function get_objectid_mapping() {
return array('db' => 'customcert', 'restore' => 'customcert');
}
public static function get_other_mapping() {
// No need to map.
return false;
}
}

View file

@ -42,7 +42,8 @@ defined('MOODLE_INTERNAL') || die();
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\plugin\provider {
\core_privacy\local\request\plugin\provider,
\core_privacy\local\request\core_userlist_provider {
/**
* Return the fields which contain personal data.

View file

@ -74,6 +74,7 @@ class report_table extends \table_sql {
$columns[] = $extrafield;
}
$columns[] = 'timecreated';
$columns[] = 'code';
$headers = [];
$headers[] = get_string('fullname');
@ -81,6 +82,7 @@ class report_table extends \table_sql {
$headers[] = get_user_field_name($extrafield);
}
$headers[] = get_string('receiveddate', 'customcert');
$headers[] = get_string('code', 'customcert');
// Check if we were passed a filename, which means we want to download it.
if ($download) {
@ -101,6 +103,7 @@ class report_table extends \table_sql {
$this->define_headers($headers);
$this->collapsible(false);
$this->sortable(true);
$this->no_sorting('code');
$this->no_sorting('download');
$this->is_downloadable(true);
@ -135,6 +138,16 @@ class report_table extends \table_sql {
return userdate($user->timecreated);
}
/**
* Generate the code column.
*
* @param \stdClass $user
* @return string
*/
public function col_code($user) {
return $user->code;
}
/**
* Generate the download column.
*

View file

@ -69,17 +69,26 @@ class email_certificate_task extends \core\task\scheduled_task {
$htmlrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'htmlemail');
$textrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'textemail');
foreach ($customcerts as $customcert) {
// Do not process an empty certificate.
$sql = "SELECT ce.*
FROM {customcert_elements} ce
JOIN {customcert_pages} cp
ON cp.id = ce.pageid
JOIN {customcert_templates} ct
ON ct.id = cp.templateid
WHERE ct.contextid = :contextid";
if (!$DB->record_exists_sql($sql, ['contextid' => $customcert->contextid])) {
continue;
}
// Get the context.
$context = \context::instance_by_id($customcert->contextid);
// Get the person we are going to send this email on behalf of.
// Look through the teachers.
if ($teachers = get_enrolled_users($context, 'moodle/course:update')) {
$teachers = sort_by_roleassignment_authority($teachers, $context);
$userfrom = reset($teachers);
} else { // Ok, no teachers, use administrator name.
$userfrom = get_admin();
}
$userfrom = \core_user::get_noreply_user();
// Store teachers for later.
$teachers = get_enrolled_users($context, 'moodle/course:update');
$courseshortname = format_string($customcert->courseshortname, true, array('context' => $context));
$coursefullname = format_string($customcert->coursefullname, true, array('context' => $context));
@ -120,6 +129,11 @@ class email_certificate_task extends \core\task\scheduled_task {
continue;
}
// Only email those with the capability to receive the certificate.
if (!has_capability('mod/customcert:receiveissue', $context, $enroluser->id)) {
continue;
}
// Check that they have passed the required time.
if (!empty($customcert->requiredtime)) {
if (\mod_customcert\certificate::get_course_time($customcert->courseid,
@ -130,7 +144,7 @@ class email_certificate_task extends \core\task\scheduled_task {
// Ensure the cert hasn't already been issued, e.g via the UI (view.php) - a race condition.
$issueid = $DB->get_field('customcert_issues', 'id',
array('userid' => $enroluser->id, 'customcertid' => $customcert->id));
array('userid' => $enroluser->id, 'customcertid' => $customcert->id), IGNORE_MULTIPLE);
if (empty($issueid)) {
// Ok, issue them the certificate.
$issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $enroluser->id);
@ -163,6 +177,7 @@ class email_certificate_task extends \core\task\scheduled_task {
// Now, email the people we need to.
foreach ($issuedusers as $user) {
$userfullname = fullname($user);
$info->userfullname = $userfullname;
// Now, get the PDF.
$template = new \stdClass();

View file

@ -283,6 +283,16 @@ class template {
$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.
$filename = preg_replace('/[\s]+/', '_', $filename);
$filename = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $filename);
if (empty($filename)) {
$filename = get_string('certificate', 'customcert');
}
$filename = clean_filename($filename . '.pdf');
// Loop through the pages and display their content.
foreach ($pages as $page) {
@ -305,10 +315,12 @@ class template {
}
}
}
if ($return) {
return $pdf->Output('', 'S');
}
$pdf->Output($filename, 'D');
$pdf->Output($filename, 'I');
}
}

View file

@ -1,5 +1,5 @@
{
"name": "markn86/moodle-mod_customcert",
"name": "mdjnelson/moodle-mod_customcert",
"type": "moodle-mod",
"require": {
"composer/installers": "~1.0"

View file

@ -60,6 +60,14 @@ $capabilities = array(
)
),
'mod/customcert:receiveissue' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW
)
),
'mod/customcert:viewreport' => array(
'captype' => 'read',

View file

@ -23,7 +23,7 @@
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for customcert"/>
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_template" REFFIELDS="id"/>
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_templates" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="customcert_templates" COMMENT="Stores each customcert template">
@ -67,7 +67,7 @@
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for customcert_pages"/>
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_template" REFFIELDS="id"/>
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_templates" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="customcert_elements" COMMENT="Stores the elements for a given page">

View file

@ -30,7 +30,7 @@ $addons = [
'issueview' => [ // Handler unique name.
'displaydata' => [
'icon' => $CFG->wwwroot . '/mod/customcert/pix/icon.png',
'class' => '',
'class' => 'core-course-module-customcert-handler',
],
'delegate' => 'CoreCourseModuleDelegate', // Delegate (where to display the link to the plugin).
'method' => 'mobile_view_activity', // Main function in \mod_customcert\output\mobile.

View file

@ -38,7 +38,7 @@ class element extends \customcertelement_image\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('select', 'fileid', get_string('image', 'customcertelement_image'), self::get_images());

View file

@ -38,7 +38,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
// We want to define the width of the border.
@ -103,7 +103,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
if (!empty($this->get_data())) {

View file

@ -43,7 +43,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, self::get_category_name($this->get_id()));
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_category_name());
}
/**
@ -55,30 +55,28 @@ class element extends \mod_customcert\element {
* @return string the html
*/
public function render_html() {
global $COURSE;
$categoryname = format_string($COURSE->fullname, true, ['context' => \context_course::instance($COURSE->id)]);
return \mod_customcert\element_helper::render_html_content($this, $categoryname);
return \mod_customcert\element_helper::render_html_content($this, $this->get_category_name());
}
/**
* Helper function that returns the category name.
*
* @param int $elementid
* @return string
*/
protected static function get_category_name($elementid) {
protected function get_category_name() : string {
global $DB, $SITE;
$courseid = \mod_customcert\element_helper::get_courseid($elementid);
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$course = get_course($courseid);
$context = \mod_customcert\element_helper::get_context($this->get_id());
// Check that there is a course category available.
if (!empty($course->category)) {
$categoryname = $DB->get_field('course_categories', 'name', array('id' => $course->category), MUST_EXIST);
return format_string($categoryname, true, ['context' => \context_course::instance($courseid)]);
} else { // Must be in a site template.
return format_string($SITE->fullname, true, ['context' => \context_system::instance()]);
$categoryname = $SITE->fullname;
}
return format_string($categoryname, true, ['context' => $context]);
}
}

View file

@ -54,7 +54,7 @@ class element extends \mod_customcert\element {
$customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST);
// Now we can get the issue for this user.
$issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id),
'*', MUST_EXIST);
'*', IGNORE_MULTIPLE);
$code = $issue->code;
}

View file

@ -43,11 +43,7 @@ class element extends \mod_customcert\element {
* @param \stdClass $user the user we are rendering this for
*/
public function render($pdf, $preview, $user) {
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$course = get_course($courseid);
$coursename = format_string($course->fullname, true, ['context' => \context_course::instance($courseid)]);
\mod_customcert\element_helper::render_content($pdf, $this, $coursename);
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name());
}
/**
@ -59,9 +55,19 @@ class element extends \mod_customcert\element {
* @return string the html
*/
public function render_html() {
global $COURSE;
return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name());
}
$coursename = format_string($COURSE->fullname, true, ['context' => \context_course::instance($COURSE->id)]);
return \mod_customcert\element_helper::render_html_content($this, $coursename);
/**
* Helper function that returns the category name.
*
* @return string
*/
protected function get_course_name() : 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]);
}
}

View file

@ -51,6 +51,21 @@ define('CUSTOMCERT_DATE_COURSE_START', '-3');
*/
define('CUSTOMCERT_DATE_COURSE_END', '-4');
/**
* Date - Current date
*/
define('CUSTOMCERT_DATE_CURRENT_DATE', '-5');
/**
* Date - Enrollment start
*/
define('CUSTOMCERT_DATE_ENROLMENT_START', '-6');
/**
* Date - Entrollment end
*/
define('CUSTOMCERT_DATE_ENROLMENT_END', '-7');
require_once($CFG->dirroot . '/lib/grade/constants.php');
/**
@ -65,7 +80,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
global $CFG, $COURSE;
@ -73,10 +88,14 @@ class element extends \mod_customcert\element {
// Get the possible date options.
$dateoptions = array();
$dateoptions[CUSTOMCERT_DATE_ISSUE] = get_string('issueddate', 'customcertelement_date');
$dateoptions[CUSTOMCERT_DATE_CURRENT_DATE] = get_string('currentdate', 'customcertelement_date');
$completionenabled = $CFG->enablecompletion && ($COURSE->id == SITEID || $COURSE->enablecompletion);
if ($completionenabled) {
$dateoptions[CUSTOMCERT_DATE_COMPLETION] = get_string('completiondate', 'customcertelement_date');
}
$dateoptions[CUSTOMCERT_DATE_ENROLMENT_START] = get_string('enrolmentstartdate', 'customcertelement_date');
$dateoptions[CUSTOMCERT_DATE_ENROLMENT_END] = get_string('enrolmentenddate', 'customcertelement_date');
$dateoptions[CUSTOMCERT_DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_date');
$dateoptions[CUSTOMCERT_DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_date');
$dateoptions[CUSTOMCERT_DATE_COURSE_GRADE] = get_string('coursegradedate', 'customcertelement_date');
@ -141,10 +160,12 @@ class element extends \mod_customcert\element {
$customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST);
// Now we can get the issue for this user.
$issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id),
'*', MUST_EXIST);
'*', IGNORE_MULTIPLE);
if ($dateitem == CUSTOMCERT_DATE_ISSUE) {
$date = $issue->timecreated;
} else if ($dateitem == CUSTOMCERT_DATE_CURRENT_DATE) {
$date = time();
} else if ($dateitem == CUSTOMCERT_DATE_COMPLETION) {
// Get the last completion date.
$sql = "SELECT MAX(c.timecompleted) as timecompleted
@ -156,6 +177,26 @@ class element extends \mod_customcert\element {
$date = $timecompleted->timecompleted;
}
}
} else if ($dateitem == CUSTOMCERT_DATE_ENROLMENT_START) {
// Get the enrolment start date.
$sql = "SELECT ue.timestart FROM {enrol} e JOIN {user_enrolments} ue ON ue.enrolid = e.id
WHERE e.courseid = :courseid
AND ue.userid = :userid";
if ($timestart = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) {
if (!empty($timestart->timestart)) {
$date = $timestart->timestart;
}
}
} else if ($dateitem == CUSTOMCERT_DATE_ENROLMENT_END) {
// Get the enrolment end date.
$sql = "SELECT ue.timeend FROM {enrol} e JOIN {user_enrolments} ue ON ue.enrolid = e.id
WHERE e.courseid = :courseid
AND ue.userid = :userid";
if ($timeend = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) {
if (!empty($timeend->timeend)) {
$date = $timeend->timeend;
}
}
} else if ($dateitem == CUSTOMCERT_DATE_COURSE_START) {
$date = $DB->get_field('course', 'startdate', array('id' => $courseid));
} else if ($dateitem == CUSTOMCERT_DATE_COURSE_END) {
@ -218,7 +259,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
// Set the item and format for this element.

View file

@ -26,6 +26,9 @@ $string['completiondate'] = 'Completion date';
$string['courseenddate'] = 'Course end date';
$string['coursegradedate'] = 'Course grade date';
$string['coursestartdate'] = 'Course start date';
$string['enrolmentenddate'] = 'Enrolment end date';
$string['enrolmentstartdate'] = 'Enrolment start date';
$string['currentdate'] = 'Current date';
$string['dateformat'] = 'Date format';
$string['dateformat_help'] = 'This is the format of the date that will be displayed';
$string['dateitem'] = 'Date item';

View file

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
$plugin->version = 2018051700; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2018051701; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2018051700; // Requires this Moodle version (3.5).
$plugin->component = 'customcertelement_date';

View file

@ -0,0 +1,731 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* This file contains the customcert date range element.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace customcertelement_daterange;
use \mod_customcert\element_helper;
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
require_once($CFG->dirroot . '/lib/grade/constants.php');
/**
* The customcert date range element.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class element extends \mod_customcert\element {
/**
* Max recurring period in seconds.
*/
const MAX_RECURRING_PERIOD = 31556926; // 12 months.
/**
* Current year placeholder string.
*/
const CURRENT_YEAR_PLACEHOLDER = '{{current_year}}';
/**
* First year in a date range placeholder string.
*/
const RANGE_FIRST_YEAR_PLACEHOLDER = '{{range_first_year}}';
/**
* Last year in a date range placeholder string.
*/
const RANGE_LAST_YEAR_PLACEHOLDER = '{{range_last_year}}';
/**
* First year in a date range placeholder string.
*/
const RECUR_RANGE_FIRST_YEAR_PLACEHOLDER = '{{recurring_range_first_year}}';
/**
* Last year in a date range placeholder string.
*/
const RECUR_RANGE_LAST_YEAR_PLACEHOLDER = '{{recurring_range_last_year}}';
/**
* A year in the user's date.
*/
const DATE_YEAR_PLACEHOLDER = '{{date_year}}';
/**
* Date - Issue
*/
const DATE_ISSUE = -1;
/**
* Date - Completion
*/
const DATE_COMPLETION = -2;
/**
* Date - Course start
*/
const DATE_COURSE_START = -3;
/**
* Date - Course end
*/
const DATE_COURSE_END = -4;
/**
* Date - Course grade date
*/
const DATE_COURSE_GRADE = -5;
/**
* Date - Course current date
*/
const DATE_CURRENT_DATE = -6;
/**
* This function renders the form elements when adding a customcert element.
*
* @param \MoodleQuickForm $mform the edit form instance
*/
public function render_form_elements($mform) {
global $COURSE;
// Get the possible date options.
$dateoptions = array();
$dateoptions[self::DATE_ISSUE] = get_string('issueddate', 'customcertelement_daterange');
$dateoptions[self::DATE_CURRENT_DATE] = get_string('currentdate', 'customcertelement_daterange');
$dateoptions[self::DATE_COMPLETION] = get_string('completiondate', 'customcertelement_daterange');
$dateoptions[self::DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_daterange');
$dateoptions[self::DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_daterange');
$dateoptions[self::DATE_COURSE_GRADE] = get_string('coursegradedate', 'customcertelement_daterange');
$dateoptions = $dateoptions + element_helper::get_grade_items($COURSE);
$mform->addElement('select', 'dateitem', get_string('dateitem', 'customcertelement_daterange'), $dateoptions);
$mform->addHelpButton('dateitem', 'dateitem', 'customcertelement_daterange');
parent::render_form_elements($mform);
$mform->addElement('header', 'dateranges', get_string('dateranges', 'customcertelement_daterange'));
$mform->addElement('static', 'help', '', get_string('help', 'customcertelement_daterange'));
$mform->addElement('static', 'placeholders', '', get_string('placeholders', 'customcertelement_daterange'));
$mform->addElement('text', 'fallbackstring', get_string('fallbackstring', 'customcertelement_daterange'));
$mform->addHelpButton('fallbackstring', 'fallbackstring', 'customcertelement_daterange');
$mform->setType('fallbackstring', PARAM_NOTAGS);
if (empty($this->get_decoded_data()->dateranges)) {
$repeats = 1;
} else {
$repeats = count($this->get_decoded_data()->dateranges);
}
$ranges = [];
$ranges[] = $mform->createElement('html', '<hr>');
$ranges[] = $mform->createElement(
'date_selector',
'startdate',
get_string('start', 'customcertelement_daterange')
);
$ranges[] = $mform->createElement(
'date_selector',
'enddate',
get_string('end', 'customcertelement_daterange')
);
$ranges[] = $mform->createElement(
'checkbox',
'recurring',
get_string('recurring', 'customcertelement_daterange')
);
$ranges[] = $mform->createElement(
'text',
'datestring',
get_string('datestring', 'customcertelement_daterange'),
['class' => 'datestring']
);
$ranges[] = $mform->createElement(
'advcheckbox',
'rangedelete',
get_string('setdeleted', 'customcertelement_daterange'),
'',
[],
[0, 1]
);
$rangeoptions = array();
$rangeoptions['startdate']['type'] = PARAM_INT;
$rangeoptions['enddate']['type'] = PARAM_INT;
$rangeoptions['recurring']['type'] = PARAM_INT;
$rangeoptions['recurring']['helpbutton'] = ['recurring', 'customcertelement_daterange'];
$rangeoptions['datestring']['type'] = PARAM_NOTAGS;
$rangeoptions['rangedelete']['type'] = PARAM_BOOL;
$addstring = get_string('addrange', 'customcertelement_daterange');
$this->get_edit_element_form()->repeat_elements($ranges, $repeats, $rangeoptions, 'repeats', 'add', 1, $addstring, true);
}
/**
* A helper function to build consistent form element name.
*
* @param string $name
* @param string $num
*
* @return string
*/
protected function build_element_name($name, $num) {
return $name . '[' . $num . ']';
}
/**
* Get decoded data stored in DB.
*
* @return \stdClass
*/
protected function get_decoded_data() {
return json_decode($this->get_data());
}
/**
* 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()) && !$mform->isSubmitted()) {
$element = $mform->getElement('dateitem');
$element->setValue($this->get_decoded_data()->dateitem);
$element = $mform->getElement('fallbackstring');
$element->setValue($this->get_decoded_data()->fallbackstring);
foreach ($this->get_decoded_data()->dateranges as $key => $range) {
$mform->setDefault($this->build_element_name('startdate', $key), $range->startdate);
$mform->setDefault($this->build_element_name('enddate', $key), $range->enddate);
$mform->setDefault($this->build_element_name('datestring', $key), $range->datestring);
$mform->setDefault($this->build_element_name('recurring', $key), $range->recurring);
}
}
parent::definition_after_data($mform);
}
/**
* Performs validation on the element values.
*
* @param array $data the submitted data
* @param array $files the submitted files
* @return array the validation errors
*/
public function validate_form_elements($data, $files) {
$errors = parent::validate_form_elements($data, $files);
// Check if at least one range is set.
$error = get_string('error:atleastone', 'customcertelement_daterange');
for ($i = 0; $i < $data['repeats']; $i++) {
if (empty($data['rangedelete'][$i])) {
$error = '';
}
}
if (!empty($error)) {
$errors['help'] = $error;
}
// Check that datestring is set dataranges what aren't need to be deleted.
for ($i = 0; $i < $data['repeats']; $i++) {
// Skip elements that needs to be deleted.
if (!empty($data['rangedelete'][$i])) {
continue;
}
if (empty($data['datestring'][$i])) {
$name = $this->build_element_name('datestring', $i);
$errors[$name] = get_string('error:datestring', 'customcertelement_daterange');
}
// Check that end date is correctly set.
if ( $data['startdate'][$i] >= $data['enddate'][$i] ) {
$errors[$this->build_element_name('enddate', $i)] = get_string('error:enddate', 'customcertelement_daterange');
}
$rangeperiod = $data['enddate'][$i] - $data['startdate'][$i];
// Check that recurring dateranges are not longer than 12 months.
if (!empty($data['recurring'][$i]) && $rangeperiod >= self::MAX_RECURRING_PERIOD ) {
$errors[$this->build_element_name('enddate', $i)] = get_string('error:recurring', 'customcertelement_daterange');
}
}
return $errors;
}
/**
* This will handle how form data will be saved into the data column in the
* customcert_elements table.
*
* @param \stdClass $data the form data
* @return string the json encoded array
*/
public function save_unique_data($data) {
$arrtostore = array(
'dateitem' => $data->dateitem,
'fallbackstring' => $data->fallbackstring,
'dateranges' => [],
);
for ($i = 0; $i < $data->repeats; $i++) {
if (empty($data->rangedelete[$i])) {
$arrtostore['dateranges'][] = [
'startdate' => $data->startdate[$i],
'enddate' => $data->enddate[$i],
'datestring' => $data->datestring[$i],
'recurring' => !empty($data->recurring[$i]),
];
}
}
// Encode these variables before saving into the DB.
return json_encode($arrtostore);
}
/**
* Handles rendering the element on the pdf.
*
* @param \pdf $pdf the pdf object
* @param bool $preview true if it is a preview, false otherwise
* @param \stdClass $user the user we are rendering this for
*/
public function render($pdf, $preview, $user) {
global $DB;
// If there is no element data, we have nothing to display.
if (empty($this->get_data())) {
return;
}
$courseid = element_helper::get_courseid($this->id);
$dateitem = $this->get_decoded_data()->dateitem;
// If we are previewing this certificate then just show a demonstration date.
if ($preview) {
$date = time();
} else {
// Get the page.
$page = $DB->get_record('customcert_pages', array('id' => $this->get_pageid()), '*', MUST_EXIST);
// Get the customcert this page belongs to.
$customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST);
// Now we can get the issue for this user.
$issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id),
'*', MUST_EXIST);
switch ($dateitem) {
case self::DATE_ISSUE:
$date = $issue->timecreated;
break;
case self::DATE_CURRENT_DATE:
$date = time();
break;
case self::DATE_COMPLETION:
// Get the last completion date.
$sql = "SELECT MAX(c.timecompleted) as timecompleted
FROM {course_completions} c
WHERE c.userid = :userid
AND c.course = :courseid";
if ($timecompleted = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) {
if (!empty($timecompleted->timecompleted)) {
$date = $timecompleted->timecompleted;
}
}
break;
case self::DATE_COURSE_START:
$date = $DB->get_field('course', 'startdate', array('id' => $courseid));
break;
case self::DATE_COURSE_END:
$date = $DB->get_field('course', 'enddate', array('id' => $courseid));
break;
case self::DATE_COURSE_GRADE:
$grade = element_helper::get_course_grade_info(
$courseid,
GRADE_DISPLAY_TYPE_DEFAULT, $user->id
);
if ($grade && !empty($grade->get_dategraded())) {
$date = $grade->get_dategraded();
}
break;
default:
if (strpos($dateitem, 'gradeitem:') === 0) {
$gradeitemid = substr($dateitem, 10);
$grade = element_helper::get_grade_item_info(
$gradeitemid,
$dateitem,
$user->id
);
} else {
$grade = element_helper::get_mod_grade_info(
$dateitem,
GRADE_DISPLAY_TYPE_DEFAULT,
$user->id
);
}
if ($grade && !empty($grade->get_dategraded())) {
$date = $grade->get_dategraded();
}
break;
}
}
// Ensure that a date has been set.
if (!empty($date)) {
element_helper::render_content($pdf, $this, $this->get_daterange_string($date));
}
}
/**
* Get daterange string.
*
* @param int $date Unix stamp date.
*
* @return string
*/
protected function get_daterange_string($date) {
$matchedrange = null;
$outputstring = '';
$formatdata = [];
$formatdata['date'] = $date;
foreach ($this->get_decoded_data()->dateranges as $key => $range) {
if ($this->is_recurring_range($range)) {
if ($matchedrange = $this->get_matched_recurring_range($date, $range)) {
$outputstring = $matchedrange->datestring;
$formatdata['range'] = $range;
$formatdata['recurringrange'] = $matchedrange;
break;
}
} else {
if ($this->is_date_in_range($date, $range)) {
$outputstring = $range->datestring;
$formatdata['range'] = $range;
break;
}
}
}
if (empty($outputstring) && !empty($this->get_decoded_data()->fallbackstring)) {
$outputstring = $this->get_decoded_data()->fallbackstring;
}
return $this->format_date_string($outputstring, $formatdata);
}
/**
* Returns whether or not a range is recurring.
*
* @param \stdClass $range Range object.
*
* @return bool
*/
protected function is_recurring_range(\stdClass $range) {
return !empty($range->recurring);
}
/**
* Check if the provided date is in the date range.
*
* @param int $date Unix timestamp date to check.
* @param \stdClass $range Range object.
*
* @return bool
*/
protected function is_date_in_range($date, \stdClass $range) {
return ($date >= $range->startdate && $date <= $range->enddate);
}
/**
* Check if provided date is in the recurring date range.
*
* @param int $date Unix timestamp date to check.
* @param \stdClass $range Range object.
*
* @return bool
*/
protected function is_date_in_recurring_range($date, \stdClass $range) {
$intdate = $this->build_number_from_date($date);
$intstart = $this->build_number_from_date($range->startdate);
$intend = $this->build_number_from_date($range->enddate);
if (!$this->has_turn_of_the_year($range)) {
if ($intdate >= $intstart && $intdate <= $intend) {
return true;
}
} else {
if ($intdate >= $intstart && $intdate >= $intend) {
return true;
}
if ($intdate <= $intstart && $intdate <= $intend) {
return true;
}
}
return false;
}
/**
* Check if provided recurring range has a turn of the year.
*
* @param \stdClass $reccurringrange Range object.
*
* @return bool
*/
protected function has_turn_of_the_year(\stdClass $reccurringrange) {
return date('Y', $reccurringrange->startdate) != date('Y', $reccurringrange->enddate);
}
/**
* Check if provided date is in the start year of the recurring range with a turn of the year.
*
* @param int $date Unix timestamp date to check.
* @param \stdClass $range Range object.
*
* @return bool
*/
protected function in_start_year($date, \stdClass $range) {
$intdate = $this->build_number_from_date($date);
$intstart = $this->build_number_from_date($range->startdate);
$intend = $this->build_number_from_date($range->enddate);
return $intdate >= $intstart && $intdate >= $intend;
}
/**
* Check if provided date is in the end year of the recurring range with a turn of the year.
*
* @param int $date Unix timestamp date to check.
* @param \stdClass $range Range object.
*
* @return bool
*/
protected function in_end_year($date, \stdClass $range) {
$intdate = $this->build_number_from_date($date);
$intstart = $this->build_number_from_date($range->startdate);
$intend = $this->build_number_from_date($range->enddate);
return $intdate <= $intstart && $intdate <= $intend;
}
/**
* Return matched recurring date range.
*
* As recurring date ranges do not depend on the year,
* we will use a date's year to build a new matched recurring date range with
* start year and end year. This is required to replace placeholders like range_first_year and range_last_year.
*
* @param int $date Unix timestamp date to check.
* @param \stdClass $range Range object.
*
* @return \stdClass || null
*/
protected function get_matched_recurring_range($date, \stdClass $range) {
if (!$this->is_date_in_recurring_range($date, $range)) {
return null;
}
$matchedrage = clone $range;
if ($this->has_turn_of_the_year($matchedrage)) {
if ($this->in_start_year($date, $matchedrage)) {
$startyear = date('Y', $date);
$endyear = $startyear + 1;
$matchedrage->startdate = strtotime(date('d.m.', $matchedrage->startdate) . $startyear);
$matchedrage->enddate = strtotime(date('d.m.', $matchedrage->enddate) . $endyear);
return $matchedrage;
}
if ($this->in_end_year($date, $matchedrage)) {
$endyear = date('Y', $date);
$startyear = $endyear - 1;
$matchedrage->startdate = strtotime(date('d.m.', $matchedrage->startdate) . $startyear);
$matchedrage->enddate = strtotime(date('d.m.', $matchedrage->enddate) . $endyear);
return $matchedrage;
}
} else {
$matchedrage->startdate = strtotime(date('d.m.', $matchedrage->startdate) . date('Y', $date));
$matchedrage->enddate = strtotime(date('d.m.', $matchedrage->enddate) . date('Y', $date));
return $matchedrage;
}
return null;
}
/**
* Build number representation of the provided date.
*
* @param int $date Unix timestamp date to check.
*
* @return int
*/
protected function build_number_from_date($date) {
return (int)date('md', $date);
}
/**
* Format date string based on different types of placeholders.
*
* @param string $datestring The date string
* @param array $formatdata A list of format data.
*
* @return string
*/
protected function format_date_string($datestring, array $formatdata) {
foreach ($this->get_placeholders() as $search => $replace) {
$datestring = str_replace($search, $replace, $datestring);
}
if (!empty($formatdata['date'])) {
foreach ($this->get_date_placeholders($formatdata['date']) as $search => $replace) {
$datestring = str_replace($search, $replace, $datestring);
}
}
if (!empty($formatdata['range'])) {
foreach ($this->get_range_placeholders($formatdata['range']) as $search => $replace) {
$datestring = str_replace($search, $replace, $datestring);
}
}
if (!empty($formatdata['recurringrange'])) {
foreach ($this->get_recurring_range_placeholders($formatdata['recurringrange']) as $search => $replace) {
$datestring = str_replace($search, $replace, $datestring);
}
}
return $datestring;
}
/**
* Return a list of placeholders to replace in date string as search => $replace pairs.
*
* @return array
*/
protected function get_placeholders() {
return [
self::CURRENT_YEAR_PLACEHOLDER => date('Y', time()),
];
}
/**
* Return a list of user's date related placeholders to replace in date string as search => $replace pairs.
* @param int $date Unix timestamp date to check.
*
* @return array
*/
protected function get_date_placeholders($date) {
return [
self::DATE_YEAR_PLACEHOLDER => date('Y', $date),
];
}
/**
* Return a list of range related placeholders to replace in date string as search => $replace pairs.
*
* @param \stdClass $range
*
* @return array
*/
protected function get_range_placeholders(\stdClass $range) {
return [
self::RANGE_FIRST_YEAR_PLACEHOLDER => date('Y', $range->startdate),
self::RANGE_LAST_YEAR_PLACEHOLDER => date('Y', $range->enddate),
];
}
/**
* Return a list of recurring range s placeholders to replace in date string as search => $replace pairs.
*
* @param \stdClass $range
*
* @return array
*/
protected function get_recurring_range_placeholders(\stdClass $range) {
return [
self::RECUR_RANGE_FIRST_YEAR_PLACEHOLDER => date('Y', $range->startdate),
self::RECUR_RANGE_LAST_YEAR_PLACEHOLDER => date('Y', $range->enddate),
];
}
/**
* Render the element in html.
*
* This function is used to render the element when we are using the
* drag and drop interface to position it.
*
* @return string the html
*/
public function render_html() {
// If there is no element data, we have nothing to display.
if (empty($this->get_data())) {
return;
}
return element_helper::render_html_content($this, get_string('preview', 'customcertelement_daterange', $this->get_name()));
}
/**
* This function is responsible for handling the restoration process of the element.
*
* We will want to update the course module the date element is pointing to as it will
* have changed in the course restore.
*
* @param \restore_customcert_activity_task $restore
*/
public function after_restore($restore) {
global $DB;
$data = $this->get_decoded_data();
if ($newitem = \restore_dbops::get_backup_ids_record($restore->get_restoreid(), 'course_module', $data->dateitem)) {
$data->dateitem = $newitem->newitemid;
$DB->set_field('customcert_elements', 'data', $this->save_unique_data($data), array('id' => $this->get_id()));
}
}
}

View file

@ -0,0 +1,46 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for customcertelement_daterange.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace customcertelement_daterange\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for customcertelement_daterange implementing null_provider.
*
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}

View file

@ -0,0 +1,53 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* Strings for component 'customcertelement_daterange', language 'en'.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
$string['addrange'] = 'Add another range';
$string['completiondate'] = 'Completion date';
$string['courseenddate'] = 'Course end date';
$string['coursegradedate'] = 'Course grade date';
$string['coursestartdate'] = 'Course start date';
$string['currentdate'] = 'Current date';
$string['dateitem'] = 'Date item';
$string['dateitem_help'] = 'This will be the date that is printed on the certificate';
$string['dateranges'] = 'Date ranges';
$string['datestring'] = 'String';
$string['end'] = 'End';
$string['error:atleastone'] = 'You must have at least one date range configured';
$string['error:datestring'] = 'You must provide string representation for the date range';
$string['error:enddate'] = 'End date must occur after the start date';
$string['error:recurring'] = 'Recurring range must not be longer than 12 months';
$string['fallbackstring'] = 'Fallback string';
$string['fallbackstring_help'] = 'This string will be displayed if no date range applies to a date. If the fallback string is not set, then there will be no output at all.';
$string['help'] = 'Configure a string representation for your date ranges.<br /><br />If your ranges overlap the first matched date range will be applied.';
$string['issueddate'] = 'Issued date';
$string['placeholders'] = 'The following placeholders can be used in the string representation or fallback string. <br/><br /> {{range_first_year}} - first year of the matched range,<br/> {{range_last_year}} - last year of the matched range,<br/> {{recurring_range_first_year}} - first year of the matched recurring period,<br/> {{recurring_range_last_year}} - last year of the matched recurring period,<br/> {{current_year}} - the current year,<br/> {{date_year}} - a year of the users\'s date.';
$string['pluginname'] = 'Date range';
$string['preview'] = 'Preview {$a}';
$string['privacy:metadata'] = 'The Date range plugin does not store any personal data.';
$string['recurring'] = 'Recurring';
$string['recurring_help'] = 'If you mark a date range as recurring then the configured year will not be considered.';
$string['setdeleted'] = 'Delete';
$string['start'] = 'Start';

View file

@ -0,0 +1,248 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* Test datarange element.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/customcert/element/daterange/tests/fixtures/fake_datarange_element.php');
/**
* Test datarange element.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class customcertelement_daterange_element_test extends advanced_testcase {
/**
* Helper function to build element data.
*
* @param stdClass $data Element data.
*
* @return object
*/
protected function build_element_data(stdClass $data) {
return (object) [
'id' => 1,
'pageid' => 1,
'name' => 'Test',
'data' => json_encode($data),
'font' => 'Font',
'fontsize' => 1,
'colour' => '#EEE',
'posx' => 0,
'posy' => 0,
'width' => 100,
'refpoint' => 1
];
}
/**
* Helper function to build datarange data.
*
* @param array $dataranges A list of dataranges.
* @param string $fallbackstring Fall back string.
*
* @return object
*/
protected function build_datarange_data(array $dataranges, $fallbackstring = '') {
return (object) [
'dateitem' => 1,
'fallbackstring' => $fallbackstring,
'numranges' => count($dataranges),
'dateranges' => $dataranges,
];
}
/**
* A helper function to get datarange element for testing.
*
* @param array $dataranges A list of dataranges.
* @param string $fallbackstring Fall back strin
*
* @return \fake_datarange_element
*/
protected function get_datarange_element(array $dataranges, $fallbackstring = '') {
$datarangedata = $this->build_datarange_data($dataranges, $fallbackstring);
$elementdata = $this->build_element_data($datarangedata);
return new fake_datarange_element($elementdata);
}
/**
* Data provider for test_get_daterange_string_for_recurring_ranges.
* @return array
*/
public function get_test_get_daterange_string_for_recurring_ranges_data_provider() {
return [
['1.11.2016', 'WS 2016/2017'],
['1.11.2017', 'WS 2017/2018'],
['1.11.2018', 'WS 2018/2019'],
['1.11.2019', 'WS 2019/2020'],
['1.02.2017', 'WS 2016/2017'],
['1.02.2018', 'WS 2017/2018'],
['1.02.2019', 'WS 2018/2019'],
['1.02.2020', 'WS 2019/2020'],
['1.05.2016', 'SS 2016'],
['1.05.2017', 'SS 2017'],
['1.05.2018', 'SS 2018'],
['1.05.2019', 'SS 2019'],
];
}
/**
* Test get correct strings for recurring ranges.
*
* @dataProvider get_test_get_daterange_string_for_recurring_ranges_data_provider
*
* @param string $date Date to test.
* @param string $expected Expected result.
*/
public function test_get_daterange_string_for_recurring_ranges($date, $expected) {
$dateranges = [
(object)[
'startdate' => strtotime('01.04.2017'),
'enddate' => strtotime('30.09.2017'),
'datestring' => 'SS {{date_year}}',
'recurring' => true,
],
(object)[
'startdate' => strtotime('01.10.2017'),
'enddate' => strtotime('31.03.2018'),
'datestring' => 'WS {{recurring_range_first_year}}/{{recurring_range_last_year}}',
'recurring' => true,
],
];
$element = $this->get_datarange_element($dateranges);
$date = strtotime($date);
$this->assertEquals($expected, $element->get_daterange_string($date));
}
/**
* Test that first found element matched.
*/
public function test_that_first_matched_range_applied_first() {
$dateranges = [
(object)[
'startdate' => strtotime('01.04.2017'),
'enddate' => strtotime('30.09.2017'),
'datestring' => 'First range',
'recurring' => false,
],
(object)[
'startdate' => strtotime('01.05.2017'),
'enddate' => strtotime('01.07.2018'),
'datestring' => 'Second range',
'recurring' => false,
],
];
$element = $this->get_datarange_element($dateranges);
$date = strtotime('1.06.2017');
$this->assertEquals('First range', $element->get_daterange_string($date));
}
/**
* Test that placeholders correctly applied to matched range and fall back string.
*/
public function test_placeholders_and_fall_back_string() {
$dateranges = [
(object)[
'startdate' => strtotime('01.04.2017'),
'enddate' => strtotime('30.09.2018'),
'datestring' => '{{current_year}} - {{range_first_year}} - {{range_last_year}} - {{date_year}}',
'recurring' => false,
],
];
$fallbackstring = '{{current_year}} - {{range_first_year}} - {{range_last_year}} - {{date_year}}';
$element = $this->get_datarange_element($dateranges, $fallbackstring);
$date = strtotime('1.01.2000');
$expected = date('Y', time()) . ' - {{range_first_year}} - {{range_last_year}} - 2000';
$this->assertEquals($expected, $element->get_daterange_string($date));
$date = strtotime('1.07.2017');
$expected = date('Y', time()) . ' - 2017 - 2018 - 2017';
$this->assertEquals($expected, $element->get_daterange_string($date));
}
/**
* Test that nothing will be displayed if not matched and empty fall back string.
*/
public function test_nothing_will_be_displayed_if_empty_fallback_string() {
$dateranges = [
(object)[
'startdate' => strtotime('01.04.2017'),
'enddate' => strtotime('30.09.2018'),
'datestring' => '{{current_year}} - {{range_first_year}} - {{range_last_year}} - {{date_year}}',
'recurring' => false,
],
];
$fallbackstring = '';
$element = $this->get_datarange_element($dateranges, $fallbackstring);
$date = strtotime('1.07.2011');
$this->assertEquals($fallbackstring, $element->get_daterange_string($date));
}
/**
* Test that display recurring_range_first_year and recurring_range_last_year placeholders.
*/
public function test_recurring_range_first_year_and_recurring_range_last_year_placeholders() {
$datestring = '{{range_first_year}}-{{range_last_year}}-{{recurring_range_first_year}}-{{recurring_range_last_year}}';
$dateranges = [
(object) [
'startdate' => strtotime('01.04.2017'),
'enddate' => strtotime('30.09.2017'),
'datestring' => $datestring,
'recurring' => true,
],
(object)[
'startdate' => strtotime('01.10.2017'),
'enddate' => strtotime('31.03.2018'),
'datestring' => $datestring,
'recurring' => true,
],
];
$element = $this->get_datarange_element($dateranges);
$date = strtotime('1.05.2020');
$this->assertEquals('2017-2017-2020-2020', $element->get_daterange_string($date));
$date = strtotime('1.05.2024');
$this->assertEquals('2017-2017-2024-2024', $element->get_daterange_string($date));
$date = strtotime('1.02.2020');
$this->assertEquals('2017-2018-2019-2020', $element->get_daterange_string($date));
$date = strtotime('1.02.2024');
$this->assertEquals('2017-2018-2023-2024', $element->get_daterange_string($date));
}
}

View file

@ -0,0 +1,47 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* Fake datarange element for testing.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Fake datarange element for testing.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class fake_datarange_element extends \customcertelement_daterange\element {
/**
* Override protected method for testing.
*
* @param int $date
*
* @return string
*/
public function get_daterange_string($date) {
$result = parent::get_daterange_string($date);
return $result;
}
}

View file

@ -0,0 +1,29 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* This file contains the version information for the date plugin.
*
* @package customcertelement_daterange
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
$plugin->version = 2018051700; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2018051700; // Requires this Moodle version (3.5).
$plugin->component = 'customcertelement_daterange';

View file

@ -60,7 +60,7 @@ class element extends \customcertelement_image\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('select', 'fileid', get_string('image', 'customcertelement_image'), self::get_images());
@ -240,7 +240,7 @@ class element extends \customcertelement_image\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
global $COURSE, $SITE;

View file

@ -43,7 +43,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
global $COURSE;
@ -107,7 +107,7 @@ class element extends \mod_customcert\element {
// If we are previewing this certificate then just show a demonstration grade.
if ($preview) {
$courseitem = \grade_item::fetch_course_item($courseid);
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);;
} else {
if ($gradeitem == CUSTOMCERT_GRADE_COURSE) {
$grade = \mod_customcert\element_helper::get_course_grade_info(
@ -167,7 +167,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
// Set the item and format for this element.

View file

@ -38,7 +38,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
global $COURSE;
@ -73,20 +73,9 @@ class element extends \mod_customcert\element {
* @param \stdClass $user the user we are rendering this for
*/
public function render($pdf, $preview, $user) {
global $DB;
// Check that the grade item is not empty.
if (!empty($this->get_data())) {
// Get the course module information.
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
// Get the name of the item.
$courseid = \mod_customcert\element_helper::get_courseid($this->get_data());
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
$itemname = format_string($itemname, true, ['context' => \context_course::instance($courseid)]);
\mod_customcert\element_helper::render_content($pdf, $this, $itemname);
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_grade_item_name());
}
}
@ -99,20 +88,9 @@ class element extends \mod_customcert\element {
* @return string the html
*/
public function render_html() {
global $DB;
// Check that the grade item is not empty.
if (!empty($this->get_data())) {
// Get the course module information.
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
// Get the name of the item.
$courseid = \mod_customcert\element_helper::get_courseid($this->get_data());
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
$itemname = format_string($itemname, true, ['context' => \context_course::instance($courseid)]);
return \mod_customcert\element_helper::render_html_content($this, $itemname);
return \mod_customcert\element_helper::render_html_content($this, $this->get_grade_item_name());
}
return '';
@ -121,7 +99,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
if (!empty($this->get_data())) {
@ -130,4 +108,42 @@ class element extends \mod_customcert\element {
}
parent::definition_after_data($mform);
}
/**
* Helper function that returns the grade item name.
*
* @return string
*/
protected function get_grade_item_name() : string {
global $DB;
$gradeitem = $this->get_data();
if (strpos($gradeitem, 'gradeitem:') === 0) {
$gradeitemid = substr($gradeitem, 10);
$gradeitem = \grade_item::fetch(['id' => $gradeitemid]);
return $gradeitem->get_name();
} else {
if (!$cm = $DB->get_record('course_modules', array('id' => $gradeitem))) {
return '';
}
if (!$module = $DB->get_record('modules', array('id' => $cm->module))) {
return '';
}
$params = [
'itemtype' => 'mod',
'itemmodule' => $module->name,
'iteminstance' => $cm->instance,
'courseid' => $cm->course,
'itemnumber' => 0
];
$gradeitem = \grade_item::fetch($params);
return $gradeitem->get_name();
}
}
}

View file

@ -60,7 +60,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('select', 'fileid', get_string('image', 'customcertelement_image'), self::get_images());
@ -282,7 +282,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
global $COURSE, $SITE;
@ -382,14 +382,14 @@ class element extends \mod_customcert\element {
// Loop through the files uploaded in the system context.
if ($files = $fs->get_area_files(\context_system::instance()->id, 'mod_customcert', 'image', false, 'filename', false)) {
foreach ($files as $hash => $file) {
$arrfiles[$file->get_id()] = $file->get_filename();
$arrfiles[$file->get_id()] = get_string('systemimage', 'customcertelement_image', $file->get_filename());
}
}
// Loop through the files uploaded in the course context.
if ($files = $fs->get_area_files(\context_course::instance($COURSE->id)->id, 'mod_customcert', 'image', false,
'filename', false)) {
foreach ($files as $hash => $file) {
$arrfiles[$file->get_id()] = $file->get_filename();
$arrfiles[$file->get_id()] = get_string('courseimage', 'customcertelement_image', $file->get_filename());
}
}
@ -398,4 +398,60 @@ class element extends \mod_customcert\element {
return $arrfiles;
}
/**
* This handles copying data from another element of the same type.
*
* @param \stdClass $data the form data
* @return bool returns true if the data was copied successfully, false otherwise
*/
public function copy_element($data) {
global $COURSE, $DB, $SITE;
$imagedata = json_decode($data->data);
// If we are in the site context we don't have to do anything, the image is already there.
if ($COURSE->id == $SITE->id) {
return true;
}
$coursecontext = \context_course::instance($COURSE->id);
$systemcontext = \context_system::instance();
$fs = get_file_storage();
// Check that a file has been selected.
if (isset($imagedata->filearea)) {
// If the course file doesn't exist, copy the system file to the course context.
if (!$coursefile = $fs->get_file(
$coursecontext->id,
'mod_customcert',
$imagedata->filearea,
$imagedata->itemid,
$imagedata->filepath,
$imagedata->filename
)) {
$systemfile = $fs->get_file(
$systemcontext->id,
'mod_customcert',
$imagedata->filearea,
$imagedata->itemid,
$imagedata->filepath,
$imagedata->filename
);
// We want to update the context of the file if it doesn't exist in the course context.
$fieldupdates = [
'contextid' => $coursecontext->id
];
$coursefile = $fs->create_file_from_storedfile($fieldupdates, $systemfile);
}
// Set the image to the copied file in the course.
$imagedata->fileid = $coursefile->get_id();
$DB->set_field('customcert_elements', 'data', $this->save_unique_data($imagedata), ['id' => $this->get_id()]);
}
return true;
}
}

View file

@ -24,6 +24,7 @@
$string['alphachannel'] = 'Alpha channel';
$string['alphachannel_help'] = 'This value determines how transparent the image is. You can set the alpha channel from 0 (fully transparent) to 1 (fully opaque).';
$string['courseimage'] = 'Course image: {$a}';
$string['height'] = 'Height';
$string['height_help'] = 'Height of the image in mm. If equal to zero, it is automatically calculated.';
$string['image'] = 'Image';
@ -31,5 +32,6 @@ $string['invalidheight'] = 'The height has to be a valid number greater than or
$string['invalidwidth'] = 'The width has to be a valid number greater than or equal to 0.';
$string['pluginname'] = 'Image';
$string['privacy:metadata'] = 'The Image plugin does not store any personal data.';
$string['systemimage'] = 'Site image: {$a}';
$string['width'] = 'Width';
$string['width_help'] = 'Width of the image in mm. If equal to zero, it is automatically calculated.';

View file

@ -0,0 +1,208 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* This file contains the customcert element QR code's core interaction API.
*
* @package customcertelement_qrcode
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace customcertelement_qrcode;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/tcpdf/tcpdf_barcodes_2d.php');
/**
* The customcert element QR code's core interaction API.
*
* @package customcertelement_qrcode
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class element extends \mod_customcert\element {
/**
* @var string The barcode type.
*/
const BARCODETYPE = 'QRCODE';
/**
* This function renders the form elements when adding a customcert element.
*
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
\mod_customcert\element_helper::render_form_element_width($mform);
$mform->addElement('text', 'height', get_string('height', 'customcertelement_qrcode'), array('size' => 10));
$mform->setType('height', PARAM_INT);
$mform->setDefault('height', 0);
$mform->addHelpButton('height', 'height', 'customcertelement_qrcode');
if ($this->showposxy) {
\mod_customcert\element_helper::render_form_element_position($mform);
}
}
/**
* Performs validation on the element values.
*
* @param array $data the submitted data
* @param array $files the submitted files
* @return array the validation errors
*/
public function validate_form_elements($data, $files) {
// Array to return the errors.
$errors = [];
// Check if height is not set, or not numeric or less than 0.
if ((!isset($data['height'])) || (!is_numeric($data['height'])) || ($data['height'] <= 0)) {
$errors['height'] = get_string('invalidheight', 'mod_customcert');
}
if ((!isset($data['width'])) || (!is_numeric($data['width'])) || ($data['width'] <= 0)) {
$errors['width'] = get_string('invalidwidth', 'mod_customcert');
}
if ($this->showposxy) {
$errors += \mod_customcert\element_helper::validate_form_element_position($data);
}
$errors += \mod_customcert\element_helper::validate_form_element_width($data);
return $errors;
}
/**
* This will handle how form data will be saved into the data column in the
* customcert_elements table.
*
* @param \stdClass $data the form data
* @return string the json encoded array
*/
public function save_unique_data($data) {
$arrtostore = [
'width' => !empty($data->width) ? (int)$data->width : 0,
'height' => !empty($data->height) ? (int)$data->height : 0
];
return json_encode($arrtostore);
}
/**
* Sets the data on the form when editing an element.
*
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
parent::definition_after_data($mform);
// Set the image, width, height and alpha channel for this element.
if (!empty($this->get_data())) {
$imageinfo = json_decode($this->get_data());
if (!empty($imageinfo->height)) {
$element = $mform->getElement('height');
$element->setValue($imageinfo->height);
}
}
}
/**
* Handles rendering the element on the pdf.
*
* @param \pdf $pdf the pdf object
* @param bool $preview true if it is a preview, false otherwise
* @param \stdClass $user the user we are rendering this for
*/
public function render($pdf, $preview, $user) {
global $DB;
// If there is no element data, we have nothing to display.
if (empty($this->get_data())) {
return;
}
$imageinfo = json_decode($this->get_data());
if ($preview) {
// Generate the URL to verify this.
$qrcodeurl = new \moodle_url('/');
$qrcodeurl = $qrcodeurl->out(false);
} else {
// Get the information we need.
$sql = "SELECT c.id, ct.contextid, ci.code
FROM {customcert_issues} ci
JOIN {customcert} c
ON ci.customcertid = c.id
JOIN {customcert_templates} ct
ON c.templateid = ct.id
JOIN {customcert_pages} cp
ON cp.templateid = ct.id
WHERE ci.userid = :userid
AND cp.id = :pageid";
// Now we can get the issue for this user.
$issue = $DB->get_record_sql($sql, array('userid' => $user->id, 'pageid' => $this->get_pageid()),
'*', MUST_EXIST);
$code = $issue->code;
// Generate the URL to verify this.
$qrcodeurl = new \moodle_url('/mod/customcert/verify_certificate.php',
[
'contextid' => $issue->contextid,
'code' => $code,
'qrcode' => 1
]
);
$qrcodeurl = $qrcodeurl->out(false);
}
$barcode = new \TCPDF2DBarcode($qrcodeurl, self::BARCODETYPE);
$image = $barcode->getBarcodePngData($imageinfo->width, $imageinfo->height);
$location = make_request_directory() . '/target';
file_put_contents($location, $image);
$pdf->Image($location, $this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height);
}
/**
* Render the element in html.
*
* This function is used to render the element when we are using the
* drag and drop interface to position it.
*
* @return string the html
*/
public function render_html() {
// If there is no element data, we have nothing to display.
if (empty($this->get_data())) {
return;
}
$imageinfo = json_decode($this->get_data());
$qrcodeurl = new \moodle_url('/');
$qrcodeurl = $qrcodeurl->out(false);
$barcode = new \TCPDF2DBarcode($qrcodeurl, self::BARCODETYPE);
return $barcode->getBarcodeHTML($imageinfo->width / 10, $imageinfo->height / 10);
}
}

View file

@ -0,0 +1,46 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for customcertelement_qrcode.
*
* @package customcertelement_qrcode
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace customcertelement_qrcode\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for customcertelement_qrcode implementing null_provider.
*
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}

View file

@ -0,0 +1,30 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* Strings for component 'customcertelement_qrcode', language 'en'.
*
* @package customcertelement_qrcode
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['height'] = 'Height';
$string['height_help'] = 'Height help';
$string['pluginname'] = 'QR code';
$string['privacy:metadata'] = 'The QR code plugin does not store any personal data.';
$string['width'] = 'Width';
$string['width_help'] = 'width help';

View file

@ -0,0 +1,29 @@
<?php
// This file is part of the customcert module for 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 <http://www.gnu.org/licenses/>.
/**
* This file contains the version information for the QR code plugin.
*
* @package customcertelement_qrcode
* @copyright 2019 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
$plugin->version = 2018051700; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2018051700; // Requires this Moodle version (3.5).
$plugin->component = 'customcertelement_qrcode';

View file

@ -38,7 +38,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('select', 'teacher', get_string('teacher', 'customcertelement_teachername'),
@ -102,6 +102,11 @@ class element extends \mod_customcert\element {
protected function get_list_of_teachers() {
global $PAGE;
// Return early if we are in a site template.
if ($PAGE->context->id == \context_system::instance()->id) {
return [];
}
// The list of teachers to return.
$teachers = array();
@ -118,7 +123,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
if (!empty($this->get_data())) {

View file

@ -38,7 +38,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('textarea', 'text', get_string('text', 'customcertelement_text'));
@ -67,9 +67,7 @@ class element extends \mod_customcert\element {
* @param \stdClass $user the user we are rendering this for
*/
public function render($pdf, $preview, $user) {
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$text = format_text($this->get_data(), FORMAT_HTML, ['context' => \context_course::instance($courseid)]);
\mod_customcert\element_helper::render_content($pdf, $this, $text);
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_text());
}
/**
@ -81,15 +79,13 @@ class element extends \mod_customcert\element {
* @return string the html
*/
public function render_html() {
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$text = format_text($this->get_data(), FORMAT_HTML, ['context' => \context_course::instance($courseid)]);
return \mod_customcert\element_helper::render_html_content($this, $text);
return \mod_customcert\element_helper::render_html_content($this, $this->get_text());
}
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
if (!empty($this->get_data())) {
@ -98,4 +94,14 @@ class element extends \mod_customcert\element {
}
parent::definition_after_data($mform);
}
/**
* Helper function that returns the text.
*
* @return string
*/
protected function get_text() : string {
$context = \mod_customcert\element_helper::get_context($this->get_id());
return format_text($this->get_data(), FORMAT_HTML, ['context' => $context]);
}
}

View file

@ -38,13 +38,14 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
// Get the user profile fields.
$userfields = array(
'firstname' => get_user_field_name('firstname'),
'lastname' => get_user_field_name('lastname'),
'username' => get_user_field_name('username'),
'email' => get_user_field_name('email'),
'city' => get_user_field_name('city'),
'country' => get_user_field_name('country'),
@ -65,7 +66,7 @@ class element extends \mod_customcert\element {
$arrcustomfields = \availability_profile\condition::get_custom_profile_fields();
$customfields = array();
foreach ($arrcustomfields as $key => $customfield) {
$customfields[$customfield->id] = $key;
$customfields[$customfield->id] = $customfield->name;
}
// Combine the two.
$fields = $userfields + $customfields;
@ -98,14 +99,56 @@ 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_user_field_value($user, $preview));
}
/**
* Render the element in html.
*
* This function is used to render the element when we are using the
* drag and drop interface to position it.
*/
public function render_html() {
global $USER;
return \mod_customcert\element_helper::render_html_content($this, $this->get_user_field_value($USER, true));
}
/**
* 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('userfield');
$element->setValue($this->get_data());
}
parent::definition_after_data($mform);
}
/**
* Helper function that returns the text.
*
* @param \stdClass $user the user we are rendering this for
* @param bool $preview Is this a preview?
* @return string
*/
protected function get_user_field_value(\stdClass $user, bool $preview) : string {
global $CFG, $DB;
// The user field to display.
$field = $this->get_data();
// The value to display on the PDF.
$value = '';
// The value to display - we always want to show a value here so it can be repositioned.
if ($preview) {
$value = $field;
} else {
$value = '';
}
if (is_number($field)) { // Must be a custom user profile field.
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
// Found the field name, let's update the value to display.
$value = $field->name;
$file = $CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php';
if (file_exists($file)) {
require_once($CFG->dirroot . '/user/profile/lib.php');
@ -119,59 +162,7 @@ class element extends \mod_customcert\element {
$value = $user->$field;
}
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$value = format_string($value, true, ['context' => \context_course::instance($courseid)]);
\mod_customcert\element_helper::render_content($pdf, $this, $value);
}
/**
* Render the element in html.
*
* This function is used to render the element when we are using the
* drag and drop interface to position it.
*/
public function render_html() {
global $CFG, $DB, $USER;
// The user field to display.
$field = $this->get_data();
// The value to display - we always want to show a value here so it can be repositioned.
$value = $field;
if (is_number($field)) { // Must be a custom user profile field.
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
// Found the field name, let's update the value to display.
$value = $field->name;
$file = $CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php';
if (file_exists($file)) {
require_once($CFG->dirroot . '/user/profile/lib.php');
require_once($file);
$class = "profile_field_{$field->datatype}";
$field = new $class($field->id, $USER->id);
if ($fieldvalue = $field->display_data()) {
// Ok, found a value for the user, let's show that instead.
$value = $fieldvalue;
}
}
}
} else if (!empty($USER->$field)) { // Field in the user table.
$value = $USER->$field;
}
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
$value = format_string($value, true, ['context' => \context_course::instance($courseid)]);
return \mod_customcert\element_helper::render_html_content($this, $value);
}
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
*/
public function definition_after_data($mform) {
if (!empty($this->get_data())) {
$element = $mform->getElement('userfield');
$element->setValue($this->get_data());
}
parent::definition_after_data($mform);
$context = \mod_customcert\element_helper::get_context($this->get_id());
return format_string($value, true, ['context' => $context]);
}
}

View file

@ -38,7 +38,7 @@ class element extends \mod_customcert\element {
/**
* This function renders the form elements when adding a customcert element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function render_form_elements($mform) {
$mform->addElement('text', 'width', get_string('width', 'customcertelement_userpicture'), array('size' => 10));
@ -190,7 +190,7 @@ class element extends \mod_customcert\element {
/**
* Sets the data on the form when editing an element.
*
* @param \mod_customcert\edit_element_form $mform the edit_form instance
* @param \MoodleQuickForm $mform the edit_form instance
*/
public function definition_after_data($mform) {
// Set the image, width and height for this element.

View file

@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['activity'] = 'Activity';
$string['addcertpage'] = 'Add page';
$string['addelement'] = 'Add element';
$string['awardedto'] = 'Awarded to';
@ -41,6 +42,7 @@ $string['customcert:manageemailothers'] = 'Manage email others setting';
$string['customcert:manageverifyany'] = 'Manage verification setting';
$string['customcert:managerequiredtime'] = 'Manage time required setting';
$string['customcert:manageprotection'] = 'Manage protection setting';
$string['customcert:receiveissue'] = 'Receive a certificate';
$string['customcert:view'] = 'View a custom certificate';
$string['customcert:viewreport'] = 'View course report';
$string['customcert:viewallcertificates'] = 'View all certificates';
@ -82,11 +84,12 @@ $string['emailstudentcertificatelinktext'] = 'View certificate';
$string['emailstudentgreeting'] = 'Dear {$a}';
$string['emailstudentsubject'] = '{$a->coursefullname}: {$a->certificatename}';
$string['emailstudents'] = 'Email students';
$string['emailstudents_help'] = 'If set this will email the students a copy of the certificate when it becomes available.';
$string['emailstudents_help'] = 'If set this will email the students a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this to \'Yes\' before you have finished creating the certificate will email the student an incomplete certificate.';
$string['emailteachers'] = 'Email teachers';
$string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available.';
$string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this to \'Yes\' before you have finished creating the certificate will email the teacher an incomplete certificate.';
$string['emailothers'] = 'Email others';
$string['emailothers_help'] = 'If set this will email the email addresses listed here (separated by a comma) with a copy of the certificate when it becomes available.';
$string['emailothers_help'] = 'If set this will email the email addresses listed here (separated by a comma) with a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this field before you have finished creating the certificate will email the addresses an incomplete certificate.';
$string['exampledatawarning'] = 'Some of these values may just be an example to ensure positioning of the elements is possible.';
$string['font'] = 'Font';
$string['font_help'] = 'The font used when generating this element.';
$string['fontcolour'] = 'Colour';
@ -94,6 +97,7 @@ $string['fontcolour_help'] = 'The colour of the font.';
$string['fontsize'] = 'Size';
$string['fontsize_help'] = 'The size of the font in points.';
$string['getcustomcert'] = 'View certificate';
$string['gradeoutcome'] = 'Outcome';
$string['height'] = 'Height';
$string['height_help'] = 'This is the height of the certificate PDF in mm. For reference an A4 piece of paper is 297mm high and a letter is 279mm high.';
$string['invalidcode'] = 'Invalid code supplied.';
@ -106,7 +110,7 @@ $string['invalidwidth'] = 'The width has to be a valid number greater than 0.';
$string['landscape'] = 'Landscape';
$string['leftmargin'] = 'Left margin';
$string['leftmargin_help'] = 'This is the left margin of the certificate PDF in mm.';
$string['listofissues'] = 'Recipients';
$string['listofissues'] = 'Recipients: {$a}';
$string['load'] = 'Load';
$string['loadtemplate'] = 'Load template';
$string['loadtemplatemsg'] = 'Are you sure you wish to load this template? This will remove any existing pages and elements for this certificate.';

View file

@ -34,6 +34,7 @@ define('NO_MOODLE_COOKIES', true);
require_once('../../../config.php');
require_once($CFG->libdir . '/filelib.php');
require_once($CFG->libdir . '/completionlib.php');
require_once($CFG->dirroot . '/webservice/lib.php');
// Allow CORS requests.
@ -54,6 +55,7 @@ if (empty($enabledfiledownload)) {
}
$cm = get_coursemodule_from_instance('customcert', $certificateid, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST);
$template = $DB->get_record('customcert_templates', ['id' => $certificate->templateid], '*', MUST_EXIST);
@ -80,6 +82,10 @@ if (!$issue) {
}
\mod_customcert\certificate::issue_certificate($certificate->id, $USER->id);
// Set the custom certificate as viewed.
$completion = new completion_info($course);
$completion->set_module_viewed($cm);
}
// Now we want to generate the PDF.

View file

@ -30,6 +30,11 @@ $downloadcert = optional_param('downloadcert', '', PARAM_BOOL);
if ($downloadcert) {
$certificateid = required_param('certificateid', PARAM_INT);
$customcert = $DB->get_record('customcert', array('id' => $certificateid), '*', MUST_EXIST);
// Check there exists an issued certificate for this user.
if (!$issue = $DB->get_record('customcert_issues', ['userid' => $userid, 'customcertid' => $customcert->id])) {
throw new moodle_exception('You have not been issued a certificate');
}
}
$page = optional_param('page', 0, PARAM_INT);
$perpage = optional_param('perpage', \mod_customcert\certificate::CUSTOMCERT_PER_PAGE, PARAM_INT);

View file

@ -125,7 +125,8 @@ $html .= html_writer::end_tag('div');
echo $OUTPUT->header();
echo $OUTPUT->heading($heading);
echo $OUTPUT->heading(get_string('rearrangeelementsheading', 'customcert'), 4);
echo $OUTPUT->heading(get_string('rearrangeelementsheading', 'customcert'), 3);
echo $OUTPUT->notification(get_string('exampledatawarning', 'customcert'), \core\output\notification::NOTIFY_WARNING);
echo $html;
$PAGE->requires->js_call_amd('mod_customcert/rearrange-area', 'init', array('#pdf'));
echo $OUTPUT->footer();

View file

@ -119,6 +119,42 @@ Feature: Being able to manage elements in a certificate template
| Width | 20 |
| Reference point location | Top left |
And I press "Save changes"
# Date range.
And I add the element "Date range" to page "1" of the "Custom certificate 1" certificate template
And I set the following fields to these values:
| Date item | Course start date |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Fallback string | {{range_first_year}} |
| id_startdate_0_day | 24 |
| id_startdate_0_month | October |
| id_startdate_0_year | 2015 |
| id_enddate_0_day | 21 |
| id_enddate_0_month | March |
| id_enddate_0_year | 2016 |
| String | Oct to March |
And I press "Save changes"
And I should see "Date range" in the "elementstable" "table"
And I click on ".edit-icon" "css_element" in the "Date range" "table_row"
And the following fields match these values:
| Date item | Course start date |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Fallback string | {{range_first_year}} |
| id_startdate_0_day | 24 |
| id_startdate_0_month | October |
| id_startdate_0_year | 2015 |
| id_enddate_0_day | 21 |
| id_enddate_0_month | March |
| id_enddate_0_year | 2016 |
| String | Oct to March |
And I press "Save changes"
# Digital signature.
And I add the element "Digital signature" to page "1" of the "Custom certificate 1" certificate template
And I set the following fields to these values:
@ -144,44 +180,44 @@ Feature: Being able to manage elements in a certificate template
# Grade.
And I add the element "Grade" to page "1" of the "Custom certificate 1" certificate template
And I set the following fields to these values:
| Grade item | Topic 0 : Assignment 1 |
| Grade format | Percentage |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Grade item | Activity : Assignment 1 |
| Grade format | Percentage |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
And I press "Save changes"
And I should see "Grade" in the "elementstable" "table"
And I click on ".edit-icon" "css_element" in the "Grade" "table_row"
And the following fields match these values:
| Grade item | Topic 0 : Assignment 1 |
| Grade format | Percentage |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Grade item | Activity : Assignment 1 |
| Grade format | Percentage |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
And I press "Save changes"
# Grade item name.
And I add the element "Grade item name" to page "1" of the "Custom certificate 1" certificate template
And I set the following fields to these values:
| Grade item | Topic 0 : Assignment 2 |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Grade item | Activity : Assignment 2 |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
And I press "Save changes"
And I should see "Grade item name" in the "elementstable" "table"
And I click on ".edit-icon" "css_element" in the "Grade item name" "table_row"
And the following fields match these values:
| Grade item | Topic 0 : Assignment 2 |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
| Grade item | Activity : Assignment 2 |
| Font | Helvetica |
| Size | 20 |
| Colour | #045ECD |
| Width | 20 |
| Reference point location | Top left |
And I press "Save changes"
# Image.
And I add the element "Image" to page "1" of the "Custom certificate 1" certificate template
@ -287,6 +323,18 @@ Feature: Being able to manage elements in a certificate template
| Width | 10 |
| Height | 10 |
And I press "Save changes"
# QR Code.
And I add the element "QR code" to page "1" of the "Custom certificate 1" certificate template
And I set the following fields to these values:
| Width | 25 |
| Height | 15 |
And I press "Save changes"
And I should see "QR code" in the "elementstable" "table"
And I click on ".edit-icon" "css_element" in the "QR code" "table_row"
And the following fields match these values:
| Width | 25 |
| Height | 15 |
And I press "Save changes"
# Just to test there are no exceptions being thrown.
And I follow "Reposition elements"
And I press "Save and close"

View file

@ -101,6 +101,64 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
$this->assertEquals($SITE->id, \mod_customcert\element_helper::get_courseid($element->id));
}
/**
* Tests we are returning the correct course module id for an element in a course customcert activity.
*/
public function test_get_context_element_in_course_certificate() {
global $DB;
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a custom certificate in the course.
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
// Get the template to add elements to.
$template = $DB->get_record('customcert_templates', array('contextid' => context_module::instance($customcert->cmid)->id));
$template = new \mod_customcert\template($template);
// Add a page to the template.
$pageid = $template->add_page();
// Add an element to this page.
$element = new \stdClass();
$element->name = 'Test element';
$element->element = 'testelement';
$element->pageid = $pageid;
$element->sequence = \mod_customcert\element_helper::get_element_sequence($element->pageid);
$element->timecreated = time();
$element->id = $DB->insert_record('customcert_elements', $element);
// Confirm the correct course module id is returned.
$this->assertEquals(context_module::instance($customcert->cmid),
\mod_customcert\element_helper::get_context($element->id));
}
/**
* Tests we are returning the correct course module id for an element in a site template.
*/
public function test_get_context_element_in_site_template() {
global $DB;
// Add a template to the site.
$template = \mod_customcert\template::create('Site template', context_system::instance()->id);
// Add a page to the template.
$pageid = $template->add_page();
// Add an element to this page.
$element = new \stdClass();
$element->name = 'Test element';
$element->element = 'testelement';
$element->pageid = $pageid;
$element->sequence = \mod_customcert\element_helper::get_element_sequence($element->pageid);
$element->timecreated = time();
$element->id = $DB->insert_record('customcert_elements', $element);
// Confirm the correct course module id is returned.
$this->assertEquals(context_system::instance(), \mod_customcert\element_helper::get_context($element->id));
}
/**
* Test we return the correct grade items in a course.
*/
@ -122,28 +180,36 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
$gc = $this->getDataGenerator()->create_grade_category(['courseid' => $course->id]);
$gc = $DB->get_record('grade_items', ['itemtype' => 'category', 'iteminstance' => $gc->id]);
// Create an item attached to an outcome.
$outcome = $this->getDataGenerator()->create_grade_outcome(['courseid' => $course->id, 'shortname' => 'outcome']);
$go = $this->getDataGenerator()->create_grade_item(
[
'courseid' => $course->id,
'outcomeid' => $outcome->id
]
);
// Confirm the function returns the correct number of grade items.
$gradeitems = \mod_customcert\element_helper::get_grade_items($course);
$this->assertCount(5, $gradeitems);
$this->assertCount(6, $gradeitems);
$this->assertArrayHasKey($assign1->cmid, $gradeitems);
$this->assertArrayHasKey($assign2->cmid, $gradeitems);
$this->assertArrayHasKey($assign3->cmid, $gradeitems);
$this->assertArrayHasKey('gradeitem:' . $gi->id, $gradeitems);
$this->assertArrayHasKey('gradeitem:' . $gc->id, $gradeitems);
$this->assertArrayHasKey('gradeitem:' . $go->id, $gradeitems);
}
/**
* Test we return the correct grade information for an activity.
*/
public function test_get_mod_grade_info() {
global $CFG;
// Set that we want 3 decimals to display.
$CFG->grade_decimalpoints = 3;
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Set that we want 3 decimals to display.
grade_set_setting($course->id, 'decimalpoints', 3);
// Create two users.
$student1 = $this->getDataGenerator()->create_user();
$student2 = $this->getDataGenerator()->create_user();
@ -199,23 +265,20 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
$this->assertEquals(null, $grade->get_grade());
$this->assertEquals('-', $grade->get_displaygrade());
$this->assertEquals(null, $grade->get_dategraded());
grade_get_setting($course->id, null, null, true);
}
/**
* Test we return the correct grade information for a course.
*/
public function test_get_course_grade_info() {
global $CFG;
// Including to use constant.
require_once($CFG->dirroot . '/mod/customcert/element/grade/classes/element.php');
// Set that we want 3 decimals to display.
$CFG->grade_decimalpoints = 3;
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Set that we want 3 decimals to display.
grade_set_setting($course->id, 'decimalpoints', 3);
// Create two users.
$student1 = $this->getDataGenerator()->create_user();
$student2 = $this->getDataGenerator()->create_user();
@ -262,20 +325,20 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
$this->assertEquals(null, $grade->get_grade());
$this->assertEquals('-', $grade->get_displaygrade());
$this->assertEquals(null, $grade->get_dategraded());
grade_get_setting($course->id, null, null, true);
}
/**
* Test we return the correct grade information for a grade item.
*/
public function test_get_grade_item_info() {
global $CFG;
// Set that we want 3 decimals to display.
$CFG->grade_decimalpoints = 3;
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Set that we want 3 decimals to display.
grade_set_setting($course->id, 'decimalpoints', 3);
// Create two users.
$student1 = $this->getDataGenerator()->create_user();
$student2 = $this->getDataGenerator()->create_user();
@ -324,5 +387,7 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
$this->assertEquals(null, $grade->get_grade());
$this->assertEquals('-', $grade->get_displaygrade());
$this->assertEquals(null, $grade->get_dategraded());
grade_get_setting($course->id, null, null, true);
}
}

View file

@ -25,8 +25,6 @@
defined('MOODLE_INTERNAL') || die();
global $CFG;
/**
* Unit tests for the email certificate task.
*
@ -44,6 +42,81 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$this->resetAfterTest();
}
/**
* Tests the email certificate task when there are no elements.
*/
public function test_email_certificates_no_elements() {
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create a user.
$user1 = $this->getDataGenerator()->create_user();
// Create a custom certificate with no elements.
$this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
// Enrol the user as a student
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
// Run the task.
$sink = $this->redirectEmails();
$task = new \mod_customcert\task\email_certificate_task();
$task->execute();
$emails = $sink->get_messages();
// Confirm that we did not send any emails because the certificate has no elements.
$this->assertCount(0, $emails);
}
/**
* Tests the email certificate task for users without a capability to receive a certificate.
*/
public function test_email_certificates_no_cap() {
global $DB;
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Create some users.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
// Enrol two of them in the course as students but revoke their right to receive a certificate issue.
$roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
unassign_capability('mod/customcert:receiveissue', $roleids['student']);
// Create a custom certificate.
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Run the task.
$sink = $this->redirectEmails();
$task = new \mod_customcert\task\email_certificate_task();
$task->execute();
$emails = $sink->get_messages();
// Confirm that we did not send any emails.
$this->assertCount(0, $emails);
}
/**
* Tests the email certificate task for students.
*/
@ -70,6 +143,22 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
'emailstudents' => 1));
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Ok, now issue this to one user.
\mod_customcert\certificate::issue_certificate($customcert->id, $user1->id);
@ -95,11 +184,9 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
// Confirm that we sent out emails to the two users.
$this->assertCount(2, $emails);
$this->assertContains(fullname($user3), $emails[0]->header);
$this->assertEquals($CFG->noreplyaddress, $emails[0]->from);
$this->assertEquals($user1->email, $emails[0]->to);
$this->assertContains(fullname($user3), $emails[1]->header);
$this->assertEquals($CFG->noreplyaddress, $emails[1]->from);
$this->assertEquals($user2->email, $emails[1]->to);
@ -138,9 +225,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$this->getDataGenerator()->enrol_user($user3->id, $course->id, $roleids['editingteacher']);
// Create a custom certificate.
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
'emailteachers' => 1));
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Run the task.
$sink = $this->redirectEmails();
$task = new \mod_customcert\task\email_certificate_task();
@ -150,11 +253,9 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
// Confirm that we only sent out 2 emails, both emails to the teacher for the two students.
$this->assertCount(2, $emails);
$this->assertContains(fullname($user3), utf8_encode($emails[0]->header));
$this->assertEquals($CFG->noreplyaddress, $emails[0]->from);
$this->assertEquals($user3->email, $emails[0]->to);
$this->assertContains(fullname($user3), utf8_encode($emails[1]->header));
$this->assertEquals($CFG->noreplyaddress, $emails[1]->from);
$this->assertEquals($user3->email, $emails[1]->to);
}
@ -163,7 +264,7 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
* Tests the email certificate task for others.
*/
public function test_email_certificates_others() {
global $CFG;
global $CFG, $DB;
// Create a course.
$course = $this->getDataGenerator()->create_course();
@ -177,9 +278,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
// Create a custom certificate.
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
'emailothers' => 'testcustomcert@example.com, doo@dah'));
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Run the task.
$sink = $this->redirectEmails();
$task = new \mod_customcert\task\email_certificate_task();
@ -189,11 +306,9 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
// Confirm that we only sent out 2 emails, both emails to the other address that was valid for the two students.
$this->assertCount(2, $emails);
$this->assertContains(fullname(get_admin()), utf8_encode($emails[0]->header));
$this->assertEquals($CFG->noreplyaddress, $emails[0]->from);
$this->assertEquals('testcustomcert@example.com', $emails[0]->to);
$this->assertContains(fullname(get_admin()), utf8_encode($emails[1]->header));
$this->assertEquals($CFG->noreplyaddress, $emails[1]->from);
$this->assertEquals('testcustomcert@example.com', $emails[1]->to);
}
@ -215,7 +330,23 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
// Create a custom certificate.
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1));
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Remove the permission for the user to view the certificate.
assign_capability('mod/customcert:view', CAP_PROHIBIT, $roleids['student'], \context_course::instance($course->id));
@ -253,9 +384,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
// Create a custom certificate.
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1,
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1,
'requiredtime' => '60'));
// Create template object.
$template = new stdClass();
$template->id = $customcert->templateid;
$template->name = 'A template';
$template->contextid = context_course::instance($course->id)->id;
$template = new \mod_customcert\template($template);
// Add a page to this template.
$pageid = $template->add_page();
// Add an element to the page.
$element = new stdClass();
$element->pageid = $pageid;
$element->name = 'Image';
$DB->insert_record('customcert_elements', $element);
// Run the task.
$sink = $this->redirectEmails();
$task = new \mod_customcert\task\email_certificate_task();

View file

@ -28,6 +28,7 @@ require_once('../../config.php');
$contextid = optional_param('contextid', context_system::instance()->id, PARAM_INT);
$code = optional_param('code', '', PARAM_ALPHANUM); // The code for the certificate we are verifying.
$qrcode = optional_param('qrcode', false, PARAM_BOOL);
$context = context::instance_by_id($contextid);
@ -87,7 +88,7 @@ if ($checkallofsite) {
// The form we are using to verify these codes.
$form = new \mod_customcert\verify_certificate_form($pageurl);
if ($form->get_data()) {
if ($code) {
$result = new stdClass();
$result->issues = array();
@ -128,7 +129,10 @@ if ($form->get_data()) {
echo $OUTPUT->header();
echo $OUTPUT->heading($heading);
echo $form->display();
// Don't show the form if we are coming from a QR code.
if (!$qrcode) {
echo $form->display();
}
if (isset($result)) {
$renderer = $PAGE->get_renderer('mod_customcert');
$result = new \mod_customcert\output\verify_certificate_results($result);

View file

@ -24,10 +24,10 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
$plugin->version = 2018051706; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2018051710; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2018051700; // Requires this Moodle version (3.5).
$plugin->cron = 0; // Period for cron to check this module (secs).
$plugin->component = 'mod_customcert';
$plugin->maturity = MATURITY_STABLE;
$plugin->release = "3.5.5"; // User-friendly version number.
$plugin->release = "3.5.9"; // User-friendly version number.

View file

@ -43,6 +43,7 @@ require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/customcert:view', $context);
$canreceive = has_capability('mod/customcert:receiveissue', $context);
$canmanage = has_capability('mod/customcert:manage', $context);
$canviewreport = has_capability('mod/customcert:viewreport', $context);
@ -134,10 +135,14 @@ if (!$downloadown && !$downloadissue) {
}
// Create the button to download the customcert.
$linkname = get_string('getcustomcert', 'customcert');
$link = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id, 'downloadown' => true));
$downloadbutton = new single_button($link, $linkname, 'post', true);
$downloadbutton = $OUTPUT->render($downloadbutton);
$downloadbutton = '';
if ($canreceive) {
$linkname = get_string('getcustomcert', 'customcert');
$link = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id, 'downloadown' => true));
$downloadbutton = new single_button($link, $linkname, 'get', true);
$downloadbutton->class .= ' m-b-1'; // Seems a bit hackish, ahem.
$downloadbutton = $OUTPUT->render($downloadbutton);
}
// Output all the page data.
echo $OUTPUT->header();
@ -146,13 +151,14 @@ if (!$downloadown && !$downloadissue) {
echo $issuehtml;
echo $downloadbutton;
if (isset($reporttable)) {
echo $OUTPUT->heading(get_string('listofissues', 'customcert'), 3);
$numissues = \mod_customcert\certificate::get_number_of_issues($customcert->id, $cm, $groupmode);
echo $OUTPUT->heading(get_string('listofissues', 'customcert', $numissues), 3);
groups_print_activity_menu($cm, $pageurl);
echo $reporttable->out($perpage, false);
}
echo $OUTPUT->footer($course);
exit();
} else { // Output to pdf.
} else if ($canreceive) { // Output to pdf.
// Set the userid value of who we are downloading the certificate for.
$userid = $USER->id;
if ($downloadown) {
@ -173,6 +179,8 @@ if (!$downloadown && !$downloadissue) {
redirect(new moodle_url('/mod/customcert/view.php', array('id' => $cm->id)));
}
\core\session\manager::write_close();
// Now we want to generate the PDF.
$template = new \mod_customcert\template($template);
$template->generate_pdf(false, $userid);

View file

@ -80,24 +80,14 @@ Y.extend(Rearrange, Y.Base, {
this.elements = params[2];
// Set the PDF dimensions.
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
this.setPdfDimensions();
// Set the boundaries.
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
this.setBoundaries();
this.setpositions();
this.createevents();
window.addEventListener("resize", this.checkWindownResize.bind(this));
},
/**
@ -130,6 +120,40 @@ Y.extend(Rearrange, Y.Base, {
}
},
/**
* Sets the PDF dimensions.
*/
setPdfDimensions: function() {
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
},
/**
* Sets the boundaries.
*/
setBoundaries: function() {
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
},
/**
* Check browser resize and reset position.
*/
checkWindownResize: function() {
this.setPdfDimensions();
this.setBoundaries();
this.setpositions();
},
/**
* Creates the JS events for changing element positions.
*/

View file

@ -1 +1 @@
YUI.add("moodle-mod_customcert-rearrange",function(e,t){var n=function(){n.superclass.constructor.apply(this,[arguments])};e.extend(n,e.Base,{templateid:0,page:[],elements:[],pdfx:0,pdfy:0,pdfwidth:0,pdfheight:0,elementxy:0,pdfleftboundary:0,pdfrightboundary:0,pixelsinmm:3.779527559055,initializer:function(t){this.templateid=t[0],this.page=t[1],this.elements=t[2],this.pdfx=e.one("#pdf").getX(),this.pdfy=e.one("#pdf").getY(),this.pdfwidth=parseFloat(e.one("#pdf").getComputedStyle("width")),this.pdfheight=parseFloat(e.one("#pdf").getComputedStyle("height")),this.pdfleftboundary=this.pdfx,this.page.leftmargin&&(this.pdfleftboundary+=parseInt(this.page.leftmargin*this.pixelsinmm,10)),this.pdfrightboundary=this.pdfx+this.pdfwidth,this.page.rightmargin&&(this.pdfrightboundary-=parseInt(this.page.rightmargin*this.pixelsinmm,10)),this.setpositions(),this.createevents()},setpositions:function(){for(var t in this.elements){var n=this.elements[t],r=this.pdfx+n.posx*this.pixelsinmm,i=this.pdfy+n.posy*this.pixelsinmm,s=parseFloat(e.one("#element-"+n.id).getComputedStyle("width")),o=n.width*this.pixelsinmm;o&&s>o&&(s=o);switch(n.refpoint){case"1":r-=s/2;break;case"2":r=r-s+2}e.one("#element-"+n.id).setX(r),e.one("#element-"+n.id).setY(i)}},createevents:function(){e.one(".savepositionsbtn [type=submit]").on("click",function(e){this.savepositions(e)},this),e.one(".applypositionsbtn [type=submit]").on("click",function(e){this.savepositions(e),e.preventDefault()},this);var t=new e.DD.Delegate({container:"#pdf",nodes:".element"});t.on("drag:start",function(){var e=t.get("currentNode");this.elementxy=e.getXY()},this),t.on("drag:end",function(){var e=t.get("currentNode");this.isoutofbounds(e)&&e.setXY(this.elementxy)},this)},isoutofbounds:function(e){var t=parseFloat(e.getComputedStyle("width")),n=parseFloat(e.getComputedStyle("height")),r=e.getX(),i=r+t,s=e.getY(),o=s+n;return r<this.pdfleftboundary||i>this.pdfrightboundary?!0:s<this.pdfy||o>this.pdfy+this.pdfheight?!0:!1},savepositions:function(t){var n={tid:this.templateid,values:[]};for(var r in this.elements){var i=this.elements[r],s=e.one("#element-"+i.id),o=s.getX()-this.pdfx,u=s.getY()-this.pdfy,a=s.getData("refpoint"),f=parseFloat(s.getComputedStyle("width"));switch(a){case"1":o+=f/2;break;case"2":o+=f}n.values.push({id:i.id,posx:Math.round(parseFloat(o/this.pixelsinmm)),posy:Math.round(parseFloat(u/this.pixelsinmm))})}n.values=JSON.stringify(n.values),e.io(M.cfg.wwwroot+"/mod/customcert/ajax.php",{method:"POST",data:n,on:{failure:function(e,t){this.ajaxfailure(t)},success:function(){var e=t.currentTarget.ancestor("form",!0),n=e.getAttribute("action"),r=e.one("[name=pid]");if(r){var i=r.get("value");window.location=n+"?pid="+i}else{var s=e.one("[name=tid]").get("value");window.location=n+"?tid="+s}}},context:this}),t.preventDefault()},ajaxfailure:function(e){var t={name:e.status+" "+e.statusText,message:e.responseText};return new M.core.exception(t)}}),e.namespace("M.mod_customcert.rearrange").init=function(e,t,r){new n(e,t,r)}},"@VERSION@",{requires:["dd-delegate","dd-drag"]});
YUI.add("moodle-mod_customcert-rearrange",function(e,t){var n=function(){n.superclass.constructor.apply(this,[arguments])};e.extend(n,e.Base,{templateid:0,page:[],elements:[],pdfx:0,pdfy:0,pdfwidth:0,pdfheight:0,elementxy:0,pdfleftboundary:0,pdfrightboundary:0,pixelsinmm:3.779527559055,initializer:function(e){this.templateid=e[0],this.page=e[1],this.elements=e[2],this.setPdfDimensions(),this.setBoundaries(),this.setpositions(),this.createevents(),window.addEventListener("resize",this.checkWindownResize.bind(this))},setpositions:function(){for(var t in this.elements){var n=this.elements[t],r=this.pdfx+n.posx*this.pixelsinmm,i=this.pdfy+n.posy*this.pixelsinmm,s=parseFloat(e.one("#element-"+n.id).getComputedStyle("width")),o=n.width*this.pixelsinmm;o&&s>o&&(s=o);switch(n.refpoint){case"1":r-=s/2;break;case"2":r=r-s+2}e.one("#element-"+n.id).setX(r),e.one("#element-"+n.id).setY(i)}},setPdfDimensions:function(){this.pdfx=e.one("#pdf").getX(),this.pdfy=e.one("#pdf").getY(),this.pdfwidth=parseFloat(e.one("#pdf").getComputedStyle("width")),this.pdfheight=parseFloat(e.one("#pdf").getComputedStyle("height"))},setBoundaries:function(){this.pdfleftboundary=this.pdfx,this.page.leftmargin&&(this.pdfleftboundary+=parseInt(this.page.leftmargin*this.pixelsinmm,10)),this.pdfrightboundary=this.pdfx+this.pdfwidth,this.page.rightmargin&&(this.pdfrightboundary-=parseInt(this.page.rightmargin*this.pixelsinmm,10))},checkWindownResize:function(){this.setPdfDimensions(),this.setBoundaries(),this.setpositions()},createevents:function(){e.one(".savepositionsbtn [type=submit]").on("click",function(e){this.savepositions(e)},this),e.one(".applypositionsbtn [type=submit]").on("click",function(e){this.savepositions(e),e.preventDefault()},this);var t=new e.DD.Delegate({container:"#pdf",nodes:".element"});t.on("drag:start",function(){var e=t.get("currentNode");this.elementxy=e.getXY()},this),t.on("drag:end",function(){var e=t.get("currentNode");this.isoutofbounds(e)&&e.setXY(this.elementxy)},this)},isoutofbounds:function(e){var t=parseFloat(e.getComputedStyle("width")),n=parseFloat(e.getComputedStyle("height")),r=e.getX(),i=r+t,s=e.getY(),o=s+n;return r<this.pdfleftboundary||i>this.pdfrightboundary?!0:s<this.pdfy||o>this.pdfy+this.pdfheight?!0:!1},savepositions:function(t){var n={tid:this.templateid,values:[]};for(var r in this.elements){var i=this.elements[r],s=e.one("#element-"+i.id),o=s.getX()-this.pdfx,u=s.getY()-this.pdfy,a=s.getData("refpoint"),f=parseFloat(s.getComputedStyle("width"));switch(a){case"1":o+=f/2;break;case"2":o+=f}n.values.push({id:i.id,posx:Math.round(parseFloat(o/this.pixelsinmm)),posy:Math.round(parseFloat(u/this.pixelsinmm))})}n.values=JSON.stringify(n.values),e.io(M.cfg.wwwroot+"/mod/customcert/ajax.php",{method:"POST",data:n,on:{failure:function(e,t){this.ajaxfailure(t)},success:function(){var e=t.currentTarget.ancestor("form",!0),n=e.getAttribute("action"),r=e.one("[name=pid]");if(r){var i=r.get("value");window.location=n+"?pid="+i}else{var s=e.one("[name=tid]").get("value");window.location=n+"?tid="+s}}},context:this}),t.preventDefault()},ajaxfailure:function(e){var t={name:e.status+" "+e.statusText,message:e.responseText};return new M.core.exception(t)}}),e.namespace("M.mod_customcert.rearrange").init=function(e,t,r){new n(e,t,r)}},"@VERSION@",{requires:["dd-delegate","dd-drag"]});

View file

@ -80,24 +80,14 @@ Y.extend(Rearrange, Y.Base, {
this.elements = params[2];
// Set the PDF dimensions.
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
this.setPdfDimensions();
// Set the boundaries.
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
this.setBoundaries();
this.setpositions();
this.createevents();
window.addEventListener("resize", this.checkWindownResize.bind(this));
},
/**
@ -130,6 +120,40 @@ Y.extend(Rearrange, Y.Base, {
}
},
/**
* Sets the PDF dimensions.
*/
setPdfDimensions: function() {
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
},
/**
* Sets the boundaries.
*/
setBoundaries: function() {
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
},
/**
* Check browser resize and reset position.
*/
checkWindownResize: function() {
this.setPdfDimensions();
this.setBoundaries();
this.setpositions();
},
/**
* Creates the JS events for changing element positions.
*/

View file

@ -78,24 +78,14 @@ Y.extend(Rearrange, Y.Base, {
this.elements = params[2];
// Set the PDF dimensions.
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
this.setPdfDimensions();
// Set the boundaries.
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
this.setBoundaries();
this.setpositions();
this.createevents();
window.addEventListener("resize", this.checkWindownResize.bind(this));
},
/**
@ -128,6 +118,40 @@ Y.extend(Rearrange, Y.Base, {
}
},
/**
* Sets the PDF dimensions.
*/
setPdfDimensions: function() {
this.pdfx = Y.one('#pdf').getX();
this.pdfy = Y.one('#pdf').getY();
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
},
/**
* Sets the boundaries.
*/
setBoundaries: function() {
this.pdfleftboundary = this.pdfx;
if (this.page.leftmargin) {
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
}
this.pdfrightboundary = this.pdfx + this.pdfwidth;
if (this.page.rightmargin) {
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
}
},
/**
* Check browser resize and reset position.
*/
checkWindownResize: function() {
this.setPdfDimensions();
this.setBoundaries();
this.setpositions();
},
/**
* Creates the JS events for changing element positions.
*/