diff --git a/.travis.yml b/.travis.yml
index 35aa3c88e..1086084d2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,8 +9,8 @@ cache:
- $HOME/.npm
php:
- - 5.6
- - 7.1
+ - 7.0
+ - 7.2
addons:
firefox: 47.0.1
@@ -22,7 +22,7 @@ addons:
env:
global:
- - MOODLE_BRANCH=MOODLE_33_STABLE
+ - MOODLE_BRANCH=MOODLE_34_STABLE
- IGNORE_NAMES=mobile_*.mustache # Mobile mustache has specific syntax, ignore their templates
matrix:
- DB=pgsql
diff --git a/CHANGES.md b/CHANGES.md
index 79d2f5fe6..26e1171b9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,13 +4,7 @@ All notable changes to this project will be documented in this file.
Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/markn86/moodle-mod_customcert/issues/169.
-## [3.3.17] - 2019-02-04
-
-### Fixed
-
-- Fixed invalid syntax for PHP 5.6 as it is still supported in 3.3.
-
-## [3.3.16] - 2019-02-04
+## [3.4.7] - 2018-12-31
### Changed
@@ -18,12 +12,14 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
### 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.3.15] - 2018-12-20
+## [3.4.6] - 2018-12-20
### Added
+- GDPR: Add support for removal of users from a context (see MDL-62560) (#252).
- Images can be made transparent (#186).
- Set default values of activity instance settings (#180).
- Allow element plugins to control if they can be added to a certificate (#225).
@@ -46,7 +42,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
- Removed incorrect course reset logic (#223).
- Description strings referring to the wrong setting (#254).
-## [3.3.14] - 2018-07-13
+## [3.4.5] - 2018-07-13
### Fixed
- Use custom fonts if present (#211).
@@ -61,7 +57,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
- One big change here is combining the report and activity view page into one.
- Allow short dates with leading zeros (#210).
-## [3.3.13] - 2018-06-26
+## [3.4.4] - 2018-06-26
### Fixed
- Respect filters in the 'My certificates' and 'Verify certificate' pages (#197).
@@ -72,12 +68,12 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
- Multiple UX improvements to both the browser and mobile views (#203).
-## [3.3.12] - 2018-06-07
+## [3.4.3] - 2018-06-07
### Fixed
- Hotfix to prevent misalignment of 'text' elements after last release (#196).
-## [3.3.11] - 2018-06-06
+## [3.4.2] - 2018-06-06
### Added
- Mobile app support (#70).
```
@@ -109,7 +105,7 @@ Note - All hash comments refer to the issue number. Eg. #169 refers to https://g
- No longer display the 'action' column and user picture URL when downloading the user report (#192).
- Elements no longer ignore filters (#170).
-## [3.3.10] - 2018-05-17
+## [3.4.1] - 2018-05-17
### Added
- GDPR Compliance (#189).
diff --git a/classes/element_helper.php b/classes/element_helper.php
index 2a1cffa56..153dae0c2 100644
--- a/classes/element_helper.php
+++ b/classes/element_helper.php
@@ -389,7 +389,7 @@ public static function get_courseid($elementid) {
* @param int $elementid The element id
* @return \context The context
*/
- public static function get_context($elementid) {
+ public static function get_context(int $elementid) : \context {
global $DB;
$sql = "SELECT ct.contextid
diff --git a/classes/output/mobile.php b/classes/output/mobile.php
index 44264ec4d..5e480c731 100644
--- a/classes/output/mobile.php
+++ b/classes/output/mobile.php
@@ -202,7 +202,7 @@ private static function update_active_group($groupmode, $groupid, $allowedgroups
* @param \context $context
* @param string $cap
*/
- protected static function require_capability(\stdClass $cm, \context $context, $cap) {
+ protected static function require_capability(\stdClass $cm, \context $context, string $cap) {
require_login($cm->course, false, $cm, true, true);
require_capability($cap, $context);
}
diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php
index 406447425..29bebc63c 100644
--- a/classes/privacy/provider.php
+++ b/classes/privacy/provider.php
@@ -25,9 +25,11 @@
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\helper;
use core_privacy\local\request\transform;
+use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
@@ -40,7 +42,8 @@
*/
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.
@@ -48,7 +51,7 @@ class provider implements
* @param collection $items a reference to the collection to use to store the metadata.
* @return collection the updated collection of metadata items.
*/
- public static function get_metadata(collection $items) {
+ public static function get_metadata(collection $items) : collection {
$items->add_database_table(
'customcert_issues',
[
@@ -70,7 +73,7 @@ public static function get_metadata(collection $items) {
* @param int $userid the userid.
* @return contextlist the list of contexts containing user info for the user.
*/
- public static function get_contexts_for_userid($userid) {
+ public static function get_contexts_for_userid(int $userid) : contextlist {
$sql = "SELECT c.id
FROM {context} c
INNER JOIN {course_modules} cm
@@ -96,6 +99,37 @@ public static function get_contexts_for_userid($userid) {
return $contextlist;
}
+ /**
+ * Get the list of users who have data within a context.
+ *
+ * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
+ */
+ public static function get_users_in_context(userlist $userlist) {
+ $context = $userlist->get_context();
+
+ if (!$context instanceof \context_module) {
+ return;
+ }
+
+ // Fetch all users who have a custom certificate.
+ $sql = "SELECT customcertissues.userid
+ FROM {course_modules} cm
+ JOIN {modules} m
+ ON m.id = cm.module AND m.name = :modname
+ JOIN {customcert} customcert
+ ON customcert.id = cm.instance
+ JOIN {customcert_issues} customcertissues
+ ON customcertissues.customcertid = customcert.id
+ WHERE cm.id = :cmid";
+
+ $params = [
+ 'cmid' => $context->instanceid,
+ 'modname' => 'customcert',
+ ];
+
+ $userlist->add_from_sql('userid', $sql, $params);
+ }
+
/**
* Export personal data for the given approved_contextlist. User and context information is contained within the contextlist.
*
@@ -182,6 +216,33 @@ public static function delete_data_for_user(approved_contextlist $contextlist) {
}
}
+ /**
+ * Delete multiple users within a single context.
+ *
+ * @param approved_userlist $userlist The approved context and user information to delete information for.
+ */
+ public static function delete_data_for_users(approved_userlist $userlist) {
+ global $DB;
+
+ $context = $userlist->get_context();
+ if (!$context instanceof \context_module) {
+ return;
+ }
+
+ $cm = get_coursemodule_from_id('customcert', $context->instanceid);
+ if (!$cm) {
+ // Only customcert module will be handled.
+ return;
+ }
+
+ $userids = $userlist->get_userids();
+ list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
+
+ $select = "customcertid = :customcertid AND userid $usersql";
+ $params = ['customcertid' => $cm->instance] + $userparams;
+ $DB->delete_records_select('customcert_issues', $select, $params);
+ }
+
/**
* Return a list of Customcert IDs mapped to their course module ID.
*
diff --git a/db/install.xml b/db/install.xml
index d776f54ee..8db82e772 100644
--- a/db/install.xml
+++ b/db/install.xml
@@ -10,7 +10,7 @@
-
+
@@ -76,7 +76,7 @@
-
+
diff --git a/db/upgrade.php b/db/upgrade.php
index 849028c2c..d0f5ef4b5 100644
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -121,6 +121,26 @@ function xmldb_customcert_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2017050502, 'customcert');
}
+ if ($oldversion < 2017050518.01) {
+ $table = new xmldb_table('customcert');
+ $index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
+ if ($dbman->index_exists($table, $index)) {
+ $dbman->drop_index($table, $index);
+ }
+ $key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, array('templateid'), 'customcert_templates', array('id'));
+ $dbman->add_key($table, $key);
+
+ $table = new xmldb_table('customcert_pages');
+ $index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
+ if ($dbman->index_exists($table, $index)) {
+ $dbman->drop_index($table, $index);
+ }
+ $key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, array('templateid'), 'customcert_templates', array('id'));
+ $dbman->add_key($table, $key);
+
+ upgrade_mod_savepoint(true, 2017050518.01, 'customcert');
+ }
+
if ($oldversion < 2017050506) {
$table = new xmldb_table('customcert_elements');
$field = new xmldb_field('size');
@@ -135,7 +155,7 @@ function xmldb_customcert_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2017050506, 'customcert');
}
- if ($oldversion < 2017050515) {
+ if ($oldversion < 2017111306) {
$table = new xmldb_table('customcert_elements');
$field = new xmldb_field('element', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'name');
@@ -143,27 +163,7 @@ function xmldb_customcert_upgrade($oldversion) {
$dbman->change_field_type($table, $field);
// Savepoint reached.
- upgrade_mod_savepoint(true, 2017050515, 'customcert');
- }
-
- if ($oldversion < 2017050518.01) {
- $table = new xmldb_table('customcert');
- $index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
- if ($dbman->index_exists($table, $index)) {
- $dbman->drop_index($table, $index);
- }
- $key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, array('templateid'), 'customcert_templates', array('id'));
- $dbman->add_key($table, $key);
-
- $table = new xmldb_table('customcert_pages');
- $index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
- if ($dbman->index_exists($table, $index)) {
- $dbman->drop_index($table, $index);
- }
- $key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, array('templateid'), 'customcert_templates', array('id'));
- $dbman->add_key($table, $key);
-
- upgrade_mod_savepoint(true, 2017050518.01, 'customcert');
+ upgrade_mod_savepoint(true, 2017111306, 'customcert');
}
return true;
diff --git a/element/bgimage/classes/privacy/provider.php b/element/bgimage/classes/privacy/provider.php
index e29b69841..61a208273 100644
--- a/element/bgimage/classes/privacy/provider.php
+++ b/element/bgimage/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/bgimage/version.php b/element/bgimage/version.php
index 7ded31f64..847512d54 100644
--- a/element/bgimage/version.php
+++ b/element/bgimage/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_bgimage';
diff --git a/element/border/classes/privacy/provider.php b/element/border/classes/privacy/provider.php
index 1639e5367..0aa2b0a61 100644
--- a/element/border/classes/privacy/provider.php
+++ b/element/border/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/border/version.php b/element/border/version.php
index aec8ecacb..2aa335097 100644
--- a/element/border/version.php
+++ b/element/border/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_border';
diff --git a/element/categoryname/classes/element.php b/element/categoryname/classes/element.php
index e358589c4..48d157820 100644
--- a/element/categoryname/classes/element.php
+++ b/element/categoryname/classes/element.php
@@ -63,7 +63,7 @@ public function render_html() {
*
* @return string
*/
- protected function get_category_name() {
+ protected function get_category_name() : string {
global $DB, $SITE;
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
diff --git a/element/categoryname/classes/privacy/provider.php b/element/categoryname/classes/privacy/provider.php
index 30ae33a92..bcdb8a759 100644
--- a/element/categoryname/classes/privacy/provider.php
+++ b/element/categoryname/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/categoryname/version.php b/element/categoryname/version.php
index ec4c99a38..6f9b86535 100644
--- a/element/categoryname/version.php
+++ b/element/categoryname/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_categoryname';
diff --git a/element/code/classes/privacy/provider.php b/element/code/classes/privacy/provider.php
index a834da45e..cbdbb5019 100644
--- a/element/code/classes/privacy/provider.php
+++ b/element/code/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/code/version.php b/element/code/version.php
index 80ac61995..b95025a73 100644
--- a/element/code/version.php
+++ b/element/code/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_code';
diff --git a/element/coursename/classes/element.php b/element/coursename/classes/element.php
index 1012fa43b..87a1764f5 100644
--- a/element/coursename/classes/element.php
+++ b/element/coursename/classes/element.php
@@ -63,7 +63,7 @@ public function render_html() {
*
* @return string
*/
- protected function get_course_name() {
+ 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());
diff --git a/element/coursename/classes/privacy/provider.php b/element/coursename/classes/privacy/provider.php
index 12b436cde..1c2d02a3b 100644
--- a/element/coursename/classes/privacy/provider.php
+++ b/element/coursename/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/coursename/version.php b/element/coursename/version.php
index 2ba2993c7..0bf953167 100644
--- a/element/coursename/version.php
+++ b/element/coursename/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_coursename';
diff --git a/element/date/classes/privacy/provider.php b/element/date/classes/privacy/provider.php
index cda042db2..1ce5f23d3 100644
--- a/element/date/classes/privacy/provider.php
+++ b/element/date/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/date/version.php b/element/date/version.php
index a81b9d0ce..d98a3164c 100644
--- a/element/date/version.php
+++ b/element/date/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_date';
diff --git a/element/digitalsignature/classes/privacy/provider.php b/element/digitalsignature/classes/privacy/provider.php
index d92747065..6e46add57 100644
--- a/element/digitalsignature/classes/privacy/provider.php
+++ b/element/digitalsignature/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/digitalsignature/version.php b/element/digitalsignature/version.php
index e35d28051..01892ac0c 100644
--- a/element/digitalsignature/version.php
+++ b/element/digitalsignature/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_digitalsignature';
diff --git a/element/grade/classes/privacy/provider.php b/element/grade/classes/privacy/provider.php
index 052efc22b..2f6b29599 100644
--- a/element/grade/classes/privacy/provider.php
+++ b/element/grade/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/grade/version.php b/element/grade/version.php
index cd59a8796..8f24b547f 100644
--- a/element/grade/version.php
+++ b/element/grade/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_grade';
diff --git a/element/gradeitemname/classes/element.php b/element/gradeitemname/classes/element.php
index 4d287dc3d..401de904a 100644
--- a/element/gradeitemname/classes/element.php
+++ b/element/gradeitemname/classes/element.php
@@ -114,7 +114,7 @@ public function definition_after_data($mform) {
*
* @return string
*/
- protected function get_grade_item_name() {
+ protected function get_grade_item_name() : string {
global $DB;
// Get the course module information.
diff --git a/element/gradeitemname/classes/privacy/provider.php b/element/gradeitemname/classes/privacy/provider.php
index d30709f9e..8cf3b952e 100644
--- a/element/gradeitemname/classes/privacy/provider.php
+++ b/element/gradeitemname/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/gradeitemname/version.php b/element/gradeitemname/version.php
index b6265f4f1..9aff1dc4e 100644
--- a/element/gradeitemname/version.php
+++ b/element/gradeitemname/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_gradeitemname';
diff --git a/element/image/classes/privacy/provider.php b/element/image/classes/privacy/provider.php
index e6db81a8a..f800d6c4e 100644
--- a/element/image/classes/privacy/provider.php
+++ b/element/image/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/image/version.php b/element/image/version.php
index 3aaf16c9d..55e6c8161 100644
--- a/element/image/version.php
+++ b/element/image/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_image';
diff --git a/element/studentname/classes/privacy/provider.php b/element/studentname/classes/privacy/provider.php
index 0d6d1ad23..a7ae40215 100644
--- a/element/studentname/classes/privacy/provider.php
+++ b/element/studentname/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/studentname/version.php b/element/studentname/version.php
index dd4ccef68..cb37cfa68 100644
--- a/element/studentname/version.php
+++ b/element/studentname/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_studentname';
diff --git a/element/teachername/classes/privacy/provider.php b/element/teachername/classes/privacy/provider.php
index 9d2ae952e..800c91f2f 100644
--- a/element/teachername/classes/privacy/provider.php
+++ b/element/teachername/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/teachername/version.php b/element/teachername/version.php
index 8b41b889a..f11f0ceb1 100644
--- a/element/teachername/version.php
+++ b/element/teachername/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_teachername';
diff --git a/element/text/classes/element.php b/element/text/classes/element.php
index ccfdba6b2..c2a4f1360 100644
--- a/element/text/classes/element.php
+++ b/element/text/classes/element.php
@@ -100,7 +100,7 @@ public function definition_after_data($mform) {
*
* @return string
*/
- protected function get_text() {
+ 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]);
}
diff --git a/element/text/classes/privacy/provider.php b/element/text/classes/privacy/provider.php
index 74ae4d384..19ca3e3a9 100644
--- a/element/text/classes/privacy/provider.php
+++ b/element/text/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/text/version.php b/element/text/version.php
index 705f10af8..0084c3ad6 100644
--- a/element/text/version.php
+++ b/element/text/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_text';
diff --git a/element/userfield/classes/element.php b/element/userfield/classes/element.php
index 1148d6d46..84db94ac2 100644
--- a/element/userfield/classes/element.php
+++ b/element/userfield/classes/element.php
@@ -133,7 +133,7 @@ public function definition_after_data($mform) {
* @param bool $preview Is this a preview?
* @return string
*/
- protected function get_user_field_value(\stdClass $user, $preview) {
+ protected function get_user_field_value(\stdClass $user, bool $preview) : string {
global $CFG, $DB;
// The user field to display.
diff --git a/element/userfield/classes/privacy/provider.php b/element/userfield/classes/privacy/provider.php
index 58a385cdd..4669a8616 100644
--- a/element/userfield/classes/privacy/provider.php
+++ b/element/userfield/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/userfield/version.php b/element/userfield/version.php
index cb0207ccc..b908ffbd5 100644
--- a/element/userfield/version.php
+++ b/element/userfield/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_userfield';
diff --git a/element/userpicture/classes/privacy/provider.php b/element/userpicture/classes/privacy/provider.php
index 4d0234f65..8b0b3f0f8 100644
--- a/element/userpicture/classes/privacy/provider.php
+++ b/element/userpicture/classes/privacy/provider.php
@@ -40,7 +40,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() {
+ public static function get_reason() : string {
return 'privacy:metadata';
}
}
diff --git a/element/userpicture/version.php b/element/userpicture/version.php
index 1df9c7d56..f6a3173d2 100644
--- a/element/userpicture/version.php
+++ b/element/userpicture/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050500; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111300; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->component = 'customcertelement_userpicture';
diff --git a/tests/external_test.php b/tests/external_test.php
index 50615f27f..6540e644f 100644
--- a/tests/external_test.php
+++ b/tests/external_test.php
@@ -27,8 +27,6 @@
global $CFG;
-require_once($CFG->dirroot . '/webservice/tests/helpers.php');
-
/**
* Unit tests for the webservices.
*
@@ -37,12 +35,12 @@
* @copyright 2018 Mark Nelson
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class mod_customcert_external_test extends externallib_advanced_testcase {
+class mod_customcert_external_test_testcase extends advanced_testcase {
/**
* Test set up.
*/
- public function setUp(): void {
+ public function setUp() {
$this->resetAfterTest();
}
diff --git a/tests/privacy_provider_test.php b/tests/privacy_provider_test.php
new file mode 100644
index 000000000..bd9fe1aa1
--- /dev/null
+++ b/tests/privacy_provider_test.php
@@ -0,0 +1,304 @@
+.
+
+/**
+ * Privacy provider tests.
+ *
+ * @package mod_customcert
+ * @copyright 2018 Mark Nelson
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use mod_customcert\privacy\provider;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy provider tests class.
+ *
+ * @package mod_customcert
+ * @copyright 2018 Mark Nelson
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mod_customcert_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
+
+ /**
+ * Test for provider::get_contexts_for_userid().
+ */
+ public function test_get_contexts_for_userid() {
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ // The customcert activity the user will have an issue from.
+ $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
+
+ // Another customcert activity that has no issued certificates.
+ $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
+
+ // Create a user who will be issued a certificate.
+ $user = $this->getDataGenerator()->create_user();
+
+ // Issue the certificate.
+ $this->create_certificate_issue($customcert->id, $user->id);
+
+ // Check the context supplied is correct.
+ $contextlist = provider::get_contexts_for_userid($user->id);
+ $this->assertCount(1, $contextlist);
+
+ $contextformodule = $contextlist->current();
+ $cmcontext = context_module::instance($customcert->cmid);
+ $this->assertEquals($cmcontext->id, $contextformodule->id);
+ }
+
+ /**
+ * Test for provider::get_users_in_context().
+ */
+ public function test_get_users_in_context() {
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ // The customcert activity the user will have an issue from.
+ $customcert1 = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
+ $customcert2 = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
+
+ // Call get_users_in_context() when the customcert hasn't any user.
+ $cm = get_coursemodule_from_instance('customcert', $customcert1->id);
+ $cmcontext = context_module::instance($cm->id);
+ $userlist = new \core_privacy\local\request\userlist($cmcontext, 'mod_customcert');
+ provider::get_users_in_context($userlist);
+
+ // Check no user has been returned.
+ $this->assertCount(0, $userlist->get_userids());
+
+ // Create some users who will be issued a certificate.
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+ $this->create_certificate_issue($customcert1->id, $user1->id);
+ $this->create_certificate_issue($customcert1->id, $user2->id);
+ $this->create_certificate_issue($customcert2->id, $user3->id);
+
+ // Call get_users_in_context() again.
+ provider::get_users_in_context($userlist);
+
+ // Check this time there are 2 users.
+ $this->assertCount(2, $userlist->get_userids());
+ $this->assertContains($user1->id, $userlist->get_userids());
+ $this->assertContains($user2->id, $userlist->get_userids());
+ $this->assertNotContains($user3->id, $userlist->get_userids());
+ }
+
+ /**
+ * Test for provider::get_users_in_context() with invalid context type.
+ */
+ public function test_get_users_in_context_invalid_context_type() {
+ $systemcontext = context_system::instance();
+
+ $userlist = new \core_privacy\local\request\userlist($systemcontext, 'mod_customcert');
+ \mod_customcert\privacy\provider::get_users_in_context($userlist);
+
+ $this->assertCount(0, $userlist->get_userids());
+ }
+
+ /**
+ * Test for provider::export_user_data().
+ */
+ public function test_export_for_context() {
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ $customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+
+ // Create users who will be issued a certificate.
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+
+ $this->create_certificate_issue($customcert->id, $user1->id);
+ $this->create_certificate_issue($customcert->id, $user1->id);
+ $this->create_certificate_issue($customcert->id, $user2->id);
+
+ // Export all of the data for the context for user 1.
+ $cmcontext = context_module::instance($customcert->cmid);
+ $this->export_context_data_for_user($user1->id, $cmcontext, 'mod_customcert');
+ $writer = \core_privacy\local\request\writer::with_context($cmcontext);
+
+ $this->assertTrue($writer->has_any_data());
+
+ $data = $writer->get_data();
+ $this->assertCount(2, $data->issues);
+
+ $issues = $data->issues;
+ foreach ($issues as $issue) {
+ $this->assertArrayHasKey('code', $issue);
+ $this->assertArrayHasKey('emailed', $issue);
+ $this->assertArrayHasKey('timecreated', $issue);
+ }
+ }
+
+ /**
+ * Test for provider::delete_data_for_all_users_in_context().
+ */
+ public function test_delete_data_for_all_users_in_context() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ $customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+ $customcert2 = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+
+ // Create users who will be issued a certificate.
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+
+ $this->create_certificate_issue($customcert->id, $user1->id);
+ $this->create_certificate_issue($customcert->id, $user2->id);
+
+ $this->create_certificate_issue($customcert2->id, $user1->id);
+ $this->create_certificate_issue($customcert2->id, $user2->id);
+
+ // Before deletion, we should have 2 issued certificates for the first certificate.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert->id]);
+ $this->assertEquals(2, $count);
+
+ // Delete data based on context.
+ $cmcontext = context_module::instance($customcert->cmid);
+ provider::delete_data_for_all_users_in_context($cmcontext);
+
+ // After deletion, the issued certificates for the activity should have been deleted.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert->id]);
+ $this->assertEquals(0, $count);
+
+ // We should still have the issues for the second certificate.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert2->id]);
+ $this->assertEquals(2, $count);
+ }
+
+ /**
+ * Test for provider::delete_data_for_user().
+ */
+ public function test_delete_data_for_user() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ $customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+
+ // Create users who will be issued a certificate.
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+
+ $this->create_certificate_issue($customcert->id, $user1->id);
+ $this->create_certificate_issue($customcert->id, $user2->id);
+
+ // Before deletion we should have 2 issued certificates.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert->id]);
+ $this->assertEquals(2, $count);
+
+ $context = \context_module::instance($customcert->cmid);
+ $contextlist = new \core_privacy\local\request\approved_contextlist($user1, 'customcert',
+ [$context->id]);
+ provider::delete_data_for_user($contextlist);
+
+ // After deletion, the issued certificates for the first user should have been deleted.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert->id, 'userid' => $user1->id]);
+ $this->assertEquals(0, $count);
+
+ // Check the issue for the other user is still there.
+ $customcertissue = $DB->get_records('customcert_issues');
+ $this->assertCount(1, $customcertissue);
+ $lastissue = reset($customcertissue);
+ $this->assertEquals($user2->id, $lastissue->userid);
+ }
+
+ /**
+ * Test for provider::delete_data_for_users().
+ */
+ public function test_delete_data_for_users() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ // Create course, customcert and users who will be issued a certificate.
+ $course = $this->getDataGenerator()->create_course();
+ $customcert1 = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+ $customcert2 = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
+ $cm1 = get_coursemodule_from_instance('customcert', $customcert1->id);
+ $cm2 = get_coursemodule_from_instance('customcert', $customcert2->id);
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+ $this->create_certificate_issue($customcert1->id, $user1->id);
+ $this->create_certificate_issue($customcert1->id, $user2->id);
+ $this->create_certificate_issue($customcert1->id, $user3->id);
+ $this->create_certificate_issue($customcert2->id, $user1->id);
+ $this->create_certificate_issue($customcert2->id, $user2->id);
+
+ // Before deletion we should have 3 + 2 issued certificates.
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert1->id]);
+ $this->assertEquals(3, $count);
+ $count = $DB->count_records('customcert_issues', ['customcertid' => $customcert2->id]);
+ $this->assertEquals(2, $count);
+
+ $context1 = context_module::instance($cm1->id);
+ $approveduserlist = new \core_privacy\local\request\approved_userlist($context1, 'customcert',
+ [$user1->id, $user2->id]);
+ provider::delete_data_for_users($approveduserlist);
+
+ // After deletion, the customcert of the 2 students provided above should have been deleted
+ // from the activity. So there should only remain 1 certificate which is for $user3.
+ $customcertissues1 = $DB->get_records('customcert_issues', ['customcertid' => $customcert1->id]);
+ $this->assertCount(1, $customcertissues1);
+ $lastissue = reset($customcertissues1);
+ $this->assertEquals($user3->id, $lastissue->userid);
+
+ // Confirm that the certificates issues in the other activity are intact.
+ $customcertissues1 = $DB->get_records('customcert_issues', ['customcertid' => $customcert2->id]);
+ $this->assertCount(2, $customcertissues1);
+ }
+
+ /**
+ * Mimicks the creation of a customcert issue.
+ *
+ * There is no API we can use to insert an customcert issue, so we
+ * will simply insert directly into the database.
+ *
+ * @param int $customcertid
+ * @param int $userid
+ */
+ protected function create_certificate_issue(int $customcertid, int $userid) {
+ global $DB;
+
+ static $i = 1;
+
+ $customcertissue = new stdClass();
+ $customcertissue->customcertid = $customcertid;
+ $customcertissue->userid = $userid;
+ $customcertissue->code = \mod_customcert\certificate::generate_code();
+ $customcertissue->timecreated = time() + $i;
+
+ // Insert the record into the database.
+ $DB->insert_record('customcert_issues', $customcertissue);
+
+ $i++;
+ }
+}
diff --git a/version.php b/version.php
index 915be45d1..96099f8a8 100644
--- a/version.php
+++ b/version.php
@@ -24,10 +24,10 @@
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
-$plugin->version = 2017050518.01; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2017050500; // Requires this Moodle version (3.3).
+$plugin->version = 2017111308; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
$plugin->cron = 0; // Period for cron to check this module (secs).
$plugin->component = 'mod_customcert';
$plugin->maturity = MATURITY_STABLE;
-$plugin->release = "3.3.17"; // User-friendly version number.
+$plugin->release = "3.4.7"; // User-friendly version number.