diff --git a/step/createbackup/classes/privacy/provider.php b/step/createbackup/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..306f0a8242c9769c5ffb306dbee6b4a748986655 --- /dev/null +++ b/step/createbackup/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecyclestep_createbackup\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecyclestep_createbackup. + * + * @package lifecyclestep_createbackup + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/step/createbackup/lang/de/lifecyclestep_createbackup.php b/step/createbackup/lang/de/lifecyclestep_createbackup.php index f767e9f0666fdbe4a8157da24dde1ca0788dfc85..12cc46d483d6d9b27aeb859c763b4ad99ca8fd25 100644 --- a/step/createbackup/lang/de/lifecyclestep_createbackup.php +++ b/step/createbackup/lang/de/lifecyclestep_createbackup.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Kurssicherungs-Schritt'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['maximumbackupspercron'] = 'Maximale Anzahl an Sicherungen per cron'; diff --git a/step/createbackup/lang/en/lifecyclestep_createbackup.php b/step/createbackup/lang/en/lifecyclestep_createbackup.php index 7f811a5cd8e279a9c9817fef846f008522f37e3f..693e7fa6c791e6b248896432d7d36f3794f82487 100644 --- a/step/createbackup/lang/en/lifecyclestep_createbackup.php +++ b/step/createbackup/lang/en/lifecyclestep_createbackup.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Create backup step'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['maximumbackupspercron'] = 'Maximum number of backups per cron'; diff --git a/step/deletecourse/classes/privacy/provider.php b/step/deletecourse/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..6ab29e62de88cb6552b1aca96ef7eb7d68093dde --- /dev/null +++ b/step/deletecourse/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecyclestep_deletecourse\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecyclestep_deletecourse. + * + * @package lifecyclestep_deletecourse + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/step/deletecourse/lang/de/lifecyclestep_deletecourse.php b/step/deletecourse/lang/de/lifecyclestep_deletecourse.php index 7b38ae14f7f0f27abd3238bec3becc1234d9ffbb..62c1f8fdc2047cc4a060fe4f0d27efab99a23077 100644 --- a/step/deletecourse/lang/de/lifecyclestep_deletecourse.php +++ b/step/deletecourse/lang/de/lifecyclestep_deletecourse.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Kurslöschen-Schritt'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['deletecourse_maximumdeletionspercron'] = 'Maximale Anzahl an Kurslöschungen per cron'; diff --git a/step/deletecourse/lang/en/lifecyclestep_deletecourse.php b/step/deletecourse/lang/en/lifecyclestep_deletecourse.php index 1246a2e9451bf07bfb9fd5c73720466adcae3815..5e6f337fc9c6f7f7541a706ee6c17a4e7dc8f35a 100644 --- a/step/deletecourse/lang/en/lifecyclestep_deletecourse.php +++ b/step/deletecourse/lang/en/lifecyclestep_deletecourse.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Delete course step'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['deletecourse_maximumdeletionspercron'] = 'Maximum number of courses deleted per cron'; diff --git a/step/duplicate/classes/privacy/provider.php b/step/duplicate/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..136ee7cacfe34f430a6abcbd12052865fa666886 --- /dev/null +++ b/step/duplicate/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecyclestep_duplicate\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecyclestep_duplicate. + * + * @package lifecyclestep_duplicate + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/step/duplicate/lang/de/lifecyclestep_duplicate.php b/step/duplicate/lang/de/lifecyclestep_duplicate.php index 1ba8f7c1da8398ca2cd171980de41c356291125d..39f01957766c1f106aea2fd21a5f95ea26b7dd9a 100644 --- a/step/duplicate/lang/de/lifecyclestep_duplicate.php +++ b/step/duplicate/lang/de/lifecyclestep_duplicate.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Kurs-Duplizieren-Schritt'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['duplicate_form'] = 'Daten eingeben'; diff --git a/step/duplicate/lang/en/lifecyclestep_duplicate.php b/step/duplicate/lang/en/lifecyclestep_duplicate.php index 4639947599ce16c11da31cdd520f9a2d7a9951c0..b71b5a1519ba529be82d4fa1777b582817356540 100644 --- a/step/duplicate/lang/en/lifecyclestep_duplicate.php +++ b/step/duplicate/lang/en/lifecyclestep_duplicate.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Duplicate step'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['duplicate_form'] = 'Enter data'; diff --git a/step/email/classes/privacy/provider.php b/step/email/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..afbcb51137b4f75466b4fdd053aa7f486071be6b --- /dev/null +++ b/step/email/classes/privacy/provider.php @@ -0,0 +1,173 @@ +<?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/>. + +namespace lifecyclestep_email\privacy; + +use context; +use context_course; +use context_system; +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\core_userlist_provider; +use core_privacy\local\request\userlist; +use core_privacy\local\request\writer; +use dml_exception; + +/** + * Privacy provider for lifecyclestep_email. + * + * @package lifecyclestep_email + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\provider, + \core_privacy\local\request\plugin\provider, + core_userlist_provider { + + /** + * Returns metadata about lifecyclestep_email. + * + * @param collection $collection The initialised collection to add items to. + * @return collection A listing of user data stored by lifecyclestep_email. + */ + public static function get_metadata(collection $collection): collection { + $collection->add_database_table( + 'lifecyclestep_email', + [ + 'touser' => 'privacy:metadata:lifecyclestep_email:touser', + 'courseid' => 'privacy:metadata:lifecyclestep_email:courseid', + 'instanceid' => 'privacy:metadata:lifecyclestep_email:instanceid' + ], + 'privacy:metadata:lifecyclestep_email:summary' + ); + return $collection; + } + + /** + * Get the list of contexts that contain user information for the specified user. + * + * @param int $userid The user to search. + * @return contextlist $contextlist The contextlist containing the list of contexts used + */ + public static function get_contexts_for_userid(int $userid): contextlist { + $contextlist = new contextlist(); + $contextlist->add_system_context(); + + $sql = "SELECT c.id FROM {context} c JOIN {lifecyclestep_email} e ON c.instanceid = e.courseid " + . "WHERE contextlevel = :coursecontextlevel " + . "AND e.touser = :touser"; + $contextlist->add_from_sql($sql, ['coursecontextlevel' => CONTEXT_COURSE, 'touser' => $userid]); + return $contextlist; + } + + /** + * Export all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts to export information for + * @throws dml_exception + */ + public static function export_user_data(approved_contextlist $contextlist): void { + global $DB; + + foreach ($contextlist->get_contexts() as $context) { + if ($context instanceof context_system) { + $records = $DB->get_records('lifecyclestep_email', ['touser' => $contextlist->get_user()->id]); + $writer = writer::with_context($context); + foreach ($records as $record) { + $subcontext = ['lifecyclestep_email-' . $record->id]; + $writer->export_data($subcontext, $record); + } + } else if ($context instanceof context_course) { + $records = $DB->get_records('lifecyclestep_email', + ['courseid' => $context->instanceid, 'touser' => $contextlist->get_user()->id]); + $writer = writer::with_context($context); + foreach ($records as $record) { + $subcontext = ['lifecyclestep_email-' . $record->id]; + $writer->export_data($subcontext, $record); + } + } + } + } + + /** + * 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): void { + if ($userlist->get_context() instanceof context_system) { + $sql = "SELECT touser FROM {lifecyclestep_email}"; + $userlist->add_from_sql('touser', $sql, []); + } else if ($userlist->get_context() instanceof context_course) { + $sql = "SELECT touser FROM {lifecyclestep_email} WHERE courseid = :courseid"; + $userlist->add_from_sql('touser', $sql, ['courseid' => $userlist->get_context()->instanceid]); + } + } + + /** + * Delete data of multiple users within a single context. + * + * @param approved_userlist $userlist The approved context and user information to delete information for. + * @throws dml_exception + */ + public static function delete_data_for_users(approved_userlist $userlist): void { + global $DB; + foreach ($userlist->get_userids() as $userid) { + if ($userlist->get_context() instanceof context_system) { + $DB->delete_records('lifecyclestep_email', ['touser' => $userid]); + } else if ($userlist->get_context() instanceof context_course) { + $DB->delete_records('lifecyclestep_email', ['touser' => $userid, + 'courseid' => $userlist->get_context()->instanceid]); + } + } + } + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + * @throws dml_exception + */ + public static function delete_data_for_all_users_in_context(context $context): void { + global $DB; + if ($context instanceof context_system) { + $DB->delete_records('lifecyclestep_email'); + } else if ($context instanceof context_course) { + $DB->delete_records('lifecyclestep_email', ['courseid' => $context->instanceid]); + } + } + + /** + * Delete all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts and user information to delete information for + * @throws dml_exception + */ + public static function delete_data_for_user(approved_contextlist $contextlist): void { + global $DB; + $user = $contextlist->get_user(); + foreach ($contextlist as $context) { + if ($context instanceof context_system) { + $DB->delete_records('lifecyclestep_email', ['touser' => $user->id]); + } else if ($context instanceof context_course) { + $DB->delete_records('lifecyclestep_email', ['touser' => $user->id, 'courseid' => $context->instanceid]); + } + } + } +} diff --git a/step/email/lang/de/lifecyclestep_email.php b/step/email/lang/de/lifecyclestep_email.php index 2a6c2a269aa1ba773d5bcf6cc7a13ef3a41010ae..82e8115c7830245677e99c26c1cc910e9ccc9af7 100644 --- a/step/email/lang/de/lifecyclestep_email.php +++ b/step/email/lang/de/lifecyclestep_email.php @@ -49,3 +49,8 @@ $string['email:preventdeletion'] = 'Löschen verhindern'; $string['keep_course'] = 'Kurs behalten'; $string['status_message_requiresattention'] = 'Kurs ist zum Löschen vorgemerkt'; $string['action_prevented_deletion'] = '{$a} verhinderte Löschung'; + +$string['privacy:metadata:lifecyclestep_email:courseid'] = 'Die ID des Kurses, zu dem E-Mail-Benachrichtigungen versandt werden'; +$string['privacy:metadata:lifecyclestep_email:instanceid'] = 'Die ID der Schritt-Instanz, der E-Mails verschickt'; +$string['privacy:metadata:lifecyclestep_email:summary'] = 'Informationen, welche Benutzer per E-Mail benachrichtigt werden'; +$string['privacy:metadata:lifecyclestep_email:touser'] = 'Die ID des Benutzers, an den eine E-Mail verschickt wird'; diff --git a/step/email/lang/en/lifecyclestep_email.php b/step/email/lang/en/lifecyclestep_email.php index 15a77d5ccc7ccef5b1d08c046cd93cac7fbf4857..a4d064430395514b8489154443575ca2a8bcc1df 100644 --- a/step/email/lang/en/lifecyclestep_email.php +++ b/step/email/lang/en/lifecyclestep_email.php @@ -49,3 +49,8 @@ $string['email:preventdeletion'] = 'Prevent deletion'; $string['keep_course'] = 'Keep course'; $string['status_message_requiresattention'] = 'Course is marked for deletion'; $string['action_prevented_deletion'] = '{$a} prevented deletion'; + +$string['privacy:metadata:lifecyclestep_email:courseid'] = 'ID of the course, emails will be sent for'; +$string['privacy:metadata:lifecyclestep_email:instanceid'] = 'ID of the step instance sending emails'; +$string['privacy:metadata:lifecyclestep_email:summary'] = 'Information about whhich users will be informed by email'; +$string['privacy:metadata:lifecyclestep_email:touser'] = 'ID of the user who is being notified via email'; diff --git a/step/email/tests/privacy/provider_test.php b/step/email/tests/privacy/provider_test.php new file mode 100644 index 0000000000000000000000000000000000000000..37e3afa7f2079cd1f694bd9c6d01fb4cbd8b4316 --- /dev/null +++ b/step/email/tests/privacy/provider_test.php @@ -0,0 +1,292 @@ +<?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/>. +/** + * Unit tests for the lifecyclestep_email implementation of the privacy API. + * + * @package lifecyclestep_email + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace lifecyclestep_email\privacy; + +use context_course; +use context_system; +use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; +use core_privacy\local\request\userlist; +use core_privacy\local\request\writer; +use core_privacy\tests\provider_testcase; +use dml_exception; +use stdClass; +use tool_lifecycle\local\entity\step_subplugin; +use tool_lifecycle\local\manager\step_manager; +use tool_lifecycle\local\manager\workflow_manager; + +/** + * Unit tests for the lifecyclestep_email implementation of the privacy API. + * + * @package lifecyclestep_email + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider_test extends provider_testcase { + + /** + * Basic setup for the provider tests. + * + * @return void + * @throws dml_exception + */ + public function setUp(): void { + global $DB; + $this->resetAfterTest(); + $this->user1 = $this->getDataGenerator()->create_user(); + $this->user2 = $this->getDataGenerator()->create_user(); + $this->user3 = $this->getDataGenerator()->create_user(); + + $this->course1 = $this->getDataGenerator()->create_course(); + $this->course2 = $this->getDataGenerator()->create_course(); + $this->course3 = $this->getDataGenerator()->create_course(); + + // Create a lifecycle email step. + $testworkflow = workflow_manager::create_workflow('testworkflow'); + $step = new step_subplugin('test email', 'email', $testworkflow->id); + step_manager::insert_or_update($step); + + // Add some entries. + $record = new stdClass(); + $record->touser = $this->user1->id; + $record->courseid = $this->course1->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + + $record = new stdClass(); + $record->touser = $this->user1->id; + $record->courseid = $this->course2->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + + $record = new stdClass(); + $record->touser = $this->user2->id; + $record->courseid = $this->course1->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + + $record = new stdClass(); + $record->touser = $this->user2->id; + $record->courseid = $this->course2->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + + $record = new stdClass(); + $record->touser = $this->user2->id; + $record->courseid = $this->course3->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + + $record = new stdClass(); + $record->touser = $this->user3->id; + $record->courseid = $this->course3->id; + $record->instanceid = $step->id; + $DB->insert_record('lifecyclestep_email', $record); + // We now have 6 entries in the table, 2 for user1, 3 for user2 and 1 for user3. + } + + /** + * Tests \block_lifecyclealert\privacy\provider::get_contexts_for_userid. + * + * @covers \lifecyclestep_email\privacy\provider::get_contexts_for_userid + */ + public function test_get_contexts_for_userid(): void { + $contextlist = provider::get_contexts_for_userid($this->user1->id); + $this->assertEquals(3, $contextlist->count()); + $this->assertTrue(in_array(context_system::instance(), $contextlist->get_contexts())); + $this->assertTrue(in_array(context_course::instance($this->course1->id), $contextlist->get_contexts())); + $this->assertTrue(in_array(context_course::instance($this->course2->id), $contextlist->get_contexts())); + } + + /** + * Tests \lifecyclestep_email\privacy\provider::export_user_data. + * + * @covers \lifecyclestep_email\privacy\provider::export_user_data + * @return void + * @throws dml_exception + */ + public function test_export_user_data(): void { + global $DB; + $course1context = context_course::instance($this->course1->id); + $course2context = context_course::instance($this->course2->id); + $approvedcontextlist = new approved_contextlist($this->user1, 'lifecyclestep_email', + [context_system::instance()->id, $course1context->id, $course2context->id]); + provider::export_user_data($approvedcontextlist); + $writer = writer::with_context(context_system::instance()); + $this->assertTrue($writer->has_any_data()); + $recordids = $DB->get_records('lifecyclestep_email', ['touser' => $this->user1->id], '', 'id'); + foreach ($recordids as $id) { + $exportedrecord = $writer->get_data(['lifecyclestep_email-' . $id->id]); + $this->assertEquals($this->user1->id, $exportedrecord->touser); + $this->assertTrue(in_array($exportedrecord->courseid, [$this->course1->id, $this->course2->id])); + } + + $writer = writer::with_context($course1context); + $this->assertTrue($writer->has_any_data()); + $recordids = $DB->get_records('lifecyclestep_email', ['touser' => $this->user1->id, + 'courseid' => $this->course1->id], '', 'id'); + foreach ($recordids as $id) { + $exportedrecord = $writer->get_data(['lifecyclestep_email-' . $id->id]); + $this->assertEquals($this->user1->id, $exportedrecord->touser); + $this->assertEquals($exportedrecord->courseid, $this->course1->id); + } + + $writer = writer::with_context($course2context); + $this->assertTrue($writer->has_any_data()); + $recordids = $DB->get_records('lifecyclestep_email', ['touser' => $this->user1->id, + 'courseid' => $this->course2->id], '', 'id'); + foreach ($recordids as $id) { + $exportedrecord = $writer->get_data(['lifecyclestep_email-' . $id->id]); + $this->assertEquals($this->user1->id, $exportedrecord->touser); + $this->assertEquals($exportedrecord->courseid, $this->course2->id); + } + } + + /** + * Tests \lifecyclestep_email\privacy\provider::get_users_in_context. + * + * @covers \lifecyclestep_email\privacy\provider::get_users_in_context + * @return void + * @throws dml_exception + */ + public function test_get_users_in_context(): void { + $userlist = new userlist(context_system::instance(), 'lifecyclestep_email'); + provider::get_users_in_context($userlist); + $this->assertCount(3, $userlist->get_userids()); + + $userlist = new userlist(context_course::instance($this->course1->id), 'lifecyclestep_email'); + provider::get_users_in_context($userlist); + $this->assertEquals(2, count($userlist->get_userids())); + $this->assertTrue(in_array($this->user1->id, $userlist->get_userids())); + $this->assertTrue(in_array($this->user2->id, $userlist->get_userids())); + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_users with system context. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_users + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_users() { + global $DB; + $approveduserlist = new approved_userlist(context_system::instance(), 'lifecyclestep_email', + [$this->user1->id, $this->user2->id]); + $this->assertEquals(6, count($DB->get_records('lifecyclestep_email'))); + provider::delete_data_for_users($approveduserlist); + // Only user3 should be left. + $this->assertEquals(1, count($DB->get_records('lifecyclestep_email'))); + foreach ($DB->get_records('lifecyclestep_email') as $record) { + // This should really only be one record. + $this->assertNotEquals($this->user1->id, $record->touser); + $this->assertNotEquals($this->user2->id, $record->touser); + } + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_users with a course context. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_users + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_users_coursecontext() { + global $DB; + $approveduserlist = new approved_userlist(context_course::instance($this->course1->id), 'lifecyclestep_email', + [$this->user1->id, $this->user2->id]); + $this->assertEquals(2, count($DB->get_records('lifecyclestep_email', ['courseid' => $this->course1->id]))); + provider::delete_data_for_users($approveduserlist); + $this->assertEquals(0, count($DB->get_records('lifecyclestep_email', ['courseid' => $this->course1->id]))); + // Other entries should still exist. + $this->assertEquals(4, count($DB->get_records('lifecyclestep_email'))); + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_all_users_in_context. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_all_users_in_context + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_all_users_in_context(): void { + global $DB; + $this->assertEquals(6, count($DB->get_records('lifecyclestep_email'))); + provider::delete_data_for_all_users_in_context(context_system::instance()); + $this->assertEmpty($DB->get_records('lifecyclestep_email')); + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_all_users_in_context with a course context. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_all_users_in_context + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_all_users_in_context_coursecontext(): void { + global $DB; + $this->assertEquals(2, count($DB->get_records('lifecyclestep_email', ['courseid' => $this->course1->id]))); + provider::delete_data_for_all_users_in_context(context_course::instance($this->course1->id)); + $this->assertEmpty($DB->get_records('lifecyclestep_email', ['courseid' => $this->course1->id])); + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_user. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_user + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_user(): void { + global $DB; + $approvedcontextlist = new approved_contextlist($this->user2, 'lifecyclestep_email', + [context_system::instance()->id]); + $this->assertEquals(6, count($DB->get_records('lifecyclestep_email'))); + provider::delete_data_for_user($approvedcontextlist); + $this->assertEquals(3, count($DB->get_records('lifecyclestep_email'))); + foreach ($DB->get_records('lifecyclestep_email') as $record) { + // This should really only be one record. + $this->assertNotEquals($this->user2->id, $record->touser); + } + } + + /** + * Tests \lifecyclestep_email\privacy\provider::delete_data_for_user. + * + * @covers \lifecyclestep_email\privacy\provider::delete_data_for_user + * @return void + * @throws dml_exception + */ + public function test_delete_data_for_user_coursecontext(): void { + global $DB; + $approvedcontextlist = new approved_contextlist($this->user1, 'lifecyclestep_email', + [context_course::instance($this->course1->id)->id, context_course::instance($this->course2->id)->id]); + $this->assertEquals(6, count($DB->get_records('lifecyclestep_email'))); + provider::delete_data_for_user($approvedcontextlist); + $this->assertEquals(0, count($DB->get_records('lifecyclestep_email', + ['courseid' => $this->course1->id, 'touser' => $this->user1->id]))); + $this->assertEquals(0, count($DB->get_records('lifecyclestep_email', + ['courseid' => $this->course2->id, 'touser' => $this->user1->id]))); + } +} diff --git a/trigger/categories/classes/privacy/provider.php b/trigger/categories/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..19da3d64224c6260fe55a8f5ca4ba7ae6225c48c --- /dev/null +++ b/trigger/categories/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_categories\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_categories. + * + * @package lifecycletrigger_categories + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/categories/lang/de/lifecycletrigger_categories.php b/trigger/categories/lang/de/lifecycletrigger_categories.php index 4711e721d139f5258636ec01062c9a57999fe45b..fcec1378ae44033d7c93995d6f1f76ce94cf3f0b 100644 --- a/trigger/categories/lang/de/lifecycletrigger_categories.php +++ b/trigger/categories/lang/de/lifecycletrigger_categories.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Kategorie-Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['categories'] = 'Kategorien, für die der Workflow ausgelöst werden soll.'; $string['categories_noselection'] = 'Bitte wählen sie mindestens eine Kategorie aus.'; diff --git a/trigger/categories/lang/en/lifecycletrigger_categories.php b/trigger/categories/lang/en/lifecycletrigger_categories.php index 178e0364791555d8dedf7079b0658b46ec3caa98..423bd48e4b62e0f037a4e19251d2e4be48f062cd 100644 --- a/trigger/categories/lang/en/lifecycletrigger_categories.php +++ b/trigger/categories/lang/en/lifecycletrigger_categories.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Categories trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['categories'] = 'Categories, for which the workflow should be triggered'; $string['categories_noselection'] = 'Please choose at least one category.'; diff --git a/trigger/delayedcourses/classes/privacy/provider.php b/trigger/delayedcourses/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..2befaf3031d9226cf4f5738d7af99080dcf4f032 --- /dev/null +++ b/trigger/delayedcourses/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_delayedcourses\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_delayedcourses. + * + * @package lifecycletrigger_delayedcourses + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/delayedcourses/lang/de/lifecycletrigger_delayedcourses.php b/trigger/delayedcourses/lang/de/lifecycletrigger_delayedcourses.php index 1dac873c8c889f9a3efc5f0eeda70f9ee99254d6..317e656702472efa60b4c46a3ce428ea8e83f64a 100644 --- a/trigger/delayedcourses/lang/de/lifecycletrigger_delayedcourses.php +++ b/trigger/delayedcourses/lang/de/lifecycletrigger_delayedcourses.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Verzögerte Kurse ausschließen - Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['delay'] = 'Dieser Trigger wird alle Kurse ausschließen, die durch Nutzerinteraktion verzögert wurden.'; diff --git a/trigger/delayedcourses/lang/en/lifecycletrigger_delayedcourses.php b/trigger/delayedcourses/lang/en/lifecycletrigger_delayedcourses.php index 4a5dcdcfe56dd097397c578dd88b82c90f54604c..2d8525ee4df026ace03b9406966ac72195adc491 100644 --- a/trigger/delayedcourses/lang/en/lifecycletrigger_delayedcourses.php +++ b/trigger/delayedcourses/lang/en/lifecycletrigger_delayedcourses.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Exclude delayed courses trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['delay'] = 'This module will exclude all courses, which were delayed by user interaction'; diff --git a/trigger/manual/classes/privacy/provider.php b/trigger/manual/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..b595b593699b12f78bb145aeb27d04c07cbaed11 --- /dev/null +++ b/trigger/manual/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_manual\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_manual. + * + * @package lifecycletrigger_manual + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/manual/lang/de/lifecycletrigger_manual.php b/trigger/manual/lang/de/lifecycletrigger_manual.php index af6f1d1d294aacaa8bc4c0e3ecfb9928ff1dac56..41bc729807e49983dbf537c8dd51f820cd7a6f67 100644 --- a/trigger/manual/lang/de/lifecycletrigger_manual.php +++ b/trigger/manual/lang/de/lifecycletrigger_manual.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Manueller Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['setting_capability'] = 'Berechtigung'; $string['setting_capability_help'] = 'Die Moodle-Berechtigung, die ein Nutzer benötigt, um einen Workflow mit diesem Trigger zu sehen und auszulösen, z.B. "enrol/manual:enrol". Bitte schauen Sie sich die Moodle Access API für Details an.'; $string['setting_icon'] = 'Icon'; diff --git a/trigger/manual/lang/en/lifecycletrigger_manual.php b/trigger/manual/lang/en/lifecycletrigger_manual.php index 249ef5e9e5d3c21baf7306304cf97c76ede9fc84..dea6815d1b8844f6df09fab258598e6a7bc25949 100644 --- a/trigger/manual/lang/en/lifecycletrigger_manual.php +++ b/trigger/manual/lang/en/lifecycletrigger_manual.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Manual trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['setting_capability'] = 'Capability'; $string['setting_capability_help'] = 'The Moodle capability needed to see and invoke a workflow using this trigger, e.g. "enrol/manual:enrol". Please see Moodle access API documentation for details.'; $string['setting_icon'] = 'Icon'; diff --git a/trigger/sitecourse/classes/privacy/provider.php b/trigger/sitecourse/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..8ef22f4c49ec2a177018b149a264e82ceade6d5f --- /dev/null +++ b/trigger/sitecourse/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_sitecourse\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_sitecourse. + * + * @package lifecycletrigger_sitecourse + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/sitecourse/lang/de/lifecycletrigger_sitecourse.php b/trigger/sitecourse/lang/de/lifecycletrigger_sitecourse.php index acd54b6dab51cd577a28a94c32b0858998b00b71..4ea16ed60d1cee9782d7fe0ba3dd13815d2f809c 100644 --- a/trigger/sitecourse/lang/de/lifecycletrigger_sitecourse.php +++ b/trigger/sitecourse/lang/de/lifecycletrigger_sitecourse.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Startseitenkurs ausschließen - Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['delay'] = 'Dieser Trigger wird den Startseitenkurs ausschließen.'; diff --git a/trigger/sitecourse/lang/en/lifecycletrigger_sitecourse.php b/trigger/sitecourse/lang/en/lifecycletrigger_sitecourse.php index 330ef9f6ec34a3f4289fae7e6d3decb0c73eaf0f..7a6c02e280a5e52de57a45e4ceb3944ac4bfee80 100644 --- a/trigger/sitecourse/lang/en/lifecycletrigger_sitecourse.php +++ b/trigger/sitecourse/lang/en/lifecycletrigger_sitecourse.php @@ -23,5 +23,6 @@ */ $string['pluginname'] = 'Exclude site course trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['delay'] = 'This module will exclude the site course from processing'; diff --git a/trigger/specificdate/classes/privacy/provider.php b/trigger/specificdate/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..72e670ced0728cc4b4cef5e7d1f5734ef76e3065 --- /dev/null +++ b/trigger/specificdate/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_specificdate\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_specificdate. + * + * @package lifecycletrigger_specificdate + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/specificdate/lang/de/lifecycletrigger_specificdate.php b/trigger/specificdate/lang/de/lifecycletrigger_specificdate.php index 8e64a25aac0ebf79e53070b9b9e247b5d9bf7a37..7eab683684dde2ee6baeea54e1c05edfd794a166 100644 --- a/trigger/specificdate/lang/de/lifecycletrigger_specificdate.php +++ b/trigger/specificdate/lang/de/lifecycletrigger_specificdate.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Bestimmtes Datum - Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['dates'] = 'Daten, an denen der Workflow ausgeführt werden soll.'; $string['dates_desc'] = 'Ein Datum pro Zeile in dem Format Tag.Monat'; diff --git a/trigger/specificdate/lang/en/lifecycletrigger_specificdate.php b/trigger/specificdate/lang/en/lifecycletrigger_specificdate.php index 1529ac202ab7ff06356e76b522826d5017345e0a..9b7113e8961b100cf03e94fc04f3b1315ee33036 100644 --- a/trigger/specificdate/lang/en/lifecycletrigger_specificdate.php +++ b/trigger/specificdate/lang/en/lifecycletrigger_specificdate.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Specific date trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['dates'] = 'Dates at which the workflow should run.'; $string['dates_desc'] = 'Write one date per line with the format Day.Month'; diff --git a/trigger/startdatedelay/classes/privacy/provider.php b/trigger/startdatedelay/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..f994ae06db05164a8662075bce195fb16f5d5f17 --- /dev/null +++ b/trigger/startdatedelay/classes/privacy/provider.php @@ -0,0 +1,40 @@ +<?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/>. + +namespace lifecycletrigger_startdatedelay\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_startdatedelay. + * + * @package lifecycletrigger_startdatedelay + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/trigger/startdatedelay/lang/de/lifecycletrigger_startdatedelay.php b/trigger/startdatedelay/lang/de/lifecycletrigger_startdatedelay.php index 7f92b7c8bde043dced9656728bf8ffa3631a6bad..1be8ecc179de3be1691a45d6dc94382b766a1269 100644 --- a/trigger/startdatedelay/lang/de/lifecycletrigger_startdatedelay.php +++ b/trigger/startdatedelay/lang/de/lifecycletrigger_startdatedelay.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Startdatumsabstand - Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; $string['delay'] = 'Zeit seit Kursstartdatum, bis ein Prozess gestartet wird'; $string['delay_help'] = 'Der Trigger wird ausgeführt, falls die Zeit, die seit dem Start des Kurses vergangen ist, größer ist, als der angegebene Zeitraum.'; diff --git a/trigger/startdatedelay/lang/en/lifecycletrigger_startdatedelay.php b/trigger/startdatedelay/lang/en/lifecycletrigger_startdatedelay.php index 93d29d534db99d81277cffd4a7ce68981bf11abc..ba6f77df0c21956f1deb48ce9ae01e7324a1eb87 100644 --- a/trigger/startdatedelay/lang/en/lifecycletrigger_startdatedelay.php +++ b/trigger/startdatedelay/lang/en/lifecycletrigger_startdatedelay.php @@ -23,6 +23,7 @@ */ $string['pluginname'] = 'Start date delay trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; $string['delay'] = 'Delay from start of course until starting a process'; $string['delay_help'] = 'The trigger will be invoked if the time passed since the course has started is longer than this delay.';