From 25cf4fa5ca20792259fc2eced5011474e8eeca74 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 14 Oct 2020 17:38:14 +1100 Subject: [PATCH] MDL-69166 core_payment: Add privacy implementation --- enrol/fee/classes/privacy/provider.php | 269 ++++++++++++++ enrol/fee/lang/en/enrol_fee.php | 1 + lang/en/payment.php | 7 + payment/classes/privacy/consumer_provider.php | 69 ++++ payment/classes/privacy/paygw_provider.php | 37 ++ payment/classes/privacy/provider.php | 338 ++++++++++++++++++ .../paypal/classes/privacy/provider.php | 82 +++++ .../gateway/paypal/lang/en/paygw_paypal.php | 1 + 8 files changed, 804 insertions(+) create mode 100644 enrol/fee/classes/privacy/provider.php create mode 100644 payment/classes/privacy/consumer_provider.php create mode 100644 payment/classes/privacy/paygw_provider.php create mode 100644 payment/classes/privacy/provider.php create mode 100644 payment/gateway/paypal/classes/privacy/provider.php diff --git a/enrol/fee/classes/privacy/provider.php b/enrol/fee/classes/privacy/provider.php new file mode 100644 index 00000000000..8c9b4c0d4de --- /dev/null +++ b/enrol/fee/classes/privacy/provider.php @@ -0,0 +1,269 @@ +. + +/** + * Privacy Subsystem implementation for enrol_fee. + * + * @package enrol_fee + * @category privacy + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace enrol_fee\privacy; + +use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; +use core_privacy\local\request\transform; +use core_privacy\local\request\userlist; +use core_privacy\local\request\writer; +use core_payment\helper as payment_helper; + +/** + * Privacy Subsystem for enrol_fee implementing null_provider. + * + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements + \core_privacy\local\metadata\null_provider, + \core_payment\privacy\consumer_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'; + } + + public static function get_contextid_for_payment(string $paymentarea, int $itemid): ?int { + global $DB; + + $sql = "SELECT ctx.id + FROM {enrol} e + JOIN {context} ctx ON (e.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse) + WHERE e.id = :enrolid AND e.enrol = :enrolname"; + $params = [ + 'contextcourse' => CONTEXT_COURSE, + 'enrolid' => $itemid, + 'enrolname' => 'fee', + ]; + $contextid = $DB->get_field_sql($sql, $params); + + return $contextid ?: null; + } + + public static function get_users_in_context(userlist $userlist) { + $context = $userlist->get_context(); + + if ($context instanceof \context_course) { + $sql = "SELECT p.userid + FROM {payments} p + JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id) + WHERE e.courseid = :courseid"; + $params = [ + 'component' => 'enrol_fee', + 'courseid' => $context->instanceid, + ]; + $userlist->add_from_sql('userid', $sql, $params); + } else if ($context instanceof \context_system) { + // If context is system, then the enrolment belongs to a deleted enrolment. + $sql = "SELECT p.userid + FROM {payments} p + LEFT JOIN {enrol} e ON p.itemid = e.id + WHERE p.component = :component AND e.id IS NULL"; + $params = [ + 'component' => 'enrol_fee', + ]; + $userlist->add_from_sql('userid', $sql, $params); + } + } + + /** + * Export all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + */ + public static function export_user_data(approved_contextlist $contextlist) { + global $DB; + + $subcontext = [ + get_string('pluginname', 'enrol_fee'), + ]; + foreach ($contextlist as $context) { + if (!$context instanceof \context_course) { + continue; + } + $feeplugins = $DB->get_records('enrol', ['courseid' => $context->instanceid, 'enrol' => 'fee']); + + foreach ($feeplugins as $feeplugin) { + \core_payment\privacy\provider::export_payment_data_for_user_in_context( + $context, + $subcontext, + $contextlist->get_user()->id, + 'enrol_fee', + 'fee', + $feeplugin->id + ); + } + } + + if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) { + // Orphaned payments. + $sql = "SELECT p.* + FROM {payments} p + LEFT JOIN {enrol} e ON p.itemid = e.id + WHERE p.userid = :userid AND p.component = :component AND e.id IS NULL"; + $params = [ + 'component' => 'enrol_fee', + 'userid' => $contextlist->get_user()->id, + ]; + + $orphanedpayments = $DB->get_recordset_sql($sql, $params); + foreach ($orphanedpayments as $payment) { + \core_payment\privacy\provider::export_payment_data_for_user_in_context( + \context_system::instance(), + $subcontext, + $payment->userid, + $payment->component, + $payment->paymentarea, + $payment->itemid + ); + } + $orphanedpayments->close(); + } + } + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + */ + public static function delete_data_for_all_users_in_context(\context $context) { + if ($context instanceof \context_course) { + $sql = "SELECT p.id + FROM {payments} p + JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id) + WHERE e.courseid = :courseid"; + $params = [ + 'component' => 'enrol_fee', + 'courseid' => $context->instanceid, + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + } else if ($context instanceof \context_system) { + // If context is system, then the enrolment belongs to a deleted enrolment. + $sql = "SELECT p.id + FROM {payments} p + LEFT JOIN {enrol} e ON p.itemid = e.id + WHERE p.component = :component AND e.id IS NULL"; + $params = [ + 'component' => 'enrol_fee', + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + } + } + + /** + * 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. + */ + public static function delete_data_for_user(approved_contextlist $contextlist) { + global $DB; + + if (empty($contextlist->count())) { + return; + } + + $contexts = $contextlist->get_contexts(); + + $courseids = []; + foreach ($contexts as $context) { + if ($context instanceof \context_course) { + $courseids[] = $context->instanceid; + } + } + + [$insql, $inparams] = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED); + + $sql = "SELECT p.id + FROM {payments} p + JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id) + WHERE p.userid = :userid AND e.courseid $insql"; + $params = $inparams + [ + 'component' => 'enrol_fee', + 'userid' => $contextlist->get_user()->id, + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + + if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) { + // Orphaned payments. + $sql = "SELECT p.id + FROM {payments} p + LEFT JOIN {enrol} e ON p.itemid = e.id + WHERE p.component = :component AND p.userid = :userid AND e.id IS NULL"; + $params = [ + 'component' => 'enrol_fee', + 'userid' => $contextlist->get_user()->id, + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + } + } + + /** + * 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_course) { + [$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED); + $sql = "SELECT p.id + FROM {payments} p + JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id) + WHERE e.courseid = :courseid AND p.userid $usersql"; + $params = $userparams + [ + 'component' => 'enrol_fee', + 'courseid' => $context->instanceid, + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + } else if ($context instanceof \context_system) { + // Orphaned payments. + [$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED); + $sql = "SELECT p.id + FROM {payments} p + LEFT JOIN {enrol} e ON p.itemid = e.id + WHERE p.component = :component AND p.userid $usersql AND e.id IS NULL"; + $params = $userparams + [ + 'component' => 'enrol_fee', + ]; + + \core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params); + } + } +} diff --git a/enrol/fee/lang/en/enrol_fee.php b/enrol/fee/lang/en/enrol_fee.php index 3a9b829fc6e..ec59549f527 100644 --- a/enrol/fee/lang/en/enrol_fee.php +++ b/enrol/fee/lang/en/enrol_fee.php @@ -47,6 +47,7 @@ $string['paymentaccount'] = 'Payment account'; $string['paymentaccount_help'] = 'Enrolment fees will be paid to this account.'; $string['pluginname'] = 'Enrolment on payment'; $string['pluginname_desc'] = 'The enrolment on payment enrolment method allows you to set up courses requiring a payment. If the fee for any course is set to zero, then students are not asked to pay for entry. There is a site-wide fee that you set here as a default for the whole site and then a course setting that you can set for each course individually. The course fee overrides the site fee.'; +$string['privacy:metadata'] = 'The enrolment on payment enrolment plugin does not store any personal data.'; $string['purchasedescription'] = 'Enrolment in course {$a}'; $string['sendpaymentbutton'] = 'Select payment type'; $string['status'] = 'Allow enrolment on payment enrolments'; diff --git a/lang/en/payment.php b/lang/en/payment.php index 052dbda2dbb..1081158d595 100644 --- a/lang/en/payment.php +++ b/lang/en/payment.php @@ -51,6 +51,13 @@ $string['nogatewayselected'] = 'You first need to select a payment gateway.'; $string['payments'] = 'Payments'; $string['paymentaccount'] = 'Payment account'; $string['paymentaccounts'] = 'Payment accounts'; +$string['privacy:metadata:database:payments'] = 'Information about the payments.'; +$string['privacy:metadata:database:payments:amount'] = 'The amount for the payment.'; +$string['privacy:metadata:database:payments:currency'] = 'The currency of the payment.'; +$string['privacy:metadata:database:payments:gateway'] = 'The payment gateway that is used for the payment.'; +$string['privacy:metadata:database:payments:timecreated'] = 'The time when the payment was made.'; +$string['privacy:metadata:database:payments:timemodified'] = 'The time when the payment record was last updated.'; +$string['privacy:metadata:database:payments:userid'] = 'The user who made the payment.'; $string['restoreaccount'] = 'Restore'; $string['selectpaymenttype'] = 'Select payment type'; $string['showarchived'] = 'Show archived'; diff --git a/payment/classes/privacy/consumer_provider.php b/payment/classes/privacy/consumer_provider.php new file mode 100644 index 00000000000..cabc1c93089 --- /dev/null +++ b/payment/classes/privacy/consumer_provider.php @@ -0,0 +1,69 @@ +. + +namespace core_payment\privacy; + +use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; +use core_privacy\local\request\userlist; +use context; + +interface consumer_provider { + + /** + * Return contextid for the provided payment data + * + * @param string $paymentarea Payment area + * @param int $itemid The item id + * @return int|null + */ + public static function get_contextid_for_payment(string $paymentarea, int $itemid): ?int; + + /** + * 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); + + /** + * Export all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + */ + public static function export_user_data(approved_contextlist $contextlist); + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + */ + public static function delete_data_for_all_users_in_context(context $context); + + /** + * 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. + */ + 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); +} diff --git a/payment/classes/privacy/paygw_provider.php b/payment/classes/privacy/paygw_provider.php new file mode 100644 index 00000000000..584925ff34f --- /dev/null +++ b/payment/classes/privacy/paygw_provider.php @@ -0,0 +1,37 @@ +. + +namespace core_payment\privacy; + +interface paygw_provider { + + /** + * Export all user data for the specified payment record, and the given context. + * + * @param \context $context Context + * @param array $subcontext The location within the current context that the payment data belongs + * @param \stdClass $payment The payment record + */ + public static function export_payment_data(\context $context, array $subcontext, \stdClass $payment); + + /** + * Delete all user data related to the given payments. + * + * @param string $paymentsql SQL query that selects payment.id field for the payments + * @param array $paymentparams Array of parameters for $paymentsql + */ + public static function delete_data_for_payment_sql(string $paymentsql, array $paymentparams); +} diff --git a/payment/classes/privacy/provider.php b/payment/classes/privacy/provider.php new file mode 100644 index 00000000000..6b7832f72ba --- /dev/null +++ b/payment/classes/privacy/provider.php @@ -0,0 +1,338 @@ +. + +/** + * Privacy Subsystem implementation for core_payment. + * + * @package core_payment + * @category privacy + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_payment\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\transform; +use core_privacy\local\request\userlist; +use core_privacy\local\request\writer; +use core_payment\helper as payment_helper; + +/** + * Privacy Subsystem implementation for core_payment. + * + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements + // This component has data. + // We need to return all payment information where the user is + // listed in the payment.userid field. + // We may also need to fetch this informtion from individual plugins in some cases. + // e.g. to fetch the full and other gateway-specific meta-data. + \core_privacy\local\metadata\provider, + + // This is a subsysytem which provides information to core. + \core_privacy\local\request\subsystem\provider, + + // This is a subsysytem which provides information to plugins. + \core_privacy\local\request\subsystem\plugin_provider, + + // This plugin is capable of determining which users have data within it. + \core_privacy\local\request\core_userlist_provider, + + // This plugin is capable of determining which users have data within it for the plugins it provides data to. + \core_privacy\local\request\shared_userlist_provider +{ + + /** + * Returns meta data about this system. + * + * @param collection $collection The initialised collection to add items to. + * @return collection A listing of user data stored through this system. + */ + public static function get_metadata(collection $collection): collection { + // The 'payments' table contains data about payments. + $collection->add_database_table('payments', [ + 'userid' => 'privacy:metadata:database:payments:userid', + 'amount' => 'privacy:metadata:database:payments:amount', + 'currency' => 'privacy:metadata:database:payments:currency', + 'gateway' => 'privacy:metadata:database:payments:gateway', + 'timecreated' => 'privacy:metadata:database:payments:timecreated', + 'timemodified' => 'privacy:metadata:database:payments:timemodified', + ], 'privacy:metadata:database:payments'); + + return $collection; + } + + /** + * Get the list of users who have data within a context. + * + * @param int $userid The user to search. + * @return contextlist The contextlist containing the list of contexts used in this plugin. + */ + public static function get_contexts_for_userid(int $userid): contextlist { + global $DB; + + $contextids = []; + $payments = $DB->get_recordset('payments', ['userid' => $userid]); + foreach ($payments as $payment) { + $contextids[] = \core_privacy\manager::component_class_callback( + $payment->component, + consumer_provider::class, + 'get_contextid_for_payment', + [$payment->paymentarea, $payment->itemid] + ) ?: SYSCONTEXTID; + } + $payments->close(); + + $contextlist = new contextlist(); + + if (!empty($contextids)) { + [$insql, $inparams] = $DB->get_in_or_equal(array_unique($contextids), SQL_PARAMS_NAMED); + $contextlist->add_from_sql("SELECT id FROM {context} WHERE id {$insql}", $inparams); + } + + 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) { + global $DB; + + $providers = static::get_consumer_providers(); + + foreach ($providers as $provider) { + $provider::get_users_in_context($userlist); + } + + // Orphaned payments. + $context = $userlist->get_context(); + if ($context instanceof \context_system) { + [$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false); + $sql = "SELECT p.userid + FROM {payments} p + WHERE component $notinsql"; + + $userlist->add_from_sql('userid', $sql, $notinparams); + } + } + + /** + * Export all user data for the specified user, in the specified contexts. + * + * @param approved_contextlist $contextlist The approved contexts to export information for. + */ + public static function export_user_data(approved_contextlist $contextlist) { + global $DB; + + $providers = static::get_consumer_providers(); + + foreach ($providers as $provider) { + $provider::export_user_data($contextlist); + } + + // Orphaned payments. + if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) { + [$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false); + $params = ['userid' => $contextlist->get_user()->id] + $notinparams; + $orphanedpayments = $DB->get_records_sql( + "SELECT * + FROM {payments} + WHERE userid = :userid AND component $notinsql", + $params + ); + + foreach ($orphanedpayments as $payment) { + static::export_payment_data_for_user_in_context( + \context_system::instance(), + [''], + $payment->userid, + $payment->component, + $payment->paymentarea, + $payment->itemid + ); + } + } + } + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + */ + public static function delete_data_for_all_users_in_context(\context $context) { + global $DB; + + $providers = static::get_consumer_providers(); + + foreach ($providers as $provider) { + $provider::delete_data_for_all_users_in_context($context); + } + + // Orphaned payments. + if ($context instanceof \context_system) { + [$notinsql, $params] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false); + $paymentsql = "SELECT id FROM {payments} WHERE component $notinsql"; + + static::delete_data_for_payment_sql($paymentsql, $params); + } + } + + /** + * 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. + */ + public static function delete_data_for_user(approved_contextlist $contextlist) { + global $DB; + + $providers = static::get_consumer_providers(); + + foreach ($providers as $provider) { + $provider::delete_data_for_user($contextlist); + } + + // Orphaned payments. + if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) { + [$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false); + $paymentsql = "SELECT id + FROM {payments} + WHERE userid = :userid AND component $notinsql"; + $paymentparams = ['userid' => $contextlist->get_user()->id] + $notinparams; + + static::delete_data_for_payment_sql($paymentsql, $paymentparams); + } + } + + /** + * 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; + + $providers = static::get_consumer_providers(); + + foreach ($providers as $provider) { + $provider::delete_data_for_users($userlist); + } + + // Orphaned payments. + if ($userlist->get_context() instanceof \context_system) { + [$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false); + [$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED); + + $paymentsql = "SELECT id + FROM {payments} + WHERE component $notinsql AND userid $usersql"; + $paymentparams = $notinparams + $userparams; + + static::delete_data_for_payment_sql($paymentsql, $paymentparams); + } + } + + /** + * Returns the list of plugins that use the payment subsystem and implement the consumer_provider interface. + * + * @return string[] provider class names + */ + private static function get_consumer_providers(): array { + $providers = []; + foreach (array_keys(\core_component::get_plugin_types()) as $plugintype) { + $potentialproviders = \core_component::get_plugin_list_with_class($plugintype, 'privacy\provider'); + foreach ($potentialproviders as $potentialprovider) { + if (is_a($potentialprovider, consumer_provider::class, true)) { + $providers[] = $potentialprovider; + } + } + } + return $providers; + } + + /** + * Export all user data for the specified user, in the specified context. + * + * @param \context $context The context that the payment belongs to + * @param string[] $subpath Sub-path to be used during export + * @param int $userid User id + * @param string $component Component name + * @param string $paymentarea Payment area + * @param int $itemid An internal identifier that is used by the component + */ + public static function export_payment_data_for_user_in_context(\context $context, array $subpath, int $userid, + string $component, string $paymentarea, int $itemid) { + global $DB; + + $payments = $DB->get_records('payments', [ + 'component' => $component, + 'paymentarea' => $paymentarea, + 'itemid' => $itemid, + 'userid' => $userid, + ]); + + foreach ($payments as $payment) { + $data = (object) [ + 'userid' => transform::user($payment->userid), + 'amount' => payment_helper::get_cost_as_string($payment->amount, $payment->currency), + 'timecreated' => transform::datetime($payment->timecreated), + 'timemodified' => transform::datetime($payment->timemodified), + ]; + $subcontext = array_merge( + [get_string('payments', 'payment')], + $subpath, + ['payment-' . $payment->id] + ); + writer::with_context($context)->export_data( + $subcontext, + $data + ); + \core_privacy\manager::component_class_callback( + 'paygw_' . $payment->gateway, + paygw_provider::class, + 'export_payment_data', + [$context, $subcontext, $payment] + ); + } + } + + /** + * Delete all user data related to the given payments. + * + * @param string $paymentsql SQL query that selects payment.id field for the payments + * @param array $paymentparams Array of parameters for $paymentsql + */ + public static function delete_data_for_payment_sql(string $paymentsql, array $paymentparams) { + global $DB; + + \core_privacy\manager::plugintype_class_callback( + 'paygw', + paygw_provider::class, + 'delete_data_for_payment_sql', + [$paymentsql, $paymentparams] + ); + + $DB->delete_records_subquery('payments', 'id', 'id', $paymentsql, $paymentparams); + } +} diff --git a/payment/gateway/paypal/classes/privacy/provider.php b/payment/gateway/paypal/classes/privacy/provider.php new file mode 100644 index 00000000000..b736d7b10e7 --- /dev/null +++ b/payment/gateway/paypal/classes/privacy/provider.php @@ -0,0 +1,82 @@ +. + +/** + * Privacy Subsystem implementation for paygw_paypal. + * + * @package paygw_paypal + * @category privacy + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace paygw_paypal\privacy; + +use core_payment\privacy\paygw_provider; +use core_privacy\local\request\writer; + +/** + * Privacy Subsystem implementation for paygw_paypal. + * + * @copyright 2020 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\null_provider, paygw_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'; + } + + /** + * Export all user data for the specified payment record, and the given context. + * + * @param \context $context Context + * @param array $subcontext The location within the current context that the payment data belongs + * @param \stdClass $payment The payment record + */ + public static function export_payment_data(\context $context, array $subcontext, \stdClass $payment) { + global $DB; + + $subcontext[] = get_string('gatewayname', 'paygw_paypal'); + $record = $DB->get_record('paygw_paypal', ['paymentid' => $payment->id]); + + $data = (object) [ + 'orderid' => $record->pp_orderid, + ]; + writer::with_context($context)->export_data( + $subcontext, + $data + ); + } + + /** + * Delete all user data related to the given payments. + * + * @param string $paymentsql SQL query that selects payment.id field for the payments + * @param array $paymentparams Array of parameters for $paymentsql + */ + public static function delete_data_for_payment_sql(string $paymentsql, array $paymentparams) { + global $DB; + + $DB->delete_records_select('paygw_paypal', "paymentid IN ({$paymentsql})", $paymentparams); + } +} diff --git a/payment/gateway/paypal/lang/en/paygw_paypal.php b/payment/gateway/paypal/lang/en/paygw_paypal.php index f3c34cab1a4..e747d1ea99b 100644 --- a/payment/gateway/paypal/lang/en/paygw_paypal.php +++ b/payment/gateway/paypal/lang/en/paygw_paypal.php @@ -38,6 +38,7 @@ $string['live'] = 'Live'; $string['paymentnotcleared'] = 'payment not cleared by PayPal.'; $string['pluginname'] = 'PayPal'; $string['pluginname_desc'] = 'The PayPal plugin allows you to receive payments via PayPal.'; +$string['privacy:metadata'] = 'The Analytic models plugin does not store any personal data.'; $string['repeatedorder'] = 'This order has already been processed earlier.'; $string['sandbox'] = 'Sandbox'; $string['secret'] = 'Secret';