. /** * Class containing helper methods for processing data requests. * * @package tool_dataprivacy * @copyright 2018 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace tool_dataprivacy; defined('MOODLE_INTERNAL') || die(); /** * Class containing helper methods for processing data requests. * * @copyright 2018 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class metadata_registry { /** * Returns plugin types / plugins and the user data that it stores in a format that can be sent to a template. * * @return array An array with all of the plugin types / plugins and the user data they store. */ public function get_registry_metadata() { $manager = new \core_privacy\manager(); $manager->set_observer(new \tool_dataprivacy\manager_observer()); $pluginman = \core_plugin_manager::instance(); $contributedplugins = $this->get_contrib_list(); $metadata = $manager->get_metadata_for_components(); $fullyrichtree = $this->get_full_component_list(); foreach ($fullyrichtree as $branch => $leaves) { $plugintype = $leaves['plugin_type']; $plugins = array_map(function($component) use ($manager, $metadata, $contributedplugins, $plugintype, $pluginman) { // Use the plugin name for the plugins, ignore for core subsystems. $internaldata = ($plugintype == 'core') ? ['component' => $component] : ['component' => $pluginman->plugin_name($component)]; $internaldata['raw_component'] = $component; if ($manager->component_is_compliant($component)) { $internaldata['compliant'] = true; if (isset($metadata[$component])) { $collection = $metadata[$component]->get_collection(); $internaldata = $this->format_metadata($collection, $component, $internaldata); } else if ($manager->is_empty_subsystem($component)) { // This is an unused subsystem. // Use the generic string. $internaldata['nullprovider'] = get_string('privacy:subsystem:empty', 'core_privacy'); } else { // Call get_reason for null provider. $internaldata['nullprovider'] = get_string($manager->get_null_provider_reason($component), $component); } } else { $internaldata['compliant'] = false; } // Check to see if we are an external plugin. // Plugin names can contain _ characters, limit to 2 to just remove initial plugintype. $componentshortname = explode('_', $component, 2); $shortname = array_pop($componentshortname); if (isset($contributedplugins[$plugintype][$shortname])) { $internaldata['external'] = true; } // Additional interface checks. if (!$manager->is_empty_subsystem($component)) { $classname = $manager->get_provider_classname_for_component($component); if (class_exists($classname)) { $componentclass = new $classname(); // Check if the interface is deprecated. if ($componentclass instanceof \core_privacy\local\deprecated) { $internaldata['deprecated'] = true; } // Check that the core_userlist_provider is implemented for all user data providers. if ($componentclass instanceof \core_privacy\local\request\core_user_data_provider && !$componentclass instanceof \core_privacy\local\request\core_userlist_provider) { $internaldata['userlistnoncompliance'] = true; } // Check that any type of userlist_provider is implemented for all shared data providers. if ($componentclass instanceof \core_privacy\local\request\shared_data_provider && !$componentclass instanceof \core_privacy\local\request\userlist_provider) { $internaldata['userlistnoncompliance'] = true; } } } return $internaldata; }, $leaves['plugins']); $fullyrichtree[$branch]['plugin_type_raw'] = $plugintype; // We're done using the plugin type. Convert it to a readable string. $fullyrichtree[$branch]['plugin_type'] = $pluginman->plugintype_name($plugintype); $fullyrichtree[$branch]['plugins'] = $plugins; } return $fullyrichtree; } /** * Formats the metadata for use with a template. * * @param array $collection The collection associated with the component that we want to expand and format. * @param string $component The component that we are dealing in * @param array $internaldata The array to add the formatted metadata to. * @return array The internal data array with the formatted metadata. */ protected function format_metadata($collection, $component, $internaldata) { foreach ($collection as $collectioninfo) { $privacyfields = $collectioninfo->get_privacy_fields(); $fields = ''; if (!empty($privacyfields)) { $fields = array_map(function($key, $field) use ($component) { return [ 'field_name' => $key, 'field_summary' => get_string($field, $component) ]; }, array_keys($privacyfields), $privacyfields); } // Can the metadata types be located somewhere else besides core? $items = explode('\\', get_class($collectioninfo)); $type = array_pop($items); $typedata = [ 'name' => $collectioninfo->get_name(), 'type' => $type, 'fields' => $fields, 'summary' => get_string($collectioninfo->get_summary(), $component) ]; if (strpos($type, 'subsystem_link') === 0 || strpos($type, 'plugintype_link') === 0) { $typedata['link'] = true; } $internaldata['metadata'][] = $typedata; } return $internaldata; } /** * Return the full list of components. * * @return array An array of plugin types which contain plugin data. */ protected function get_full_component_list() { global $CFG; $list = \core_component::get_component_list(); $list['core']['core'] = "{$CFG->dirroot}/lib"; $formattedlist = []; foreach ($list as $plugintype => $plugin) { $formattedlist[] = ['plugin_type' => $plugintype, 'plugins' => array_keys($plugin)]; } return $formattedlist; } /** * Returns a list of contributed plugins installed on the system. * * @return array A list of contributed plugins installed. */ protected function get_contrib_list() { return array_map(function($plugins) { return array_filter($plugins, function($plugindata) { return !$plugindata->is_standard(); }); }, \core_plugin_manager::instance()->get_plugins()); } }