MDL-63924 privacy: Add shared user providers to subsytsems
[moodle.git] / admin / tool / dataprivacy / classes / metadata_registry.php
blob65264807acb7dcef697c70b0dd1b05033f2d31a1
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Class containing helper methods for processing data requests.
20 * @package tool_dataprivacy
21 * @copyright 2018 Adrian Greeve
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 namespace tool_dataprivacy;
26 defined('MOODLE_INTERNAL') || die();
28 /**
29 * Class containing helper methods for processing data requests.
31 * @copyright 2018 Adrian Greeve
32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 class metadata_registry {
36 /**
37 * Returns plugin types / plugins and the user data that it stores in a format that can be sent to a template.
39 * @return array An array with all of the plugin types / plugins and the user data they store.
41 public function get_registry_metadata() {
42 $manager = new \core_privacy\manager();
43 $manager->set_observer(new \tool_dataprivacy\manager_observer());
45 $pluginman = \core_plugin_manager::instance();
46 $contributedplugins = $this->get_contrib_list();
47 $metadata = $manager->get_metadata_for_components();
48 $fullyrichtree = $this->get_full_component_list();
49 foreach ($fullyrichtree as $branch => $leaves) {
50 $plugintype = $leaves['plugin_type'];
51 $plugins = array_map(function($component) use ($manager, $metadata, $contributedplugins, $plugintype, $pluginman) {
52 // Use the plugin name for the plugins, ignore for core subsystems.
53 $internaldata = ($plugintype == 'core') ? ['component' => $component] :
54 ['component' => $pluginman->plugin_name($component)];
55 $internaldata['raw_component'] = $component;
56 if ($manager->component_is_compliant($component)) {
57 $internaldata['compliant'] = true;
58 if (isset($metadata[$component])) {
59 $collection = $metadata[$component]->get_collection();
60 $internaldata = $this->format_metadata($collection, $component, $internaldata);
61 } else if ($manager->is_empty_subsystem($component)) {
62 // This is an unused subsystem.
63 // Use the generic string.
64 $internaldata['nullprovider'] = get_string('privacy:subsystem:empty', 'core_privacy');
65 } else {
66 // Call get_reason for null provider.
67 $internaldata['nullprovider'] = get_string($manager->get_null_provider_reason($component), $component);
69 } else {
70 $internaldata['compliant'] = false;
72 // Check to see if we are an external plugin.
73 // Plugin names can contain _ characters, limit to 2 to just remove initial plugintype.
74 $componentshortname = explode('_', $component, 2);
75 $shortname = array_pop($componentshortname);
76 if (isset($contributedplugins[$plugintype][$shortname])) {
77 $internaldata['external'] = true;
80 // Additional interface checks.
81 if (!$manager->is_empty_subsystem($component)) {
82 $classname = $manager->get_provider_classname_for_component($component);
83 if (class_exists($classname)) {
84 $componentclass = new $classname();
85 // Check if the interface is deprecated.
86 if ($componentclass instanceof \core_privacy\local\deprecated) {
87 $internaldata['deprecated'] = true;
90 // Check that the core_userlist_provider is implemented for all user data providers.
91 if ($componentclass instanceof \core_privacy\local\request\core_user_data_provider
92 && !$componentclass instanceof \core_privacy\local\request\core_userlist_provider) {
93 $internaldata['userlistnoncompliance'] = true;
96 // Check that any type of userlist_provider is implemented for all shared data providers.
97 if ($componentclass instanceof \core_privacy\local\request\shared_data_provider
98 && !$componentclass instanceof \core_privacy\local\request\userlist_provider) {
99 $internaldata['userlistnoncompliance'] = true;
104 return $internaldata;
105 }, $leaves['plugins']);
106 $fullyrichtree[$branch]['plugin_type_raw'] = $plugintype;
107 // We're done using the plugin type. Convert it to a readable string.
108 $fullyrichtree[$branch]['plugin_type'] = $pluginman->plugintype_name($plugintype);
109 $fullyrichtree[$branch]['plugins'] = $plugins;
111 return $fullyrichtree;
115 * Formats the metadata for use with a template.
117 * @param array $collection The collection associated with the component that we want to expand and format.
118 * @param string $component The component that we are dealing in
119 * @param array $internaldata The array to add the formatted metadata to.
120 * @return array The internal data array with the formatted metadata.
122 protected function format_metadata($collection, $component, $internaldata) {
123 foreach ($collection as $collectioninfo) {
124 $privacyfields = $collectioninfo->get_privacy_fields();
125 $fields = '';
126 if (!empty($privacyfields)) {
127 $fields = array_map(function($key, $field) use ($component) {
128 return [
129 'field_name' => $key,
130 'field_summary' => get_string($field, $component)
132 }, array_keys($privacyfields), $privacyfields);
134 // Can the metadata types be located somewhere else besides core?
135 $items = explode('\\', get_class($collectioninfo));
136 $type = array_pop($items);
137 $typedata = [
138 'name' => $collectioninfo->get_name(),
139 'type' => $type,
140 'fields' => $fields,
141 'summary' => get_string($collectioninfo->get_summary(), $component)
143 if (strpos($type, 'subsystem_link') === 0 || strpos($type, 'plugintype_link') === 0) {
144 $typedata['link'] = true;
146 $internaldata['metadata'][] = $typedata;
148 return $internaldata;
152 * Return the full list of components.
154 * @return array An array of plugin types which contain plugin data.
156 protected function get_full_component_list() {
157 global $CFG;
159 $list = \core_component::get_component_list();
160 $list['core']['core'] = "{$CFG->dirroot}/lib";
161 $formattedlist = [];
162 foreach ($list as $plugintype => $plugin) {
163 $formattedlist[] = ['plugin_type' => $plugintype, 'plugins' => array_keys($plugin)];
166 return $formattedlist;
170 * Returns a list of contributed plugins installed on the system.
172 * @return array A list of contributed plugins installed.
174 protected function get_contrib_list() {
175 return array_map(function($plugins) {
176 return array_filter($plugins, function($plugindata) {
177 return !$plugindata->is_standard();
179 }, \core_plugin_manager::instance()->get_plugins());