From 0f9f068be1e826d30c5ffa3de61d4399b7b3d34f Mon Sep 17 00:00:00 2001 From: Vithusha Kethiri Date: Thu, 29 Feb 2024 13:02:32 +1100 Subject: [PATCH 1/5] Add privacy provider --- .../notification/classes/privacy/provider.php | 75 +++++++++++++++++++ .../activity/classes/privacy/provider.php | 39 ++++++++++ .../cohort/classes/privacy/provider.php | 39 ++++++++++ .../course/classes/privacy/provider.php | 39 ++++++++++ .../enrolment/classes/privacy/provider.php | 39 ++++++++++ .../session/classes/privacy/provider.php | 39 ++++++++++ lang/en/pulse.php | 7 ++ 7 files changed, 277 insertions(+) create mode 100644 actions/notification/classes/privacy/provider.php create mode 100644 conditions/activity/classes/privacy/provider.php create mode 100644 conditions/cohort/classes/privacy/provider.php create mode 100644 conditions/course/classes/privacy/provider.php create mode 100644 conditions/enrolment/classes/privacy/provider.php create mode 100644 conditions/session/classes/privacy/provider.php diff --git a/actions/notification/classes/privacy/provider.php b/actions/notification/classes/privacy/provider.php new file mode 100644 index 0000000..70b8e8d --- /dev/null +++ b/actions/notification/classes/privacy/provider.php @@ -0,0 +1,75 @@ +. + +namespace pulseaction_notification\privacy; + +use core_privacy\local\metadata\collection; +use core_privacy\local\request\contextlist; +/** + * Privacy provider. + * + * @package pulseaction_notification + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\data_provider { + /** + * Returns meta data about this system. + * + * @param collection $collection + * @return collection + */ + public static function get_metadata(collection $collection): collection { + // We store time spent in a course per linked to a user. + $collection->add_database_table( + 'pulseaction_notification_sch', + [ + 'userid' => 'privacy:metadata:pulseaction_notification_sch:userid', + 'status' => 'privacy:metadata:pulseaction_notification_sch:status', + 'timecreated' => 'privacy:metadata:pulseaction_notification_sch:timecreated', + ], + 'privacy:metadata:pulseaction_notification' + ); + 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 list of contexts used in this plugin. + */ + + public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist { + $contextlist = new \core_privacy\local\request\contextlist(); + + $sql = "SELECT c.id + FROM {context} c + JOIN {course} co ON c.instanceid = co.id + JOIN {user} u ON u.id = :userid + WHERE c.contextlevel = :contextlevel"; + + $params = [ + 'userid' => $userid, + 'contextlevel' => CONTEXT_USER, + ]; + + $contextlist->add_from_sql($sql, $params); + + return $contextlist; + } +} diff --git a/conditions/activity/classes/privacy/provider.php b/conditions/activity/classes/privacy/provider.php new file mode 100644 index 0000000..50e9ef1 --- /dev/null +++ b/conditions/activity/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +/** + * Privacy provider. + * + * @package pulsecondition_activity + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace pulsecondition_activity\privacy; + +defined('MOODLE_INTERNAL') || die(); + +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:pulsecondition_activity'; + } +} diff --git a/conditions/cohort/classes/privacy/provider.php b/conditions/cohort/classes/privacy/provider.php new file mode 100644 index 0000000..7906ec9 --- /dev/null +++ b/conditions/cohort/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +/** + * Privacy provider. + * + * @package pulsecondition_cohort + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace pulsecondition_cohort\privacy; + +defined('MOODLE_INTERNAL') || die(); + +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:pulsecondition_cohort'; + } +} diff --git a/conditions/course/classes/privacy/provider.php b/conditions/course/classes/privacy/provider.php new file mode 100644 index 0000000..9230f96 --- /dev/null +++ b/conditions/course/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +/** + * Privacy provider. + * + * @package pulsecondition_course + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace pulsecondition_course\privacy; + +defined('MOODLE_INTERNAL') || die(); + +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:pulsecondition_course'; + } +} diff --git a/conditions/enrolment/classes/privacy/provider.php b/conditions/enrolment/classes/privacy/provider.php new file mode 100644 index 0000000..4add4ea --- /dev/null +++ b/conditions/enrolment/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +/** + * Privacy provider. + * + * @package pulsecondition_enrolment + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace pulsecondition_enrolment\privacy; + +defined('MOODLE_INTERNAL') || die(); + +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:pulsecondition_enrolment'; + } +} diff --git a/conditions/session/classes/privacy/provider.php b/conditions/session/classes/privacy/provider.php new file mode 100644 index 0000000..83793b4 --- /dev/null +++ b/conditions/session/classes/privacy/provider.php @@ -0,0 +1,39 @@ +. + +/** + * Privacy provider. + * + * @package pulsecondition_session + * @author vithushakethiri + * @copyright 2024 Catalyst IT + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace pulsecondition_session\privacy; + +defined('MOODLE_INTERNAL') || die(); + +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:pulsecondition_session'; + } +} diff --git a/lang/en/pulse.php b/lang/en/pulse.php index 378b84b..8b6672c 100644 --- a/lang/en/pulse.php +++ b/lang/en/pulse.php @@ -182,6 +182,13 @@ $string['privacy:metadata:pulseusers'] = 'List of users invitation notified'; $string['privacy:metadata:pulsemessageexplanation'] = 'Invitations are sent to students through the messaging system.'; +$string['privacy:metadata:pulseaction_notification'] = 'Information about the user to send the notification'; +$string['privacy:metadata:pulsecondition_activity'] = 'The plugin does not store any personal data.'; +$string['privacy:metadata:pulsecondition_cohort'] = 'The plugin does not store any personal data.'; +$string['privacy:metadata:pulsecondition_course'] = 'The plugin does not store any personal data.'; +$string['privacy:metadata:pulsecondition_enrolment'] = 'The plugin does not store any personal data.'; +$string['privacy:metadata:pulsecondition_session'] = 'The plugin does not store any personal data.'; + // Lang strings for the presets. $string['presets'] = "Pulse presets"; $string['usepreset'] = 'Use preset'; From fd1a70002c6f08e32d959e74f4a23aadc2eb78bc Mon Sep 17 00:00:00 2001 From: Vithusha Kethiri Date: Thu, 29 Feb 2024 13:52:20 +1100 Subject: [PATCH 2/5] Updated notification provider --- .../notification/classes/privacy/provider.php | 117 +++++++++++++++++- 1 file changed, 114 insertions(+), 3 deletions(-) diff --git a/actions/notification/classes/privacy/provider.php b/actions/notification/classes/privacy/provider.php index 70b8e8d..dcce8d7 100644 --- a/actions/notification/classes/privacy/provider.php +++ b/actions/notification/classes/privacy/provider.php @@ -17,7 +17,12 @@ namespace pulseaction_notification\privacy; 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\userlist; +use core_privacy\local\request\writer; + /** * Privacy provider. * @@ -59,17 +64,123 @@ public static function get_contexts_for_userid(int $userid) : \core_privacy\loca $sql = "SELECT c.id FROM {context} c - JOIN {course} co ON c.instanceid = co.id + JOIN {pulseaction_notification_sch} pl ON c.instanceid = pl.userid JOIN {user} u ON u.id = :userid WHERE c.contextlevel = :contextlevel"; $params = [ - 'userid' => $userid, - 'contextlevel' => CONTEXT_USER, + 'userid' => $userid, + 'contextlevel' => CONTEXT_USER, ]; $contextlist->add_from_sql($sql, $params); 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_course) { + return; + } + + $sql = "SELECT ts.userid + FROM {pulseaction_notification_sch} ts + WHERE ts.courseid = :courseid"; + + $params = [ + 'courseid' => $context->instanceid, + ]; + $userlist->add_from_sql('userid', $sql, $params); + + } + + /** + * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + */ + public static function export_user_data(approved_contextlist $contextlist) { + global $DB; + + $userid = $contextlist->get_user()->id; + + foreach ($contextlist->get_contexts() as $context) { + if ($context->contextlevel != CONTEXT_COURSE) { + // Only support course context. + continue; + } + + $data = $DB->get_record('pulseaction_notification_sch', ['userid' => $userid, 'courseid' => $context->instanceid]); + writer::with_context($context)->export_data( + [get_string('privacy:metadata:pulseaction_notification', 'pulseaction_notification'), 'pulseaction_notification'], + $data + ); + } + + return $contextlist; + } + + /** + * Delete all personal data for all users in the specified context. + * + * @param context $context Context to delete data from. + */ + public static function delete_data_for_all_users_in_context(\context $context) { + global $DB; + + if ($context->contextlevel != CONTEXT_COURSE) { + return; + } + + $DB->delete_records('pulseaction_notification_sch', ['courseid' => $context->instanceid]); + } + + /** + * Delete user within a single context. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + */ + public static function delete_data_for_user(approved_contextlist $contextlist) { + global $DB; + + $userid = $contextlist->get_user()->id; + + foreach ($contextlist->get_contexts() as $context) { + if ($context->contextlevel != CONTEXT_COURSE) { + // Only support course context. + continue; + } + + $DB->delete_records('pulseaction_notification_sch', ['userid' => $userid, 'courseid' => $context->instanceid]); + } + } + + /** + * 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(); + + // Sanity check that context is at the course context level. + if ($context->contextlevel !== CONTEXT_COURSE) { + return; + } + + list($userinsql, $userinparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED); + $params = array_merge(['courseid' => $context->instanceid], $userinparams); + $sql = "courseid = :courseid AND userid {$userinsql}"; + + $DB->delete_records_select('pulseaction_notification_sch', $sql, $params); + } + } From 7d955cd4bcd58457a81eb60f4057b0f44d26f7e0 Mon Sep 17 00:00:00 2001 From: Vithusha Kethiri Date: Mon, 4 Mar 2024 10:56:05 +1100 Subject: [PATCH 3/5] Update lang strings --- actions/notification/lang/en/pulseaction_notification.php | 2 ++ conditions/activity/lang/en/pulsecondition_activity.php | 2 ++ conditions/cohort/lang/en/pulsecondition_cohort.php | 3 +++ conditions/course/lang/en/pulsecondition_course.php | 2 ++ conditions/enrolment/lang/en/pulsecondition_enrolment.php | 2 ++ conditions/session/lang/en/pulsecondition_session.php | 2 ++ lang/en/pulse.php | 6 ------ 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/actions/notification/lang/en/pulseaction_notification.php b/actions/notification/lang/en/pulseaction_notification.php index 2e309a3..8adccfd 100644 --- a/actions/notification/lang/en/pulseaction_notification.php +++ b/actions/notification/lang/en/pulseaction_notification.php @@ -147,3 +147,5 @@ // ...Reports filter string. $string['automationinstance'] = 'Automation instance'; $string['automationtemplate'] = 'Automation template'; + +$string['privacy:metadata:pulseaction_notification'] = 'Information about the user to send the notification'; diff --git a/conditions/activity/lang/en/pulsecondition_activity.php b/conditions/activity/lang/en/pulsecondition_activity.php index e38026f..7aa7d72 100644 --- a/conditions/activity/lang/en/pulsecondition_activity.php +++ b/conditions/activity/lang/en/pulsecondition_activity.php @@ -33,3 +33,5 @@ $string['selectactivity_help'] = "The Select Activities setting allows you to choose from all available activities within your course that have completion configured. This selection determines which specific activities will trigger the automation when their completion conditions are met."; + +$string['privacy:metadata:pulsecondition_activity'] = 'The plugin does not store any personal data.'; diff --git a/conditions/cohort/lang/en/pulsecondition_cohort.php b/conditions/cohort/lang/en/pulsecondition_cohort.php index 26ba07e..5c99a6d 100644 --- a/conditions/cohort/lang/en/pulsecondition_cohort.php +++ b/conditions/cohort/lang/en/pulsecondition_cohort.php @@ -31,3 +31,6 @@ selected cohorts.The options for cohort membership include:
Disabled: Cohort membership condition is disabled.
All: Cohort membership condition applies to all enrolled users.
Upcoming: Cohort membership condition only applies to future enrolments'; + +$string['privacy:metadata:pulsecondition_cohort'] = 'The plugin does not store any personal data.'; + diff --git a/conditions/course/lang/en/pulsecondition_course.php b/conditions/course/lang/en/pulsecondition_course.php index 8911f77..9c92e0b 100644 --- a/conditions/course/lang/en/pulsecondition_course.php +++ b/conditions/course/lang/en/pulsecondition_course.php @@ -26,3 +26,5 @@ $string['pluginname'] = 'Course completion'; $string['coursecompletion'] = 'Course completion'; $string['coursecompletion_help'] = 'Course Completion: This automation will be triggered when the course is marked as completed, where this instance is used.
Disabled: Course completion condition is disabled.
All: Course completion condition applies to all enrolled users.
Upcoming: Course completion condition only applies to future enrolments.'; + +$string['privacy:metadata:pulsecondition_course'] = 'The plugin does not store any personal data.'; \ No newline at end of file diff --git a/conditions/enrolment/lang/en/pulsecondition_enrolment.php b/conditions/enrolment/lang/en/pulsecondition_enrolment.php index a4df0f6..af1952f 100644 --- a/conditions/enrolment/lang/en/pulsecondition_enrolment.php +++ b/conditions/enrolment/lang/en/pulsecondition_enrolment.php @@ -26,3 +26,5 @@ $string['pluginname'] = 'User enrolment'; $string['enrolment'] = 'User enrolment'; $string['enrolment_help'] = 'Enrolments: This automation will be triggered when a user is enrolled in the course where this instance is located.
Disabled: Enrolment condition is disabled.
All: Enrolment condition applies to all enrolments.
Upcoming: Enrolment condition only applies to future enrolments.'; + +$string['privacy:metadata:pulsecondition_enrolment'] = 'The plugin does not store any personal data.'; \ No newline at end of file diff --git a/conditions/session/lang/en/pulsecondition_session.php b/conditions/session/lang/en/pulsecondition_session.php index 28ab932..e38bcdf 100644 --- a/conditions/session/lang/en/pulsecondition_session.php +++ b/conditions/session/lang/en/pulsecondition_session.php @@ -28,3 +28,5 @@ $string['sessionmodule'] = 'Session module'; $string['sessionmodule_help'] = 'Select the session module for this session booking condition.'; $string['sessionbooking_help'] = 'Session: This automation will be triggered when a session is booked within the course. This trigger is only available within the course and should be selected within the automation instance.The options for session triggers include:
Disabled: Session trigger is disabled.
All: Session trigger applies to all enrolled users.
Upcoming: Session trigger only applies to future enrolments.'; + +$string['privacy:metadata:pulsecondition_session'] = 'The plugin does not store any personal data.'; \ No newline at end of file diff --git a/lang/en/pulse.php b/lang/en/pulse.php index 8b6672c..d75a1e3 100644 --- a/lang/en/pulse.php +++ b/lang/en/pulse.php @@ -182,12 +182,6 @@ $string['privacy:metadata:pulseusers'] = 'List of users invitation notified'; $string['privacy:metadata:pulsemessageexplanation'] = 'Invitations are sent to students through the messaging system.'; -$string['privacy:metadata:pulseaction_notification'] = 'Information about the user to send the notification'; -$string['privacy:metadata:pulsecondition_activity'] = 'The plugin does not store any personal data.'; -$string['privacy:metadata:pulsecondition_cohort'] = 'The plugin does not store any personal data.'; -$string['privacy:metadata:pulsecondition_course'] = 'The plugin does not store any personal data.'; -$string['privacy:metadata:pulsecondition_enrolment'] = 'The plugin does not store any personal data.'; -$string['privacy:metadata:pulsecondition_session'] = 'The plugin does not store any personal data.'; // Lang strings for the presets. $string['presets'] = "Pulse presets"; From e1758a225c57ddafb6587b2563f61b1fc1414397 Mon Sep 17 00:00:00 2001 From: Vithusha Kethiri Date: Fri, 8 Mar 2024 14:10:45 +1100 Subject: [PATCH 4/5] Update lang strings --- actions/notification/lang/en/pulseaction_notification.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/actions/notification/lang/en/pulseaction_notification.php b/actions/notification/lang/en/pulseaction_notification.php index 8adccfd..86581b7 100644 --- a/actions/notification/lang/en/pulseaction_notification.php +++ b/actions/notification/lang/en/pulseaction_notification.php @@ -149,3 +149,6 @@ $string['automationtemplate'] = 'Automation template'; $string['privacy:metadata:pulseaction_notification'] = 'Information about the user to send the notification'; +$string['privacy:metadata:pulseaction_notification_sch:userid'] = 'The ID of the user is tracked.'; +$string['privacy:metadata:pulseaction_notification_sch:status'] = 'The status of the user is tracked.'; +$string['privacy:metadata:pulseaction_notification_sch:timecreated'] = 'The created time of the user is tracked.'; From e7648b9a76edfd92da227b994e5504259e7cd5e8 Mon Sep 17 00:00:00 2001 From: Vithusha Kethiri Date: Thu, 23 May 2024 13:36:38 +1000 Subject: [PATCH 5/5] Fix: Replace VALUE_OPTIONAL with VALUE_DEFAULT in get_chapters_parameters() --- actions/notification/classes/external.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/notification/classes/external.php b/actions/notification/classes/external.php index 4f696e1..b8c7c9e 100644 --- a/actions/notification/classes/external.php +++ b/actions/notification/classes/external.php @@ -44,7 +44,7 @@ class external extends \external_api { */ public static function get_chapters_parameters() { return new \external_function_parameters( - array('mod' => new \external_value(PARAM_INT, 'Book module cmid ', VALUE_OPTIONAL)) + array('mod' => new \external_value(PARAM_INT, 'Book module cmid ', VALUE_DEFAULT)) ); }