MDL-61307 core_privacy: Define and test providers

This commit is contained in:
Andrew Nicols
2018-03-09 12:25:09 +08:00
parent 1d58d59c86
commit 289fe1ef76
48 changed files with 5940 additions and 0 deletions
@@ -0,0 +1,160 @@
<?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/>.
/**
* This file defines the core_privacy\local\metadata\collection class object.
*
* The collection class is used to organize a collection of types
* objects, which contains the privacy field details of a component.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata;
use core_privacy\local\metadata\types\type;
defined('MOODLE_INTERNAL') || die();
/**
* A collection of metadata items.
*
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class collection {
/**
* @var string The component that the items in the collection belong to.
*/
protected $component;
/**
* @var array The collection of metadata items.
*/
protected $collection = [];
/**
* Constructor for a component's privacy collection class.
*
* @param string $component component name.
*/
public function __construct($component) {
$this->component = $component;
}
/**
* Function to add an object that implements type interface to the current collection.
*
* @param type $type to add to collection.
* @return $this
*/
public function add_type(type $type) {
$this->collection[] = $type;
return $this;
}
/**
* Function to add a database table which contains user data to this collection.
*
* @param string $name the name of the database table.
* @param array $privacyfields An associative array of fieldname to description.
* @param string $summary A description of what the table is used for.
* @return $this
*/
public function add_database_table($name, array $privacyfields, $summary = '') {
$this->add_type(new types\database_table($name, $privacyfields, $summary));
return $this;
}
/**
* Function to link a subsystem to the component.
*
* @param string $name the name of the subsystem to link.
* @param string $summary A description of what is stored within this subsystem.
* @return $this
*/
public function link_subsystem($name, $summary = '') {
$this->add_type(new types\subsystem_link($name, $summary));
return $this;
}
/**
* Function to link a plugin to the component.
*
* @param string $name the name of the plugin to link.
* @param string $summary A description of what tis stored within this plugin.
* @return $this
*/
public function link_plugintype($name, $summary = '') {
$this->add_type(new types\plugintype_link($name, $summary));
return $this;
}
/**
* Function to indicate that data may be exported to an external location.
*
* @param string $name A name for the type of data exported.
* @param array $privacyfields A list of fields with their description.
* @param string $summary A description of what the table is used for. This is a language string identifier
* within the component.
* @return $this
*/
public function link_external_location($name, array $privacyfields, $summary = '') {
$this->add_type(new types\external_location($name, $privacyfields, $summary));
return $this;
}
/**
* Add a type of user preference to the collection.
*
* Typically this is a single user preference, but in some cases the
* name of a user preference fits a particular format.
*
* @param string $name The name of the user preference.
* @param string $summary A description of what the preference is used for.
* @return $this
*/
public function add_user_preference($name, $summary = '') {
$this->add_type(new types\user_preference($name, $summary));
return $this;
}
/**
* Function to return the current component name.
*
* @return string
*/
public function get_component() {
return $this->component;
}
/**
* The content of this collection.
*
* @return types\type[]
*/
public function get_collection() {
return $this->collection;
}
}
@@ -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/>.
/**
* This file contains the core_privacy\nodata interface.
*
* Plugins implement this interface to declare that they don't store any personal information.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata;
defined('MOODLE_INTERNAL') || die();
interface 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 ;
}
@@ -0,0 +1,43 @@
<?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/>.
/**
* INterface for main metadata provider interface.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata;
defined('MOODLE_INTERNAL') || die();
/**
* INterface for main metadata provider interface.
*
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface 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 ;
}
@@ -0,0 +1,110 @@
<?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/>.
/**
* This file defines an item of metadata which encapsulates a database table.
*
* @package core_privacy
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The database_table type.
*
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class database_table implements type {
/**
* @var string Database table name.
*/
protected $name;
/**
* @var array Fields which contain user information within the table.
*/
protected $privacyfields;
/**
* @var string A description of what this table is used for.
*/
protected $summary;
/**
* Constructor to create a new database_table type.
*
* @param string $name The name of the database table being described.
* @param array $privacyfields A list of fields with their description.
* @param string $summary A description of what the table is used for.
*/
public function __construct($name, array $privacyfields = [], $summary = '') {
if (debugging('', DEBUG_DEVELOPER)) {
if (empty($privacyfields)) {
debugging("Table '{$name}' was supplied without any fields.", DEBUG_DEVELOPER);
}
foreach ($privacyfields as $key => $field) {
$teststring = clean_param($field, PARAM_STRINGID);
if ($teststring !== $field) {
debugging("Field '{$key}' passed for table '{$name}' has an invalid langstring identifier: '{$field}'",
DEBUG_DEVELOPER);
}
}
$teststring = clean_param($summary, PARAM_STRINGID);
if ($teststring !== $summary) {
debugging("Summary information for the '{$name}' table has an invalid langstring identifier: '{$summary}'",
DEBUG_DEVELOPER);
}
}
$this->name = $name;
$this->privacyfields = $privacyfields;
$this->summary = $summary;
}
/**
* The name of the database table.
*
* @return string
*/
public function get_name() {
return $this->name;
}
/**
* The list of fields within the table which contain user data, with a description of each field.
*
* @return array
*/
public function get_privacy_fields() {
return $this->privacyfields;
}
/**
* A summary of what this table is used for.
*
* @return string
*/
public function get_summary() {
return $this->summary;
}
}
@@ -0,0 +1,112 @@
<?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/>.
/**
* This file defines an item of metadata which encapsulates data which is exported to an external location.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The external_location type.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class external_location implements type {
/**
* @var string The name to describe the type of information exported.
*/
protected $name;
/**
* @var array The list of data names and descriptions exported.
*/
protected $privacyfields;
/**
* @var string A description of what this table is used for.
* This is a language string identifier.
*/
protected $summary;
/**
* Constructor to create a new external_location type.
*
* @param string $name A name for the type of data exported.
* @param array $privacyfields A list of fields with their description.
* @param string $summary A description of what the table is used for. This is a language string identifier
* within the component.
*/
public function __construct($name, array $privacyfields = [], $summary = '') {
if (debugging('', DEBUG_DEVELOPER)) {
if (empty($privacyfields)) {
debugging("Location '{$name}' was supplied without any fields.", DEBUG_DEVELOPER);
}
foreach ($privacyfields as $key => $field) {
$teststring = clean_param($field, PARAM_STRINGID);
if ($teststring !== $field) {
debugging("Field '{$key}' passed for location '{$name}' has an invalid langstring identifier: '{$field}'",
DEBUG_DEVELOPER);
}
}
$teststring = clean_param($summary, PARAM_STRINGID);
if ($teststring !== $summary) {
debugging("Summary information for the '{$name}' location has an invalid langstring identifier: '{$summary}'",
DEBUG_DEVELOPER);
}
}
$this->name = $name;
$this->privacyfields = $privacyfields;
$this->summary = $summary;
}
/**
* The name to describe the type of information exported.
*
* @return string
*/
public function get_name() {
return $this->name;
}
/**
* Get the list of fields which contain user data, with a description of each field.
*
* @return array
*/
public function get_privacy_fields() {
return $this->privacyfields;
}
/**
* A summary of what this type of exported data is used for.
*
* @return string
*/
public function get_summary() {
return $this->summary;
}
}
@@ -0,0 +1,92 @@
<?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/>.
/**
* This file defines a link to another Moodle plugin.
*
* @package core_privacy
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The plugintype link.
*
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugintype_link implements type {
/**
* @var The name of the core plugintype to link.
*/
protected $name;
/**
* @var string A description of what this plugintype is used to store.
*/
protected $summary;
/**
* Constructor for the plugintype_link.
*
* @param string $name The name of the plugintype to link.
* @param string $summary A description of what is stored within this plugintype.
*/
public function __construct($name, $summary = '') {
if (debugging('', DEBUG_DEVELOPER)) {
$teststring = clean_param($summary, PARAM_STRINGID);
if ($teststring !== $summary) {
debugging("Summary information for use of the '{$name}' plugintype " .
"has an invalid langstring identifier: '{$summary}'",
DEBUG_DEVELOPER);
}
}
$this->name = $name;
$this->summary = $summary;
}
/**
* Function to return the name of this plugintype_link type.
*
* @return string $name
*/
public function get_name() {
return $this->name;
}
/**
* A plugintype link does not define any fields itself.
*
* @return array
*/
public function get_privacy_fields() : array {
return null;
}
/**
* A summary of what this plugintype is used for.
*
* @return string $summary
*/
public function get_summary() {
return $this->summary;
}
}
@@ -0,0 +1,92 @@
<?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/>.
/**
* This file defines a link to another Moodle subsystem.
*
* @package core_privacy
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The subsystem link type.
*
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class subsystem_link implements type {
/**
* @var The name of the core subsystem to link.
*/
protected $name;
/**
* @var string A description of what this subsystem is used to store.
*/
protected $summary;
/**
* Constructor for the subsystem_link.
*
* @param string $name The name of the subsystem to link.
* @param string $summary A description of what is stored within this subsystem.
*/
public function __construct($name, $summary = '') {
if (debugging('', DEBUG_DEVELOPER)) {
$teststring = clean_param($summary, PARAM_STRINGID);
if ($teststring !== $summary) {
debugging("Summary information for use of the '{$name}' subsystem " .
"has an invalid langstring identifier: '{$summary}'",
DEBUG_DEVELOPER);
}
}
$this->name = $name;
$this->summary = $summary;
}
/**
* Function to return the name of this subsystem_link type.
*
* @return string $name
*/
public function get_name() {
return $this->name;
}
/**
* A subsystem link does not define any fields itself.
*
* @return array
*/
public function get_privacy_fields() : array {
return null;
}
/**
* A summary of what this subsystem is used for.
*
* @return string $summary
*/
public function get_summary() {
return $this->summary;
}
}
@@ -0,0 +1,56 @@
<?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/>.
/**
* The base type interface which encapsulates a set of data held by a component with Moodle.
*
* @package core_privacy
* @copyright 2018 Zig Tan <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The base type interface which all metadata types must implement.
*
* @copyright 2018 Zig Tan <[email protected]>
* @package core_privacy
*/
interface type {
/**
* Get the name describing this type.
*
* @return string
*/
public function get_name();
/**
* A list of the fields and their usage description.
*
* @return array
*/
public function get_privacy_fields();
/**
* A summary of what the metalink type is used for.
*
* @return string $summary
*/
public function get_summary();
}
@@ -0,0 +1,93 @@
<?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/>.
/**
* This file defines an item of metadata which encapsulates a user's preferences.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\metadata\types;
defined('MOODLE_INTERNAL') || die();
/**
* The user_preference type.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class user_preference implements type {
/**
* @var The name of this user preference.
*/
protected $name;
/**
* @var A description of what this user preference means.
*/
protected $summary;
/**
* Constructor to create a new user_preference types.
*
* @param string $name The name of the user preference.
* @param string $summary A description of what the preference is used for.
*/
public function __construct($name, $summary = '') {
if (debugging('', DEBUG_DEVELOPER)) {
$teststring = clean_param($summary, PARAM_STRINGID);
if ($teststring !== $summary) {
debugging("Summary information for use of the '{$name}' subsystem " .
" has an invalid langstring identifier: '{$summary}'",
DEBUG_DEVELOPER);
}
}
$this->name = $name;
$this->summary = $summary;
}
/**
* The name of the user preference.
*
* @return string
*/
public function get_name() {
return $this->name;
}
/**
* A user preference encapsulates a single field and has no sub-fields.
*
* @return array
*/
public function get_privacy_fields() {
return null;
}
/**
* A summary of what this user preference is used for.
*
* @return string
*/
public function get_summary() {
return $this->summary;
}
}
@@ -0,0 +1,75 @@
<?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/>.
/**
* An implementation of a contextlist which has been filtered and approved.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* An implementation of a contextlist which has been filtered and approved.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class approved_contextlist extends contextlist_base {
/**
* @var \stdClass The user this contextlist belongs to.
*/
protected $user;
/**
* Create a new approved contextlist.
*
* @param \stdClass $user The user record.
* @param string $component the frankenstyle component name.
* @param \int[] $contextids The list of contextids present in this list.
*/
public function __construct(\stdClass $user, string $component, array $contextids) {
$this->set_user($user);
$this->set_component($component);
$this->set_contextids($contextids);
}
/**
* Specify the user which owns this request.
*
* @param \stdClass $user The user record.
* @return $this
*/
protected function set_user(\stdClass $user) : approved_contextlist {
$this->user = $user;
return $this;
}
/**
* Get the user which requested their data.
*
* @return \stdClass
*/
public function get_user() : \stdClass {
return $this->user;
}
}
@@ -0,0 +1,143 @@
<?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/>.
/**
* This file contains the interface required to implmeent a content writer.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The interface for a Moodle content writer.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*/
interface content_writer {
/**
* Constructor for the content writer.
*
* Note: The writer_factory must be passed.
* @param writer $writer The factory.
*/
public function __construct(writer $writer);
/**
* Set the context for the current item being processed.
*
* @param \context $context The context to use
* @return content_writer
*/
public function set_context(\context $context) : content_writer ;
/**
* Export the supplied data within the current context, at the supplied subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stdClass $data The data to be exported
* @return content_writer
*/
public function export_data(array $subcontext, \stdClass $data) : content_writer ;
/**
* Export metadata about the supplied subcontext.
*
* Metadata consists of a key/value pair and a description of the value.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $name The metadata name.
* @param string $value The metadata value.
* @param string $description The description of the value.
* @return content_writer
*/
public function export_metadata(array $subcontext, string $name, $value, string $description) : content_writer ;
/**
* Export a piece of related data.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $name The name of the file to be exported.
* @param \stdClass $data The related data to export.
* @return content_writer
*/
public function export_related_data(array $subcontext, $name, $data) : content_writer ;
/**
* Export a piece of data in a custom format.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $filename The name of the file to be exported.
* @param string $filecontent The content to be exported.
* @return content_writer
*/
public function export_custom_file(array $subcontext, $filename, $filecontent) : content_writer ;
/**
* Prepare a text area by processing pluginfile URLs within it.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
* @param string $text The text to be processed
* @return string The processed string
*/
public function rewrite_pluginfile_urls(array $subcontext, $component, $filearea, $itemid, $text) : string;
/**
* Export all files within the specified component, filearea, itemid combination.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
* @return content_writer
*/
public function export_area_files(array $subcontext, $component, $filearea, $itemid) : content_writer ;
/**
* Export the specified file in the target location.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stored_file $file The file to be exported.
* @return content_writer
*/
public function export_file(array $subcontext, \stored_file $file) : content_writer ;
/**
* Export the specified user preference.
*
* @param string $component The name of the component.
* @param string $key The name of th key to be exported.
* @param string $value The value of the preference
* @param string $description A description of the value
* @return content_writer
*/
public function export_user_preference(string $component, string $key, string $value, string $description) : content_writer ;
/**
* Perform any required finalisation steps and return the location of the finalised export.
*
* @return string
*/
public function finalise_content() : string ;
}
@@ -0,0 +1,72 @@
<?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/>.
/**
* Privacy Fetch Result Set.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Fetch Result Set.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist extends contextlist_base {
/**
* Add a set of contexts from SQL.
*
* The SQL should only return a list of context IDs.
*
* @param string $sql The SQL which will fetch the list of * context IDs
* @param array $params The set of SQL parameters
* @return $this
*/
public function add_from_sql(string $sql, array $params) : contextlist {
global $DB;
$fields = \context_helper::get_preload_record_columns_sql('ctx');
$wrapper = "SELECT {$fields} FROM {context} ctx WHERE id IN ({$sql})";
$contexts = $DB->get_recordset_sql($wrapper, $params);
$contextids = [];
foreach ($contexts as $context) {
$contextids[] = $context->ctxid;
\context_helper::preload_from_record($context);
}
$this->set_contextids(array_merge($this->get_contextids(), $contextids));
return $this;
}
/**
* Sets the component for this contextlist.
*
* @param string $component the frankenstyle component name.
*/
public function set_component($component) {
parent::set_component($component);
}
}
@@ -0,0 +1,161 @@
<?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/>.
/**
* Base implementation of a contextlist.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* Base implementation of a contextlist used to store a set of contexts.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class contextlist_base implements
// Implement an Iterator to fetch the Context objects.
\Iterator,
// Implement the Countable interface to allow the number of returned results to be queried easily.
\Countable {
/**
* @var array List of context IDs.
*
* Note: this must not be updated using set_contextids only as this
* ensures uniqueness.
*/
private $contextids = [];
/**
* @var string component the frankenstyle component name.
*/
protected $component = '';
/**
* @var int Current position of the iterator.
*/
protected $iteratorposition = 0;
/**
* Set the contextids.
*
* @param array $contextids The list of contexts.
*/
protected function set_contextids(array $contextids) {
$this->contextids = array_unique($contextids);
}
/**
* Get the list of context IDs that relate to this request.
*
* @return int[]
*/
public function get_contextids() : array {
return $this->contextids;
}
/**
* Get the complete list of context objects that relate to this
* request.
*
* @return \contect[]
*/
public function get_contexts() : array {
$contexts = [];
foreach ($this->contextids as $contextid) {
$contexts[] = \context::instance_by_id($contextid);
}
return $contexts;
}
/**
* Sets the component for this contextlist.
*
* @param string $component the frankenstyle component name.
*/
protected function set_component($component) {
$this->component = $component;
}
/**
* Get the name of the component to which this contextlist belongs.
*
* @return string the component name associated with this contextlist.
*/
public function get_component() : string {
return $this->component;
}
/**
* Return the current context.
*
* @return \context
*/
public function current() {
return \context::instance_by_id($this->contextids[$this->iteratorposition]);
}
/**
* Return the key of the current element.
*
* @return mixed
*/
public function key() {
return $this->iteratorposition;
}
/**
* Move to the next context in the list.
*/
public function next() {
++$this->iteratorposition;
}
/**
* Check if the current position is valid.
*
* @return bool
*/
public function valid() {
return isset($this->contextids[$this->iteratorposition]);
}
/**
* Rewind to the first found context.
*
* The list of contexts is uniqued during the rewind.
* The rewind is called at the start of most iterations.
*/
public function rewind() {
$this->iteratorposition = 0;
}
/**
* Return the number of contexts.
*/
public function count() {
return count($this->contextids);
}
}
@@ -0,0 +1,180 @@
<?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/>.
/**
* This file defines the contextlist_collection class object.
*
* The contextlist_collection is used to organize a collection of contextlists.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* A collection of contextlist items.
*
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist_collection implements \Iterator, \Countable {
/**
* @var int $userid The ID of the user that the contextlist collection belongs to.
*/
protected $userid = null;
/**
* @var array $contextlists the internal array of contextlist objects.
*/
protected $contextlists = [];
/**
* @var int Current position of the iterator.
*/
protected $iteratorposition = 0;
/**
* Constructor to create a new contextlist_collection.
*
* @param int $userid The userid to which this collection belongs.
*/
public function __construct($userid) {
$this->userid = $userid;
}
/**
* Return the ID of the user whose collection this is.
*
* @return int
*/
public function get_userid() : int {
return $this->userid;
}
/**
* Add a contextlist to this collection.
*
* @param contextlist_base $contextlist the contextlist to export.
* @return $this
*/
public function add_contextlist(contextlist_base $contextlist) {
$component = $contextlist->get_component();
if (empty($component)) {
throw new \moodle_exception("The contextlist must have a component set");
}
if (isset($this->contextlists[$component])) {
throw new \moodle_exception("A contextlist has already been added for the '{$component}' component");
}
$this->contextlists[$component] = $contextlist;
return $this;
}
/**
* Get the contextlists in this collection.
*
* @return array the associative array of contextlists in this collection, indexed by component name.
* E.g. mod_assign => contextlist, core_comment => contextlist.
*/
public function get_contextlists() : array {
return $this->contextlists;
}
/**
* Get the contextlist for the specified component.
*
* @param string $component the frankenstyle name of the component to fetch for.
* @return contextlist_base|null
*/
public function get_contextlist_for_component(string $component) {
if (isset($this->contextlists[$component])) {
return $this->contextlists[$component];
}
return null;
}
/**
* Return the current contexlist.
*
* @return \context
*/
public function current() {
$key = $this->get_key_from_position();
return $this->contextlists[$key];
}
/**
* Return the key of the current element.
*
* @return mixed
*/
public function key() {
return $this->get_key_from_position();
}
/**
* Move to the next context in the list.
*/
public function next() {
++$this->iteratorposition;
}
/**
* Check if the current position is valid.
*
* @return bool
*/
public function valid() {
return ($this->iteratorposition < count($this->contextlists));
}
/**
* Rewind to the first found context.
*
* The list of contexts is uniqued during the rewind.
* The rewind is called at the start of most iterations.
*/
public function rewind() {
$this->iteratorposition = 0;
}
/**
* Get the key for the current iterator position.
*
* @return string
*/
protected function get_key_from_position() {
$keylist = array_keys($this->contextlists);
if (isset($keylist[$this->iteratorposition])) {
return $keylist[$this->iteratorposition];
}
return null;
}
/**
* Return the number of contexts.
*/
public function count() {
return count($this->contextlists);
}
}
@@ -0,0 +1,44 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\core_data_provider interface to describe
* classes which provide data in some form to core.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The core_data_provider interface is used to describe a provider which
* services user requests between components and core.
*
* It does not define a specific way of doing so and different types of
* data will need to extend this interface in order to define their own
* contract.
*
* It should not be implemented directly, but should be extended by other
* interfaces in core.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*/
interface core_data_provider extends data_provider {
}
@@ -0,0 +1,69 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\core_user_data_provider interface to describe
* classes which provide user data in some form to core.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The core_user_data_provider interface is used to describe a provider
* which services user requests between components and core.
*
* It describes data how these requests are serviced in a specific format.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*/
interface core_user_data_provider extends core_data_provider {
/**
* 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 in this plugin.
*/
public static function get_contexts_for_userid(int $userid) : contextlist;
/**
* 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 use data which matches the specified deletion_criteria.
*
* @param deletion_criteria $criteria An object containing specific deletion criteria to delete for.
*/
public static function delete_for_context(deletion_criteria $criteria);
/**
* 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_user_data(approved_contextlist $contextlist);
}
@@ -0,0 +1,49 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\data_provider interface to describe
* a class which provides data in some form.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The data_provider interface is used to describe a provider
* which services user requests in any fashion. This includes both
* -- component <-> core; and
* -- component <-> component.
*
* It does not define a specific way of doing so and different types of
* data will need to extend this interface in order to define their own
* contract.
*
* It should not be implemented directly, but should be extended by other
* interfaces in core.
*
* This is the base interface for any component which stores any form of
* user data.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*/
interface data_provider {
}
@@ -0,0 +1,58 @@
<?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/>.
/**
* The \core_privacy\local\request\deletion_criteria class.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The deletion_criteria class is used to describe conditions for a set of
* data due to be deleted.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class deletion_criteria {
/**
* @var context The context being deleted.
*/
protected $context = null;
/**
* Constructor for a new deletion_criteria.
*
* @param \context $context The context being deleted.
*/
public function __construct(\context $context) {
$this->context = $context;
}
/**
* Get the context to be deleted.
*
* @return \context
*/
public function get_context() : \context {
return $this->context;
}
}
+301
View File
@@ -0,0 +1,301 @@
<?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/>.
/**
* This file contains the core_privacy\local\request helper.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
use \core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/modinfolib.php');
require_once($CFG->dirroot . '/course/modlib.php');
/**
* The core_privacy\local\request\helper class with useful shared functionality.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Add core-controlled contexts which are related to a component but that component may know about.
*
* For example, most activities are not aware of activity completion, but the course implements it for them.
* These should be included.
*
* @param int $userid The user being added for.
* @param contextlist $contextlist The contextlist being appended to.
* @return contextlist The final contextlist
*/
public static function add_shared_contexts_to_contextlist_for(int $userid, contextlist $contextlist) : contextlist {
if (strpos($contextlist->get_component(), 'mod_') === 0) {
// Activity modules support data stored by core about them - for example, activity completion.
$contextlist = static::add_shared_contexts_to_contextlist_for_course_module($userid, $contextlist);
}
return $contextlist;
}
/**
* Handle export of standard data for a plugin which implements the null provider and does not normally store data
* of its own.
*
* This is used in cases such as activities like mod_resource, which do not store their own data, but may still have
* data on them (like Activity Completion).
*
* Any context provided in a contextlist should have base data exported as a minimum.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_data_for_null_provider(approved_contextlist $contextlist) {
$user = $contextlist->get_user();
foreach ($contextlist as $context) {
$data = static::get_context_data($context, $user);
static::export_context_files($context, $user);
writer::with_context($context)->export_data([], $data);
}
}
/**
* Handle removal of 'standard' data for any plugin.
*
* This will handle deletion for things such as activity completion.
*
* @param string $component The component being deleted for.
* @param deletion_criteria $criteria An object containing specific deletion criteria to delete for.
*/
public static function delete_for_context(string $component, deletion_criteria $criteria) {
if (strpos($component, 'mod_') === 0) {
// Activity modules support data stored by core about them - for example, activity completion.
static::delete_for_context_course_module($component, $criteria->get_context());
}
}
/**
* Delete all 'standard' user data for the specified user, in the specified contexts.
*
* This will handle deletion for things such as activity completion.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_user_data(approved_contextlist $contextlist) {
$component = $contextlist->get_component();
if (strpos($component, 'mod_') === 0) {
// Activity modules support data stored by core about them - for example, activity completion.
static::delete_user_data_for_course_module($contextlist);
}
}
/**
* Get all general data for this context.
*
* @param \context $context The context to retrieve data for.
* @param \stdClass $user The user being written.
* @return \stdClass
*/
public static function get_context_data(\context $context, \stdClass $user) : \stdClass {
global $DB;
$basedata = (object) [];
if ($context instanceof \context_module) {
return static::get_context_module_data($context, $user);
}
if ($context instanceof \context_block) {
return static::get_context_block_data($context, $user);
}
return $basedata;
}
/**
* Export all files for this context.
*
* @param \context $context The context to export files for.
* @param \stdClass $user The user being written.
* @return \stdClass
*/
public static function export_context_files(\context $context, \stdClass $user) {
if ($context instanceof \context_module) {
return static::export_context_module_files($context, $user);
}
}
/**
* Add core-controlled contexts which are related to a component but that component may know about.
*
* For example, most activities are not aware of activity completion, but the course implements it for them.
* These should be included.
*
* @param int $userid The user being added for.
* @param contextlist $contextlist The contextlist being appended to.
* @return contextlist The final contextlist
*/
protected static function add_shared_contexts_to_contextlist_for_course_module(int $userid, contextlist $contextlist) : contextlist {
// Fetch all contexts where the user has activity completion enabled.
$sql = "SELECT
c.id
FROM {course_modules_completion} cmp
INNER JOIN {course_modules} cm ON cm.id = cmp.coursemoduleid
INNER JOIN {modules} m ON m.id = cm.module
INNER JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :contextlevel
WHERE cmp.userid = :userid
AND m.name = :modname";
$params = [
'userid' => $userid,
// Strip the mod_ from the name.
'modname' => substr($contextlist->get_component(), 4),
'contextlevel' => CONTEXT_MODULE,
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get all general data for the activity module at this context.
*
* @param \context_module $context The context to retrieve data for.
* @param \stdClass $user The user being written.
* @return \stdClass
*/
protected static function get_context_module_data(\context_module $context, \stdClass $user) : \stdClass {
global $DB;
$coursecontext = $context->get_course_context();
$modinfo = get_fast_modinfo($coursecontext->instanceid);
$cm = $modinfo->cms[$context->instanceid];
$component = "mod_{$cm->modname}";
$course = $cm->get_course();
$moduledata = $DB->get_record($cm->modname, ['id' => $cm->instance]);
$basedata = (object) [
'name' => $cm->get_formatted_name(),
];
if (plugin_supports('mod', $cm->modname, FEATURE_MOD_INTRO, true)) {
$intro = $moduledata->intro;
$intro = writer::with_context($context)
->rewrite_pluginfile_urls([], $component, 'intro', 0, $intro);
$options = [
'noclean' => true,
'para' => false,
'context' => $context,
'overflowdiv' => true,
];
$basedata->intro = format_text($intro, $moduledata->introformat, $options);
}
// Completion tracking.
$completioninfo = new \completion_info($course);
$completion = $completioninfo->is_enabled($cm);
if ($completion != COMPLETION_TRACKING_NONE) {
$completiondata = $completioninfo->get_data($cm, true, $user->id);
$basedata->completion = (object) [
'state' => $completiondata->completionstate,
];
}
return $basedata;
}
/**
* Get all general data for the block at this context.
*
* @param \context_block $context The context to retrieve data for.
* @param \stdClass $user The user being written.
* @return \stdClass General data about this block instance.
*/
protected static function get_context_block_data(\context_block $context, \stdClass $user) : \stdClass {
global $DB;
$block = $DB->get_record('block_instances', ['id' => $context->instanceid]);
$basedata = (object) [
'blocktype' => get_string('pluginname', 'block_' . $block->blockname)
];
return $basedata;
}
/**
* Get all general data for the activity module at this context.
*
* @param \context_module $context The context to retrieve data for.
* @param \stdClass $user The user being written.
* @return \stdClass
*/
protected static function export_context_module_files(\context_module $context, \stdClass $user) {
$coursecontext = $context->get_course_context();
$modinfo = get_fast_modinfo($coursecontext->instanceid);
$cm = $modinfo->cms[$context->instanceid];
$component = "mod_{$cm->modname}";
writer::with_context($context)
// Export the files for the intro.
->export_area_files([], $component, 'intro', 0);
}
/**
* Handle removal of 'standard' data for course modules.
*
* This will handle deletion for things such as activity completion.
*
* @param string $component The component being deleted for.
* @param \context_module $context The context to delete all data for.
*/
public static function delete_for_context_course_module(string $component, \context_module $context) {
global $DB;
// Delete course completion data for this context.
$DB->delete_records('course_modules_completion', ['coursemoduleid' => $context->instanceid]);
}
/**
* Delete all 'standard' user data for the specified user in course modules.
*
* This will handle deletion for things such as activity completion.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
protected static function delete_user_data_for_course_module(approved_contextlist $contextlist) {
global $DB;
foreach ($contextlist as $context) {
// Delete course completion data for this context.
$DB->delete_records('course_modules_completion', [
'coursemoduleid' => $context->instanceid,
'userid' => $contextlist->get_user()->id,
]);
}
}
}
@@ -0,0 +1,320 @@
<?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/>.
/**
* This file contains the moodle format implementation of the content writer.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The moodle_content_writer is the default Moodle implementation of a content writer.
*
* It exports data to a rich tree structure using Moodle's context system,
* and produces a single zip file with all content.
*
* Objects of data are stored as JSON.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class moodle_content_writer implements content_writer {
/**
* @var string The base path on disk for this instance.
*/
protected $path = null;
/**
* @var \context The current context of the writer.
*/
protected $context = null;
/**
* @var \stored_file[] The list of files to be exported.
*/
protected $files = [];
/**
* Constructor for the content writer.
*
* Note: The writer factory must be passed.
*
* @param writer $writer The factory.
*/
public function __construct(writer $writer) {
$this->path = make_request_directory();
}
/**
* Set the context for the current item being processed.
*
* @param \context $context The context to use
*/
public function set_context(\context $context) : content_writer {
$this->context = $context;
return $this;
}
/**
* Export the supplied data within the current context, at the supplied subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stdClass $data The data to be exported
*/
public function export_data(array $subcontext, \stdClass $data) : content_writer {
$path = $this->get_path($subcontext, 'data.json');
$this->write_data($path, json_encode($data));
return $this;
}
/**
* Export metadata about the supplied subcontext.
*
* Metadata consists of a key/value pair and a description of the value.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $key The metadata name.
* @param string $value The metadata value.
* @param string $description The description of the value.
*/
public function export_metadata(array $subcontext, string $key, $value, string $description) : content_writer {
$path = $this->get_full_path($subcontext, 'metadata.json');
if (file_exists($path)) {
$data = json_decode(file_get_contents($path));
} else {
$data = (object) [];
}
$data->$key = (object) [
'value' => $value,
'description' => $description,
];
$path = $this->get_path($subcontext, 'metadata.json');
$this->write_data($path, json_encode($data));
return $this;
}
/**
* Export a piece of related data.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $name The name of the file to be exported.
* @param \stdClass $data The related data to export.
*/
public function export_related_data(array $subcontext, $name, $data) : content_writer {
$path = $this->get_path($subcontext, "{$name}.json");
$this->write_data($path, json_encode($data));
return $this;
}
/**
* Export a piece of data in a custom format.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $filename The name of the file to be exported.
* @param string $filecontent The content to be exported.
*/
public function export_custom_file(array $subcontext, $filename, $filecontent) : content_writer {
$filename = clean_param($filename, PARAM_FILE);
$path = $this->get_path($subcontext, $filename);
$this->write_data($path, $filecontent);
return $this;
}
/**
* Prepare a text area by processing pluginfile URLs within it.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
* @param string $text The text to be processed
* @return string The processed string
*/
public function rewrite_pluginfile_urls(array $subcontext, $component, $filearea, $itemid, $text) : string {
return str_replace('@@PLUGINFILE@@/', 'files/', $text);
}
/**
* Export all files within the specified component, filearea, itemid combination.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
*/
public function export_area_files(array $subcontext, $component, $filearea, $itemid) : content_writer {
$fs = get_file_storage();
$files = $fs->get_area_files($this->context->id, $component, $filearea, $itemid);
foreach ($files as $file) {
$this->export_file($subcontext, $file);
}
return $this;
}
/**
* Export the specified file in the target location.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stored_file $file The file to be exported.
*/
public function export_file(array $subcontext, \stored_file $file) : content_writer {
if (!$file->is_directory()) {
$subcontextextra = [
get_string('files'),
$file->get_filepath(),
];
$path = $this->get_path(array_merge($subcontext, $subcontextextra), $file->get_filename());
check_dir_exists(dirname($path), true, true);
$this->files[$path] = $file;
}
return $this;
}
/**
* Export the specified user preference.
*
* @param string $component The name of the component.
* @param string $key The name of th key to be exported.
* @param string $value The value of the preference
* @param string $description A description of the value
* @return content_writer
*/
public function export_user_preference(string $component, string $key, string $value, string $description) : content_writer {
if ($this->context !== \context_system::instance()) {
throw new \coding_exception('export_user_preference must be called against the system context');
}
$subcontext = [
get_string('userpreferences'),
];
$fullpath = $this->get_full_path($subcontext, "{$component}.json");
$path = $this->get_path($subcontext, "{$component}.json");
if (file_exists($fullpath)) {
$data = json_decode(file_get_contents($fullpath));
} else {
$data = (object) [];
}
$data->$key = (object) [
'value' => $value,
'description' => $description,
];
$this->write_data($path, json_encode($data));
return $this;
}
/**
* Determine the path for the current context.
*
* @return array The context path.
*/
protected function get_context_path() : Array {
$path = [];
$contexts = array_reverse($this->context->get_parent_contexts(true));
foreach ($contexts as $context) {
$path[] = clean_param($context->get_context_name(), PARAM_FILE);
}
return $path;
}
/**
* Get the relative file path within the current context, and subcontext, using the specified filename.
*
* @param string[] $subcontext The location within the current context to export this data.
* @param string $name The intended filename, including any extensions.
* @return string The fully-qualfiied file path.
*/
protected function get_path(array $subcontext, string $name) : string {
// Combine the context path, and the subcontext data.
$path = array_merge(
$this->get_context_path(),
$subcontext
);
// Join the directory together with the name.
$filepath = implode(DIRECTORY_SEPARATOR, $path) . DIRECTORY_SEPARATOR . $name;
return preg_replace('@' . DIRECTORY_SEPARATOR . '+@', DIRECTORY_SEPARATOR, $filepath);
}
/**
* Get the fully-qualified file path within the current context, and subcontext, using the specified filename.
*
* @param string[] $subcontext The location within the current context to export this data.
* @param string $name The intended filename, including any extensions.
* @return string The fully-qualfiied file path.
*/
protected function get_full_path(array $subcontext, string $name) : string {
$path = array_merge(
[$this->path],
[$this->get_path($subcontext, $name)]
);
// Join the directory together with the name.
$filepath = implode(DIRECTORY_SEPARATOR, $path);
return preg_replace('@' . DIRECTORY_SEPARATOR . '+@', DIRECTORY_SEPARATOR, $filepath);
}
/**
* Write the data to the specified path.
*
* @param string $path The path to export the data at.
* @param string $data The data to be exported.
*/
protected function write_data(string $path, string $data) {
$targetpath = $this->path . DIRECTORY_SEPARATOR . $path;
check_dir_exists(dirname($targetpath), true, true);
file_put_contents($targetpath, $data);
$this->files[$path] = $targetpath;
}
/**
* Perform any required finalisation steps and return the location of the finalised export.
*
* @return string
*/
public function finalise_content() : string {
$exportfile = make_request_directory() . '/export.zip';
$fp = get_file_packer();
$fp->archive_to_pathname($this->files, $exportfile);
// Reset the writer to prevent any further writes.
writer::reset();
return $exportfile;
}
}
@@ -0,0 +1,39 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\plugin\provider interface to describe
* a class which provides data in some form for a plugin.
*
* Plugins should implement this if they store any personal information.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request\plugin;
defined('MOODLE_INTERNAL') || die();
/**
* The provider interface for plugins which provide data from a plugin
* directly to the Privacy subsystem.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface provider extends \core_privacy\local\request\core_user_data_provider {
}
@@ -0,0 +1,42 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\plugin\subplugin_provider
* interface to describe a class which provides data in some form for the
* subplugin of another plugin.
*
* It should not be implemented directly, but should be extended by the
* plugin providing a subplugin.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request\plugin;
defined('MOODLE_INTERNAL') || die();
/**
* The subplugin_provider interface is for plugins which are sub-plugins of
* a plugin. They do not provide data directly to the core Privacy
* subsystem, but will be accessed and called via the plugin itself.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface subplugin_provider extends \core_privacy\local\request\shared_data_provider {
}
@@ -0,0 +1,54 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\plugin\subsystem_provider
* interface to describe a class which provides data in some form for a
* subsystem.
*
* It should not be implemented directly, but should be extended by the
* subsystem responsible for the plugintype.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request\plugin;
defined('MOODLE_INTERNAL') || die();
/**
* The subsystem_provider interface is for plugins which may not
* necessarily be called directly, but instead via a subsystem.
*
* One example of this is the questiontype plugintype. These are
* intrinsically linked against the question subsystem and the question
* subsystem should define an interface extending this one through which it
* can query and retrieve specific data from each questiontype as required.
*
* Each questiontype may additionally respond directly to the privacy API
* if it also impleents the \core_privacay\local\request\plugin\provider
* interface directly.
*
* Care should be taken when extending this provider to not conflict with
* the \core_privacay\local\request\plugin\provider interface.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface subsystem_provider extends \core_privacy\local\request\shared_data_provider {
}
@@ -0,0 +1,48 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\shared_data_provider interface to describe
* a class which provides data in some form.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The shared_data_provider interface is used to describe a provider which
* services user requests between components and and other components.
*
* This includes communication between subplugin, subsystems, and plugins
* which are designed to interact closely with subsystems.
*
* It does not define a specific way of doing so and different types of
* data will need to extend this interface in order to define their own
* contract.
*
* It should not be implemented directly, but should be extended by other
* interfaces in core.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
*/
interface shared_data_provider extends data_provider {
}
@@ -0,0 +1,36 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\subsystem\plugin_provider interface to describe
* a class which provides data in some form for a subsystem.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request\subsystem;
defined('MOODLE_INTERNAL') || die();
/**
* The plugin_provider interface for subsystems which provide data directly to a plugin.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
*/
interface plugin_provider extends \core_privacy\local\request\shared_data_provider {
}
@@ -0,0 +1,39 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\subsystem\provider interface to describe
* a class which provides data in some form for a subsystem.
*
* Plugins should implement this if they directly store any personal information.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request\subsystem;
defined('MOODLE_INTERNAL') || die();
/**
* The provider interface for plugins which provide data from a subsystem
* directly to the Privacy subsystem.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
*/
interface provider extends \core_privacy\local\request\core_user_data_provider {
}
@@ -0,0 +1,83 @@
<?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/>.
/**
* This file contains the core_privacy\local\request helper.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* A class containing a set of data transformations for core data types.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class transform {
/**
* Translate a userid into the standard user format for exports.
*
* We have not determined if we will do this or not, but we provide the functionality and encourgae people to use
* it so that it can be retrospectively fitted if required.
*
* @param int $userid the userid to translate
* @return mixed
*/
public static function user(int $userid) {
// For the moment we do not think we should transform as this reveals information about other users.
// However this function is implemented should the need arise in the future.
return $userid;
}
/**
* Translate a unix timestamp into a datetime string.
*
* @param int $datetime the unixtimestamp to translate.
* @return string The translated string.
*/
public static function datetime($datetime) {
return userdate($datetime, get_string('strftimedaydatetime', 'langconfig'));
}
/**
* Translate a unix timestamp into a date string.
*
* @param int $date the unixtimestamp to translate.
* @return string The translated string.
*/
public static function date($date) {
return userdate($date, get_string('strftimetime', 'langconfig'));
}
/**
* Translate a bool or int (0/1) value into a translated yes/no string.
*
* @param bool $value The value to translate
* @return string
*/
public static function yesno($value) {
if ($value) {
return get_string('yes');
} else {
return get_string('no');
}
}
}
@@ -0,0 +1,46 @@
<?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/>.
/**
* This file contains the \core_privacy\local\request\user_preference_provider interface to describe
* a class which provides preference data in some form to core.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The user_preference_provider interface is an interface designed to be
* implemented by components directly to describe a case where that
* component is responsible for storing some form of system-wide user
* preference.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface user_preference_provider extends core_data_provider {
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid);
}
+118
View File
@@ -0,0 +1,118 @@
<?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/>.
/**
* This file contains the interface required to implmeent a content writer.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\local\request;
defined('MOODLE_INTERNAL') || die();
/**
* The writer factory class used to fetch and work with the content_writer.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class writer {
/**
* @var writer The singleton instance of this writer.
*/
protected static $instance = null;
/**
* @var content_writer The current content_writer instance.
*/
protected $realwriter = null;
/**
* Constructor for the content writer.
*
* Protected to prevent direct instantiation.
*/
protected function __construct() {
}
/**
* Singleton to return or create and return a copy of a content_writer.
*
* @return content_writer
*/
protected function get_writer_instance() : content_writer {
if (null === $this->realwriter) {
if (PHPUNIT_TEST) {
$this->realwriter = new \core_privacy\tests\request\content_writer(static::instance());
} else {
$this->realwriter = new moodle_content_writer(static::instance());
}
}
return $this->realwriter;
}
/**
* Return an instance of
*/
protected static final function instance() {
if (null === self::$instance) {
self::$instance = new static();
}
return self::$instance;
}
/**
* Reset the writer and content_writer.
*/
public static final function reset() {
static::$instance = null;
}
/**
* Provide an instance of the writer with the specified context applied.
*
* @param \context $context The context to apply
* @return content_writer The content_writer
*/
public static function with_context(\context $context) : content_writer {
return static::instance()
->get_writer_instance()
->set_context($context);
}
/**
* Export the specified user preference.
*
* @param string $component The name of the component.
* @param string $key The name of th key to be exported.
* @param string $value The value of the preference
* @param string $description A description of the value
* @return content_writer
*/
public static function export_user_preference(
string $component,
string $key,
string $value,
string $description
) : content_writer {
return static::with_context(\context_system::instance())
->export_user_preference($component, $key, $value, $description);
}
}
+120
View File
@@ -0,0 +1,120 @@
<?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/>.
/**
* Testcase for providers implementing parts of the core_privacy subsystem.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\tests;
defined('MOODLE_INTERNAL') || die();
global $CFG;
/**
* Testcase for providers implementing parts of the core_privacy subsystem.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class provider_testcase extends \advanced_testcase {
/**
* Test tearDown.
*/
public function tearDown() {
\core_privacy\local\request\writer::reset();
}
/**
* Export all data for a component for the specified user.
*
* @param int $userid The userid of the user to fetch.
* @param string $component The component to get context data for.
* @return \core_privacy\local\request\contextlist
*/
public function get_contexts_for_userid(int $userid, string $component) {
$classname = $this->get_provider_classname($component);
return $classname::get_contexts_for_userid($userid);
}
/**
* Export all data for a component for the specified user.
*
* @param int $userid The userid of the user to fetch.
* @param string $component The component to get export data for.
*/
public function export_all_data_for_user(int $userid, string $component) {
$contextlist = $this->get_contexts_for_userid($userid, $component);
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
\core_user::get_user($userid),
$component,
$contextlist->get_contextids()
);
$classname = $this->get_provider_classname($component);
$classname::export_user_data($approvedcontextlist);
}
/**
* Export all daa within a context for a component for the specified user.
*
* @param int $userid The userid of the user to fetch.
* @param \context $context The context to export data for.
* @param string $component The component to get export data for.
*/
public function export_context_data_for_user(int $userid, \context $context, string $component) {
$contextlist = new \core_privacy\tests\request\approved_contextlist(
\core_user::get_user($userid),
$component,
[$context->id]
);
$classname = $this->get_provider_classname($component);
$classname::export_user_data($contextlist);
}
/**
* Determine the classname and ensure that it is a provider.
*
* @param string $component The classname.
* @return string
*/
protected function get_provider_classname($component) {
$classname = "\\${component}\\privacy\\provider";
if (!class_exists($classname)) {
throw new \coding_exception("{$component} does not implement any provider");
}
$rc = new \ReflectionClass($classname);
if (!$rc->implementsInterface(\core_privacy\local\metadata\provider::class)) {
throw new \coding_exception("{$component} does not implement metadata provider");
}
if (!$rc->implementsInterface(\core_privacy\local\request\core_user_data_provider::class)) {
throw new \coding_exception("{$component} does not declare that it provides any user data");
}
return $classname;
}
}
@@ -0,0 +1,79 @@
<?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/>.
/**
* Approved result set for unit testing.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\tests\request;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Fetch Result Set.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class approved_contextlist extends \core_privacy\local\request\approved_contextlist {
/**
* Add a single context to this approved_contextlist.
*
* @param \context $context The context to be added.
* @return $this
*/
public function add_context(\context $context) {
return $this->add_context_by_id($context->id);
}
/**
* Add a single context to this approved_contextlist by it's ID.
*
* @param int $contextid The context to be added.
* @return $this
*/
public function add_context_by_id($contextid) {
return $this->set_contextids(array_merge($this->get_contextids(), [$contextid]));
}
/**
* Add a set of contexts to this approved_contextlist.
*
* @param \context[] $contexts The contexts to be added.
* @return $this
*/
public function add_contexts(array $contexts) {
foreach ($contexts as $context) {
$this->add_context($context);
}
}
/**
* Add a set of contexts to this approved_contextlist by ID.
*
* @param int[] $contexts The contexts to be added.
* @return $this
*/
public function add_contexts_by_id(array $contexts) {
foreach ($contexts as $contextid) {
$this->add_context_by_id($contextid);
}
}
}
@@ -0,0 +1,484 @@
<?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/>.
/**
* This file contains the moodle format implementation of the content writer.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\tests\request;
defined('MOODLE_INTERNAL') || die();
/**
* An implementation of the content_writer for use in unit tests.
*
* This implementation does not export any data but instead stores it in
* structures within the instance which can be easily queried for use
* during unit tests.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class content_writer implements \core_privacy\local\request\content_writer {
/**
* @var \context The context currently being exported.
*/
protected $context = null;
/**
* @var array The collection of metadata which has been exported.
*/
protected $metadata = [];
/**
* @var array The data which has been exported.
*/
protected $data = [];
/**
* @var array The related data which has been exported.
*/
protected $relateddata = [];
/**
* @var array The list of stored files which have been exported.
*/
protected $files = [];
/**
* @var array The custom files which have been exported.
*/
protected $customfiles = [];
/**
* @var array The site-wide user preferences which have been exported.
*/
protected $userprefs = [];
/**
* Whether any data has been exported at all within the current context.
*/
public function has_any_data() {
$hasdata = !empty($this->data[$this->context->id]);
$hasrelateddata = !empty($this->relateddata[$this->context->id]);
$hasmetadata = !empty($this->metadata[$this->context->id]);
$hasfiles = !empty($this->files[$this->context->id]);
$hascustomfiles = !empty($this->customfiles[$this->context->id]);
$hasuserprefs = !empty($this->userprefs);
return $hasdata || $hasrelateddata || $hasmetadata || $hasfiles || $hascustomfiles || $hasuserprefs;
}
/**
* Constructor for the content writer.
*
* Note: The writer_factory must be passed.
* @param \core_privacy\local\request\writer $writer The writer factory.
*/
public function __construct(\core_privacy\local\request\writer $writer) {
}
/**
* Set the context for the current item being processed.
*
* @param \context $context The context to use
*/
public function set_context(\context $context) : \core_privacy\local\request\content_writer {
$this->context = $context;
if (empty($this->data[$this->context->id])) {
$this->data[$this->context->id] = [];
}
if (empty($this->relateddata[$this->context->id])) {
$this->relateddata[$this->context->id] = [];
}
if (empty($this->metadata[$this->context->id])) {
$this->metadata[$this->context->id] = [];
}
if (empty($this->files[$this->context->id])) {
$this->files[$this->context->id] = [];
}
if (empty($this->customfiles[$this->context->id])) {
$this->customfiles[$this->context->id] = [];
}
return $this;
}
/**
* Return the current context.
*
* @return \context
*/
public function get_current_context() : \context {
return $this->context;
}
/**
* Export the supplied data within the current context, at the supplied subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stdClass $data The data to be exported
*/
public function export_data(array $subcontext, \stdClass $data) : \core_privacy\local\request\content_writer {
array_push($subcontext, 'data');
$finalcontent = $data;
while ($pathtail = array_pop($subcontext)) {
$finalcontent = [
$pathtail => $finalcontent,
];
}
$this->data[$this->context->id] = array_replace_recursive($this->data[$this->context->id], $finalcontent);
return $this;
}
/**
* Get all data within the subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @return array The metadata as a series of keys to value + descrition objects.
*/
public function get_data(array $subcontext = []) {
$basepath = $this->data[$this->context->id];
while ($subpath = array_shift($subcontext)) {
if (isset($basepath[$subpath])) {
$basepath = $basepath[$subpath];
} else {
return [];
}
}
if (isset($basepath['data'])) {
return $basepath['data'];
} else {
return [];
}
}
/**
* Export metadata about the supplied subcontext.
*
* Metadata consists of a key/value pair and a description of the value.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $key The metadata name.
* @param string $value The metadata value.
* @param string $description The description of the value.
* @return $this
*/
public function export_metadata(array $subcontext,
string $key,
$value,
string $description
) : \core_privacy\local\request\content_writer {
array_push($subcontext, 'metadata');
$finalcontent = [
$key => (object) [
'value' => $value,
'description' => $description,
],
];
while ($pathtail = array_pop($subcontext)) {
$finalcontent = [
$pathtail => $finalcontent,
];
}
$this->metadata[$this->context->id] = array_replace_recursive($this->metadata[$this->context->id], $finalcontent);
return $this;
}
/**
* Get all metadata within the subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @return array The metadata as a series of keys to value + descrition objects.
*/
public function get_all_metadata(array $subcontext = []) {
$basepath = $this->metadata[$this->context->id];
while ($subpath = array_shift($subcontext)) {
if (isset($basepath[$subpath])) {
$basepath = $basepath[$subpath];
}
}
if (isset($basepath['metadata'])) {
return $basepath['metadata'];
} else {
return [];
}
}
/**
* Get the specified metadata within the subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $key The metadata to be fetched within the context + subcontext.
* @param boolean $valueonly Whether to fetch only the value, rather than the value + description.
* @return array The metadata as a series of keys to value + descrition objects.
*/
public function get_metadata(array $subcontext = [], $key, $valueonly = true) {
$data = $this->get_all_metadata($subcontext);
if (!isset($data[$key])) {
return null;
}
$metadata = $data[$key];
if ($valueonly) {
return $metadata->value;
} else {
return $metadata;
}
}
/**
* Export a piece of related data.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $name The name of the file to be exported.
* @param \stdClass $data The related data to export.
*/
public function export_related_data(array $subcontext, $name, $data) : \core_privacy\local\request\content_writer {
array_push($subcontext, $name);
array_push($subcontext, 'data');
$finalcontent = $data;
while ($pathtail = array_pop($subcontext)) {
$finalcontent = [
$pathtail => $finalcontent,
];
}
$this->relateddata[$this->context->id] = array_replace_recursive($this->relateddata[$this->context->id], $finalcontent);
return $this;
}
/**
* Get all data within the subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $filename The name of the intended filename.
* @return array The metadata as a series of keys to value + descrition objects.
*/
public function get_related_data(array $subcontext = [], $filename) {
$basepath = $this->relateddata[$this->context->id];
$subcontext[] = $filename;
while ($subpath = array_shift($subcontext)) {
if (isset($basepath[$subpath])) {
$basepath = $basepath[$subpath];
} else {
return [];
}
}
if (isset($basepath['data'])) {
return $basepath['data'];
} else {
return [];
}
}
/**
* Export a piece of data in a custom format.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $filename The name of the file to be exported.
* @param string $filecontent The content to be exported.
*/
public function export_custom_file(array $subcontext, $filename, $filecontent) : \core_privacy\local\request\content_writer {
$filename = clean_param($filename, PARAM_FILE);
$finalcontent = [
$filename => $filecontent,
];
while ($pathtail = array_pop($subcontext)) {
$finalcontent = [
$pathtail => $finalcontent,
];
}
$this->customfiles[$this->context->id] = array_replace_recursive($this->customfiles[$this->context->id], $finalcontent);
return $this;
}
/**
* Get the specified custom file within the subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $filename The name of the file to be fetched within the context + subcontext.
* @return string The content of the file.
*/
public function get_custom_file(array $subcontext = [], $filename = null) {
if (!empty($filename)) {
array_push($subcontext, $filename);
}
$basepath = $this->customfiles[$this->context->id];
while ($subpath = array_shift($subcontext)) {
if (isset($basepath[$subpath])) {
$basepath = $basepath[$subpath];
}
}
return $basepath;
}
/**
* Prepare a text area by processing pluginfile URLs within it.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
* @param string $text The text to be processed
* @return string The processed string
*/
public function rewrite_pluginfile_urls(array $subcontext, $component, $filearea, $itemid, $text) : string {
return str_replace('@@PLUGINFILE@@/', 'files/', $text);
}
/**
* Export all files within the specified component, filearea, itemid combination.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param string $component The name of the component that the files belong to.
* @param string $filearea The filearea within that component.
* @param string $itemid Which item those files belong to.
*/
public function export_area_files(array $subcontext, $component, $filearea, $itemid) : \core_privacy\local\request\content_writer {
$fs = get_file_storage();
$files = $fs->get_area_files($this->context->id, $component, $filearea, $itemid);
foreach ($files as $file) {
$this->export_file($subcontext, $file);
}
return $this;
}
/**
* Export the specified file in the target location.
*
* @param array $subcontext The location within the current context that this data belongs.
* @param \stored_file $file The file to be exported.
*/
public function export_file(array $subcontext, \stored_file $file) : \core_privacy\local\request\content_writer {
if (!$file->is_directory()) {
$subcontextextra = [
'files',
$file->get_filepath(),
];
$newsubcontext = array_merge($subcontext, $subcontextextra);
$finalcontent = [
$file,
];
while ($pathtail = array_pop($subcontext)) {
$finalcontent = [
$pathtail => $finalcontent,
];
}
$this->customfiles[$this->context->id] = array_replace_recursive($this->customfiles[$this->context->id], $finalcontent);
}
return $this;
}
/**
* Get all files in the specfied subcontext.
*
* @param array $subcontext The location within the current context that this data belongs.
* @return \stored_file[] The list of stored_files in this context + subcontext.
*/
public function get_files(array $subcontext = []) {
$basepath = $this->files[$this->context->id];
while ($subpath = array_shift($subcontext)) {
if (isset($basepath[$subpath])) {
$basepath = $basepath[$subpath];
}
}
return $basepath;
}
/**
* Export the specified user preference.
*
* @param string $component The name of the component.
* @param string $key The name of th key to be exported.
* @param string $value The value of the preference
* @param string $description A description of the value
* @return \core_privacy\local\request\content_writer
*/
public function export_user_preference(
string $component,
string $key,
string $value,
string $description
) : \core_privacy\local\request\content_writer {
if (!isset($this->userprefs[$component])) {
$this->userprefs[$component] = (object) [];
}
$this->userprefs[$component]->$key = (object) [
'value' => $value,
'description' => $description,
];
return $this;
}
/**
* Get all user preferences for the specified component.
*
* @param string $component The name of the component.
* @return \stdClass
*/
public function get_user_preferences(string $component) {
if (isset($this->userprefs[$component])) {
return $this->userprefs[$component];
} else {
return (object) [];
}
}
/**
* Perform any required finalisation steps and return the location of the finalised export.
*
* @return string
*/
public function finalise_content() : string {
return 'mock_path';
}
}
@@ -0,0 +1,58 @@
<?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 approved contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\approved_contextlist;
/**
* Tests for the \core_privacy API's approved contextlist functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class approved_contextlist_test extends advanced_testcase {
/**
* The approved contextlist should not be modifiable once set.
*/
public function test_default_values_set() {
$testuser = \core_user::get_user_by_username('admin');
$contextids = [3, 2, 1];
$component = 'core_privacy';
$uit = new approved_contextlist($testuser, $component, $contextids);
$this->assertEquals($testuser, $uit->get_user());
$this->assertEquals($component, $uit->get_component());
$result = $uit->get_contextids();
// Note: Array order is not guaranteed and should not matter.
foreach ($contextids as $contextid) {
$this->assertNotFalse(array_search($contextid, $result));
}
}
}
+211
View File
@@ -0,0 +1,211 @@
<?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/>.
/**
* Collection unit tests.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\collection;
use \core_privacy\local\metadata\types;
/**
* Tests for the \core_privacy API's collection functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_collection extends advanced_testcase {
/**
* Test that adding an unknown type causes the type to be added to the collection.
*/
public function test_add_type_generic_type() {
$collection = new collection('core_privacy');
// Mock a new types\type.
$mockedtype = $this->createMock(types\type::class);
$collection->add_type($mockedtype);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$this->assertEquals($mockedtype, reset($items));
}
/**
* Test that adding a known type works as anticipated.
*/
public function test_add_type_known_type() {
$collection = new collection('core_privacy');
$linked = new types\subsystem_link('example', 'langstring');
$collection->add_type($linked);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$this->assertEquals($linked, reset($items));
}
/**
* Test that adding multiple types returns them all.
*/
public function test_add_type_multiple() {
$collection = new collection('core_privacy');
$a = new types\subsystem_link('example', 'langstring');
$collection->add_type($a);
$b = new types\subsystem_link('example', 'langstring');
$collection->add_type($b);
$items = $collection->get_collection();
$this->assertCount(2, $items);
}
/**
* Test that the add_database_table function adds a database table.
*/
public function test_add_database_table() {
$collection = new collection('core_privacy');
$name = 'example';
$fields = ['field' => 'description'];
$summary = 'summarisation';
$collection->add_database_table($name, $fields, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\database_table::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($fields, $item->get_privacy_fields());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the add_user_preference function adds a single user preference.
*/
public function test_add_user_preference() {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->add_user_preference($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\user_preference::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_external_location function links an external location.
*/
public function test_link_external_location() {
$collection = new collection('core_privacy');
$name = 'example';
$fields = ['field' => 'description'];
$summary = 'summarisation';
$collection->link_external_location($name, $fields, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\external_location::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($fields, $item->get_privacy_fields());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_subsystem function links the subsystem.
*/
public function test_link_subsystem() {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->link_subsystem($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\subsystem_link::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_plugintype function links the plugin.
*/
public function test_link_plugintype() {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->link_plugintype($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\plugintype_link::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Data provider to supply a list of valid components.
*
* @return array
*/
public function component_list_provider() {
return [
['core_privacy'],
['mod_forum'],
];
}
/**
* Test that we can get the component correctly.
*
* The component will be used for string translations.
*
* @dataProvider component_list_provider
* @param string $component The component to test
*/
public function test_get_component($component) {
$collection = new collection($component);
$this->assertEquals($component, $collection->get_component());
}
}
+162
View File
@@ -0,0 +1,162 @@
<?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 abstract contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist_base;
/**
* Tests for the \core_privacy API's contextlist base functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist_base_test extends advanced_testcase {
/**
* Ensure that get_contextids returns the list of unique contextids.
*
* @dataProvider get_contextids_provider
* @param array $input List of context IDs
* @param array $expected list of contextids
* @param int $count Expected count
*/
public function test_get_contextids($input, $expected, $count) {
$uit = new test_contextlist_base();
$uit->set_contextids($input);
$result = $uit->get_contextids();
$this->assertCount($count, $result);
// Note: Array order is not guaranteed and should not matter.
foreach ($expected as $contextid) {
$this->assertNotFalse(array_search($contextid, $result));
}
}
/**
* Provider for the list of contextids.
*
* @return array
*/
public function get_contextids_provider() {
return [
'basic' => [
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'duplicates' => [
[1, 1, 2, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'Mixed order with duplicates' => [
[5, 4, 2, 5, 4, 1, 3, 4, 1, 5, 5, 5, 2, 4, 1, 2],
[1, 2, 3, 4, 5],
5,
],
];
}
/**
* Ensure that get_contexts returns the correct list of contexts.
*/
public function test_get_contexts() {
global $DB;
$contexts = [];
$contexts[] = \context_system::instance();
$contexts[] = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$ids = [];
foreach ($contexts as $context) {
$ids[] = $context->id;
}
$uit = new test_contextlist_base();
$uit->set_contextids($ids);
$result = $uit->get_contexts();
$this->assertCount(count($contexts), $result);
foreach ($contexts as $context) {
$this->assertNotFalse(array_search($context, $result));
}
}
/**
* Ensure that the contextlist_base is countable.
*
* @dataProvider get_contextids_provider
* @param array $input List of context IDs
* @param array $expected list of contextids
* @param int $count Expected count
*/
public function test_countable($input, $expected, $count) {
$uit = new test_contextlist_base();
$uit->set_contextids($input);
$this->assertCount($count, $uit);
}
/**
* Ensure that the contextlist_base iterates over the set of contexts.
*/
public function test_context_iteration() {
global $DB;
$allcontexts = $DB->get_records('context');
$contexts = [];
foreach ($allcontexts as $context) {
$contexts[] = \context::instance_by_id($context->id);
}
$uit = new test_contextlist_base();
$uit->set_contextids(array_keys($allcontexts));
foreach ($uit as $key => $context) {
$this->assertNotFalse(array_search($context, $contexts));
}
}
}
/**
* A test class extending the contextlist_base allowing setting of the
* contextids.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_contextlist_base extends contextlist_base {
/**
* Set the contextids for the test class.
*
* @param int[] $contexids The list of contextids to use.
*/
public function set_contextids(array $contextids) {
parent::set_contextids($contextids);
}
}
@@ -0,0 +1,175 @@
<?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 a the collection of contextlists class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist_collection;
use \core_privacy\local\request\contextlist;
use \core_privacy\local\request\approved_contextlist;
/**
* Tests for the \core_privacy API's contextlist collection functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist_collection_test extends advanced_testcase {
/**
* A contextlist_collection should support the contextlist type.
*/
public function test_supports_contextlist() {
$uit = new contextlist_collection(1);
$contextlist = new contextlist();
$contextlist->set_component('core_privacy');
$uit->add_contextlist($contextlist);
$this->assertCount(1, $uit->get_contextlists());
}
/**
* A contextlist_collection should support the approved_contextlist type.
*/
public function test_supports_approved_contextlist() {
$uit = new contextlist_collection(1);
$testuser = \core_user::get_user_by_username('admin');
$contextids = [3, 2, 1];
$uit->add_contextlist(new approved_contextlist($testuser, 'core_privacy', $contextids));
$this->assertCount(1, $uit->get_contextlists());
}
/**
* Ensure that get_contextlist_for_component returns the correct contextlist.
*/
public function test_get_contextlist_for_component() {
$uit = new contextlist_collection(1);
$coretests = new contextlist();
$coretests->set_component('core_tests');
$uit->add_contextlist($coretests);
$coreprivacy = new contextlist();
$coreprivacy->set_component('core_privacy');
$uit->add_contextlist($coreprivacy);
// Note: This uses assertSame rather than assertEquals.
// The former checks the actual object, whilst assertEquals only checks that they look the same.
$this->assertSame($coretests, $uit->get_contextlist_for_component('core_tests'));
$this->assertSame($coreprivacy, $uit->get_contextlist_for_component('core_privacy'));
}
/**
* Ensure that get_contextlist_for_component does not die horribly when querying a non-existent component.
*/
public function test_get_contextlist_for_component_not_found() {
$uit = new contextlist_collection(1);
$this->assertNull($uit->get_contextlist_for_component('core_tests'));
}
/**
* Ensure that a duplicate contextlist in the collection throws an Exception.
*/
public function test_duplicate_addition_throws() {
$uit = new contextlist_collection(1);
$coretests = new contextlist();
$coretests->set_component('core_tests');
$uit->add_contextlist($coretests);
$this->expectException('moodle_exception');
$uit->add_contextlist($coretests);
}
/**
* Ensure that the contextlist_collection is countable.
*/
public function test_countable() {
$uit = new contextlist_collection(1);
$contextlist = new contextlist();
$contextlist->set_component('test_example');
$uit->add_contextlist($contextlist);
$contextlist = new contextlist();
$contextlist->set_component('test_another');
$uit->add_contextlist($contextlist);
$this->assertCount(2, $uit);
}
/**
* Ensure that the contextlist_collection iterates over the set of contextlists.
*/
public function test_iteration() {
$uit = new contextlist_collection(1);
$testdata = [];
$component = 'test_example';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
$component = 'test_another';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
$component = 'test_third';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
foreach ($uit as $component => $list) {
$this->assertEquals($testdata[$component], $list);
}
$this->assertCount(3, $uit);
}
/**
* Test that the userid is correctly returned.
*/
public function test_get_userid() {
$uit = new contextlist_collection(1);
$this->assertEquals(1, $uit->get_userid());
}
/**
* Test that an exception is thrown if a contextlist does not contain a component.
*/
public function test_add_without_component() {
$uit = new contextlist_collection(1);
$this->expectException(moodle_exception::class);
$uit->add_contextlist(new contextlist());
}
}
+55
View File
@@ -0,0 +1,55 @@
<?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 approved contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist;
/**
* Tests for the \core_privacy API's approved contextlist functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist_test extends advanced_testcase {
/**
* Ensure that valid SQL results in the relevant contexts being added.
*/
public function test_add_from_sql() {
global $DB;
$sql = "SELECT c.id FROM {context} c";
$params = [];
$allcontexts = $DB->get_records_sql($sql, $params);
$uit = new contextlist();
$uit->add_from_sql($sql, $params);
$this->assertCount(count($allcontexts), $uit);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?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 request deletion criteria.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\deletion_criteria;
/**
* Tests for the \core_privacy API's request deletion criteria class.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class deletion_criteria_test extends advanced_testcase {
/**
* The get_context function should return the entered context.
*/
public function test_get_context() {
$context = \context_system::instance();
$uit = new deletion_criteria($context);
$this->assertSame($context, $uit->get_context());
}
/**
* The get_context function should return the entered context.
*/
public function test_get_context_user_context() {
$context = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$uit = new deletion_criteria($context);
$this->assertSame($context, $uit->get_context());
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1,747 @@
<?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 Moodle Content Writer.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\moodle_content_writer;
/**
* Tests for the \core_privacy API's moodle_content_writer functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class moodle_content_writer_test extends advanced_testcase {
/**
* Test that exported data is saved correctly within the system context.
*
* @dataProvider export_data_provider
* @param \stdClass $data Data
*/
public function test_export_data($data) {
$context = \context_system::instance();
$subcontext = [];
$writer = $this->get_writer_instance()
->set_context($context)
->export_data($subcontext, $data);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, $subcontext, 'data.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertEquals($data, $expanded);
}
/**
* Test that exported data is saved correctly for context/subcontext.
*
* @dataProvider export_data_provider
* @param \stdClass $data Data
*/
public function test_export_data_different_context($data) {
$context = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$subcontext = ['sub', 'context'];
$writer = $this->get_writer_instance()
->set_context($context)
->export_data($subcontext, $data);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, $subcontext, 'data.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertEquals($data, $expanded);
}
/**
* Test that exported is saved within the correct directory locations.
*/
public function test_export_data_writes_to_multiple_context() {
$subcontext = ['sub', 'context'];
$systemcontext = \context_system::instance();
$systemdata = (object) [
'belongsto' => 'system',
];
$usercontext = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$userdata = (object) [
'belongsto' => 'user',
];
$writer = $this->get_writer_instance();
$writer
->set_context($systemcontext)
->export_data($subcontext, $systemdata);
$writer
->set_context($usercontext)
->export_data($subcontext, $userdata);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($systemcontext, $subcontext, 'data.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertEquals($systemdata, $expanded);
$contextpath = $this->get_context_path($usercontext, $subcontext, 'data.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertEquals($userdata, $expanded);
}
/**
* Test that multiple writes to the same location cause the latest version to be written.
*/
public function test_export_data_multiple_writes_same_context() {
$subcontext = ['sub', 'context'];
$systemcontext = \context_system::instance();
$originaldata = (object) [
'belongsto' => 'system',
];
$newdata = (object) [
'abc' => 'def',
];
$writer = $this->get_writer_instance();
$writer
->set_context($systemcontext)
->export_data($subcontext, $originaldata);
$writer
->set_context($systemcontext)
->export_data($subcontext, $newdata);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($systemcontext, $subcontext, 'data.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertEquals($newdata, $expanded);
}
/**
* Data provider for exporting user data.
*/
public function export_data_provider() {
return [
'basic' => [
(object) [
'example' => (object) [
'key' => 'value',
],
],
],
];
}
/**
* Test that metadata can be set.
*
* @dataProvider export_metadata_provider
* @param string $key Key
* @param string $value Value
* @param string $description Description
*/
public function test_export_metadata($key, $value, $description) {
$context = \context_system::instance();
$subcontext = ['a', 'b', 'c'];
$writer = $this->get_writer_instance()
->set_context($context)
->export_metadata($subcontext, $key, $value, $description);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, $subcontext, 'metadata.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->$key));
$this->assertEquals($value, $expanded->$key->value);
$this->assertEquals($description, $expanded->$key->description);
}
/**
* Test that metadata can be set additively.
*/
public function test_export_metadata_additive() {
$context = \context_system::instance();
$subcontext = [];
$writer = $this->get_writer_instance();
$writer
->set_context($context)
->export_metadata($subcontext, 'firstkey', 'firstvalue', 'firstdescription');
$writer
->set_context($context)
->export_metadata($subcontext, 'secondkey', 'secondvalue', 'seconddescription');
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, $subcontext, 'metadata.json');
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->firstkey));
$this->assertEquals('firstvalue', $expanded->firstkey->value);
$this->assertEquals('firstdescription', $expanded->firstkey->description);
$this->assertTrue(isset($expanded->secondkey));
$this->assertEquals('secondvalue', $expanded->secondkey->value);
$this->assertEquals('seconddescription', $expanded->secondkey->description);
}
/**
* Test that metadata can be set additively.
*/
public function test_export_metadata_to_multiple_contexts() {
$systemcontext = \context_system::instance();
$usercontext = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$subcontext = [];
$writer = $this->get_writer_instance();
$writer
->set_context($systemcontext)
->export_metadata($subcontext, 'firstkey', 'firstvalue', 'firstdescription')
->export_metadata($subcontext, 'secondkey', 'secondvalue', 'seconddescription');
$writer
->set_context($usercontext)
->export_metadata($subcontext, 'firstkey', 'alternativevalue', 'alternativedescription')
->export_metadata($subcontext, 'thirdkey', 'thirdvalue', 'thirddescription');
$fileroot = $this->fetch_exported_content($writer);
$systemcontextpath = $this->get_context_path($systemcontext, $subcontext, 'metadata.json');
$this->assertTrue($fileroot->hasChild($systemcontextpath));
$json = $fileroot->getChild($systemcontextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->firstkey));
$this->assertEquals('firstvalue', $expanded->firstkey->value);
$this->assertEquals('firstdescription', $expanded->firstkey->description);
$this->assertTrue(isset($expanded->secondkey));
$this->assertEquals('secondvalue', $expanded->secondkey->value);
$this->assertEquals('seconddescription', $expanded->secondkey->description);
$this->assertFalse(isset($expanded->thirdkey));
$usercontextpath = $this->get_context_path($usercontext, $subcontext, 'metadata.json');
$this->assertTrue($fileroot->hasChild($usercontextpath));
$json = $fileroot->getChild($usercontextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->firstkey));
$this->assertEquals('alternativevalue', $expanded->firstkey->value);
$this->assertEquals('alternativedescription', $expanded->firstkey->description);
$this->assertFalse(isset($expanded->secondkey));
$this->assertTrue(isset($expanded->thirdkey));
$this->assertEquals('thirdvalue', $expanded->thirdkey->value);
$this->assertEquals('thirddescription', $expanded->thirdkey->description);
}
/**
* Data provider for exporting user metadata.
*
* return array
*/
public function export_metadata_provider() {
return [
'basic' => [
'key',
'value',
'This is a description',
],
'valuewithspaces' => [
'key',
'value has mixed',
'This is a description',
],
'encodedvalue' => [
'key',
base64_encode('value has mixed'),
'This is a description',
],
];
}
/**
* Exporting a single stored_file should cause that file to be output in the files directory.
*/
public function test_export_area_files() {
$this->resetAfterTest();
$context = \context_system::instance();
$fs = get_file_storage();
// Add two files to core_privacy::tests::0.
$files = [];
$file = (object) [
'component' => 'core_privacy',
'filearea' => 'tests',
'itemid' => 0,
'path' => '/',
'name' => 'a.txt',
'content' => 'Test file 0',
];
$files[] = $file;
$file = (object) [
'component' => 'core_privacy',
'filearea' => 'tests',
'itemid' => 0,
'path' => '/',
'name' => 'b.txt',
'content' => 'Test file 1',
];
$files[] = $file;
// One with a different itemid.
$file = (object) [
'component' => 'core_privacy',
'filearea' => 'tests',
'itemid' => 1,
'path' => '/',
'name' => 'c.txt',
'content' => 'Other',
];
$files[] = $file;
// One with a different filearea.
$file = (object) [
'component' => 'core_privacy',
'filearea' => 'alternative',
'itemid' => 0,
'path' => '/',
'name' => 'd.txt',
'content' => 'Alternative',
];
$files[] = $file;
// One with a different component.
$file = (object) [
'component' => 'core',
'filearea' => 'tests',
'itemid' => 0,
'path' => '/',
'name' => 'e.txt',
'content' => 'Other tests',
];
$files[] = $file;
foreach ($files as $file) {
$record = [
'contextid' => $context->id,
'component' => $file->component,
'filearea' => $file->filearea,
'itemid' => $file->itemid,
'filepath' => $file->path,
'filename' => $file->name,
];
$file->namepath = $file->path . $file->name;
$file->storedfile = $fs->create_file_from_string($record, $file->content);
}
$writer = $this->get_writer_instance()
->set_context($context)
->export_area_files([], 'core_privacy', 'tests', 0);
$fileroot = $this->fetch_exported_content($writer);
$firstfiles = array_slice($files, 0, 2);
foreach ($firstfiles as $file) {
$contextpath = $this->get_context_path($context, [get_string('files')], $file->namepath);
$this->assertTrue($fileroot->hasChild($contextpath));
$this->assertEquals($file->content, $fileroot->getChild($contextpath)->getContent());
}
$otherfiles = array_slice($files, 2);
foreach ($otherfiles as $file) {
$contextpath = $this->get_context_path($context, [get_string('files')], $file->namepath);
$this->assertFalse($fileroot->hasChild($contextpath));
}
}
/**
* Exporting a single stored_file should cause that file to be output in the files directory.
*
* @dataProvider export_file_provider
* @param string $filepath File path
* @param string $filename File name
* @param string $content Content
*/
public function test_export_file($filepath, $filename, $content) {
$this->resetAfterTest();
$context = \context_system::instance();
$filenamepath = $filepath . $filename;
$filerecord = array(
'contextid' => $context->id,
'component' => 'core_privacy',
'filearea' => 'tests',
'itemid' => 0,
'filepath' => $filepath,
'filename' => $filename,
);
$fs = get_file_storage();
$file = $fs->create_file_from_string($filerecord, $content);
$writer = $this->get_writer_instance()
->set_context($context)
->export_file([], $file);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, [get_string('files')], $filenamepath);
$this->assertTrue($fileroot->hasChild($contextpath));
$this->assertEquals($content, $fileroot->getChild($contextpath)->getContent());
}
/**
* Data provider for the test_export_file function.
*
* @return array
*/
public function export_file_provider() {
return [
'basic' => [
'/',
'testfile.txt',
'An example file content',
],
'longpath' => [
'/path/within/a/path/within/a/path/',
'testfile.txt',
'An example file content',
],
'pathwithspaces' => [
'/path with/some spaces/',
'testfile.txt',
'An example file content',
],
'filewithspaces' => [
'/path with/some spaces/',
'test file.txt',
'An example file content',
],
'image' => [
'/',
'logo.png',
file_get_contents(__DIR__ . '/fixtures/logo.png'),
],
'UTF8' => [
'/Žluťoučký/',
'koníček.txt',
'koníček',
],
'EUC-JP' => [
'/言語設定/',
'言語設定.txt',
'言語設定',
],
];
}
/**
* User preferences can not be exported against the user context.
*/
public function test_export_user_preference_context_user() {
$admin = \core_user::get_user_by_username('admin');
$writer = $this->get_writer_instance();
$this->expectException('coding_exception');
$writer->set_context(\context_user::instance($admin->id))
->export_user_preference('core_privacy', 'validkey', 'value', 'description');
}
/**
* User preferences can not be exported against the coursecat context.
*/
public function test_export_user_preference_context_coursecat() {
global $DB;
$categories = $DB->get_records('course_categories');
$firstcategory = reset($categories);
$this->expectException('coding_exception');
$this->get_writer_instance()
->set_context(\context_coursecat::instance($firstcategory->id))
->export_user_preference('core_privacy', 'validkey', 'value', 'description');
}
/**
* User preferences can not be exported against the course context.
*/
public function test_export_user_preference_context_course() {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->expectException('coding_exception');
$this->get_writer_instance()
->set_context(\context_course::instance($course->id))
->export_user_preference('core_privacy', 'validkey', 'value', 'description');
}
/**
* User preferences can not be exported against a module context.
*/
public function test_export_user_preference_context_module() {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
$this->expectException('coding_exception');
$this->get_writer_instance()
->set_context(\context_module::instance($forum->cmid))
->export_user_preference('core_privacy', 'validkey', 'value', 'description');
}
/**
* User preferences can not be exported against a block context.
*/
public function test_export_user_preference_context_block() {
global $DB;
$blocks = $DB->get_records('block_instances');
$block = reset($blocks);
$this->expectException('coding_exception');
$this->get_writer_instance()
->set_context(\context_block::instance($block->id))
->export_user_preference('core_privacy', 'validkey', 'value', 'description');
}
/**
* User preferences can be exported against the system.
*
* @dataProvider export_user_preference_provider
* @param string $component Component
* @param string $key Key
* @param string $value Value
* @param string $desc Description
*/
public function test_export_user_preference_context_system($component, $key, $value, $desc) {
$context = \context_system::instance();
$writer = $this->get_writer_instance()
->set_context($context)
->export_user_preference($component, $key, $value, $desc);
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->$key));
$data = $expanded->$key;
$this->assertEquals($value, $data->value);
$this->assertEquals($desc, $data->description);
}
/**
* User preferences can be exported against the system.
*/
public function test_export_multiple_user_preference_context_system() {
$context = \context_system::instance();
$writer = $this->get_writer_instance();
$component = 'core_privacy';
$writer
->set_context($context)
->export_user_preference($component, 'key1', 'val1', 'desc1')
->export_user_preference($component, 'key2', 'val2', 'desc2');
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->key1));
$data = $expanded->key1;
$this->assertEquals('val1', $data->value);
$this->assertEquals('desc1', $data->description);
$this->assertTrue(isset($expanded->key2));
$data = $expanded->key2;
$this->assertEquals('val2', $data->value);
$this->assertEquals('desc2', $data->description);
}
/**
* User preferences can be exported against the system.
*/
public function test_export_user_preference_replace() {
$context = \context_system::instance();
$writer = $this->get_writer_instance();
$component = 'core_privacy';
$key = 'key';
$writer
->set_context($context)
->export_user_preference($component, $key, 'val1', 'desc1');
$writer
->set_context($context)
->export_user_preference($component, $key, 'val2', 'desc2');
$fileroot = $this->fetch_exported_content($writer);
$contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
$this->assertTrue($fileroot->hasChild($contextpath));
$json = $fileroot->getChild($contextpath)->getContent();
$expanded = json_decode($json);
$this->assertTrue(isset($expanded->$key));
$data = $expanded->$key;
$this->assertEquals('val2', $data->value);
$this->assertEquals('desc2', $data->description);
}
/**
* Provider for various user preferences.
*
* @return array
*/
public function export_user_preference_provider() {
return [
'basic' => [
'core_privacy',
'onekey',
'value',
'description',
],
'encodedvalue' => [
'core_privacy',
'donkey',
base64_encode('value'),
'description',
],
'long description' => [
'core_privacy',
'twokey',
'value',
'This is a much longer description which actually states what this is used for. Blah blah blah.',
],
];
}
/**
* Get a fresh content writer.
*
* @return moodle_content_writer
*/
public function get_writer_instance() {
$factory = $this->createMock(writer::class);
return new moodle_content_writer($factory);
}
/**
* Fetch the exported content for inspection.
*
* @param moodle_content_writer $writer
* @return \org\bovigo\vfs\vfsStreamDirectory
*/
protected function fetch_exported_content(moodle_content_writer $writer) {
$export = $writer
->set_context(\context_system::instance())
->finalise_content();
$fileroot = \org\bovigo\vfs\vfsStream::setup('root');
$target = \org\bovigo\vfs\vfsStream::url('root');
$fp = get_file_packer();
$fp->extract_to_pathname($export, $target);
return $fileroot;
}
/**
* Determine the path for the current context.
*
* Note: This is a wrapper around the real function.
*
* @param \context $context The context being written
* @param array $subcontext The subcontext path
* @param string $name THe name of the file target
* @return array The context path.
*/
protected function get_context_path($context, $subcontext = null, $name = '') {
$rc = new ReflectionClass(moodle_content_writer::class);
$writer = $this->get_writer_instance();
$writer->set_context($context);
if (null === $subcontext) {
$rcm = $rc->getMethod('get_context_path');
$rcm->setAccessible(true);
return $rcm->invoke($writer);
} else {
$rcm = $rc->getMethod('get_path');
$rcm->setAccessible(true);
return $rcm->invoke($writer, $subcontext, $name);
}
}
}
+206
View File
@@ -0,0 +1,206 @@
<?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 request helper.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\helper;
use \core_privacy\local\request\writer;
/**
* Tests for the \core_privacy API's request helper functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class request_helper_test extends advanced_testcase {
/**
* Test that basic module data is returned.
*/
public function test_get_context_data_context_module() {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$forum = $this->getDataGenerator()->create_module('forum', [
'course' => $course->id,
]);
$context = context_module::instance($forum->cmid);
$modinfo = get_fast_modinfo($course->id);
$cm = $modinfo->cms[$context->instanceid];
// Fetch the data.
$result = helper::get_context_data($context, $user);
$this->assertInstanceOf('stdClass', $result);
// Check that the name matches.
$this->assertEquals($cm->get_formatted_name(), $result->name);
// This plugin supports the intro. Check that it is included and correct.
$formattedintro = format_text($forum->intro, $forum->introformat, [
'noclean' => true,
'para' => false,
'context' => $context,
'overflowdiv' => true,
]);
$this->assertEquals($formattedintro, $result->intro);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that basic block data is returned.
*/
public function test_get_context_data_context_block() {
$this->resetAfterTest();
// Setup.
$block = $this->getDataGenerator()->create_block('online_users');
$context = context_block::instance($block->id);
$user = \core_user::get_user_by_username('admin');
// Fetch the data.
$data = helper::get_context_data($context, $user);
$this->assertEquals(get_string('pluginname', 'block_online_users'), $data->blocktype);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that a course moudle with completion tracking enabled has the completion data returned.
*/
public function test_get_context_data_context_module_completion() {
$this->resetAfterTest();
// Create a module and set completion.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
$assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'completion' => 1]);
$context = context_module::instance($assign->cmid);
$cm = get_coursemodule_from_id('assign', $assign->cmid);
// Fetch context data.
$contextdata = helper::get_context_data($context, $user);
// Completion state is zero.
// Check non completion for a user.
$this->assertEquals(0, $contextdata->completion->state);
// Complete the activity as a user.
$completioninfo = new completion_info($course);
$completioninfo->update_state($cm, COMPLETION_COMPLETE, $user->id);
// Check that completion is now exported.
$contextdata = helper::get_context_data($context, $user);
$this->assertEquals(1, $contextdata->completion->state);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are no files to export for a course module context, nothing is exported.
*/
public function test_export_context_files_context_module_no_files() {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$forum = $this->getDataGenerator()->create_module('forum', [
'course' => $course->id,
]);
$context = context_module::instance($forum->cmid);
$modinfo = get_fast_modinfo($course->id);
$cm = $modinfo->cms[$context->instanceid];
// Fetch the data.
helper::export_context_files($context, $user);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are no files to export for a course context, nothing is exported.
*/
public function test_export_context_files_context_course_no_files() {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$context = context_course::instance($course->id);
// Fetch the data.
helper::export_context_files($context, $user);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are files to export for a course context, the files are exported.
*/
public function test_export_context_files_context_course_intro_files() {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
$context = context_module::instance($assign->cmid);
// File details.
$filerecord = array(
'contextid' => $context->id,
'component' => 'mod_assign',
'filearea' => 'intro',
'itemid' => 0,
'filepath' => '/',
'filename' => 'logo.png',
);
$content = file_get_contents(__DIR__ . '/fixtures/logo.png');
// Store the file.
$fs = get_file_storage();
$file = $fs->create_file_from_string($filerecord, $content);
// Fetch the data.
helper::export_context_files($context, $user);
// This should have resulted in the file being exported.
$this->assertTrue(writer::with_context($context)->has_any_data());
}
}
+110
View File
@@ -0,0 +1,110 @@
<?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 request transform helper.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\transform;
/**
* Tests for the \core_privacy API's request transform helper functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class request_transform_test extends advanced_testcase {
/**
* Test that user translation currently does nothing.
*
* We have not determined if we will do this or not, but we provide the functionality and encourgae people to use
* it so that it can be retrospectively fitted if required.
*/
public function test_user() {
// Note: This test currently sucks, but there's no point creating users just to test this.
for ($i = 0; $i < 10; $i++) {
$this->assertEquals($i, transform::user($i));
}
}
/**
* Test that the datetime is translated into a string.
*/
public function test_datetime() {
$this->assertInternalType('string', transform::datetime(1));
}
/**
* Test that the date is translated into a string.
*/
public function test_date() {
$this->assertInternalType('string', transform::date(1));
}
/**
* Ensure that the yesno function translates correctly.
*
* @dataProvider yesno_provider
* @param mixed $input The input to test
* @param string $expected The expected value
*/
public function test_yesno($input, $expected) {
$this->assertEquals($expected, transform::yesno($input));
}
/**
* Data provider for tests of the yesno transformation.
*
* @return array
*/
public function yesno_provider() {
return [
'Bool False' => [
false,
get_string('no'),
],
'Bool true' => [
true,
get_string('yes'),
],
'Int 0' => [
0,
get_string('no'),
],
'Int 1' => [
1,
get_string('yes'),
],
'String 0' => [
'0',
get_string('no'),
],
'String 1' => [
'1',
get_string('yes'),
],
];
}
}
+144
View File
@@ -0,0 +1,144 @@
<?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/>.
/**
* Type unit tests for the Database Table.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\types\database_table;
/**
* Tests for the \core_privacy API's types\database_table functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_types_database_table extends advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_invalid_configs($name, $fields, $summary) {
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_invalid_configs_debug_normal($name, $fields, $summary) {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_valid_configs($name, $fields, $summary) {
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'privacy,foo',
],
'Space in field name' => [
'example',
[
'field' => 'This field is used for purposes.',
],
'privacy:valid',
],
'Comma in field name' => [
'example',
[
'field' => 'invalid,name',
],
'privacy:valid',
],
'No fields specified' => [
'example',
[],
'privacy:example:valid',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[
'field' => 'privacy:example:valid:field',
'field2' => 'privacy:example:valid:field2',
],
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,144 @@
<?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/>.
/**
* Type unit tests for the External Location.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\types\external_location;
/**
* Tests for the \core_privacy API's types\external_location functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_types_external_location extends advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_invalid_configs($name, $fields, $summary) {
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_invalid_configs_debug_normal($name, $fields, $summary) {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
*/
public function test_valid_configs($name, $fields, $summary) {
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'privacy,foo',
],
'Space in field name' => [
'example',
[
'field' => 'This field is used for purposes.',
],
'privacy:valid',
],
'Comma in field name' => [
'example',
[
'field' => 'invalid,name',
],
'privacy:valid',
],
'No fields specified' => [
'example',
[],
'privacy:example:valid',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[
'field' => 'privacy:example:valid:field',
'field2' => 'privacy:example:valid:field2',
],
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,111 @@
<?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/>.
/**
* Types unit tests for the Plugintype Link.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\types\plugintype_link;
/**
* Tests for the \core_privacy API's types\plugintype_link functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_types_plugintype_link extends advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs($name, $summary) {
$record = new plugintype_link($name, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs_debug_normal($name, $summary) {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new plugintype_link($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_valid_configs($name, $summary) {
$record = new plugintype_link($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
'privacy:example:valid',
],
];
}
}
+111
View File
@@ -0,0 +1,111 @@
<?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/>.
/**
* Types unit tests for the Subsystem Link.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\types\subsystem_link;
/**
* Tests for the \core_privacy API's types\subsystem_link functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_types_subsystem_link extends advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs($name, $summary) {
$record = new subsystem_link($name, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs_debug_normal($name, $summary) {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new subsystem_link($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_valid_configs($name, $summary) {
$record = new subsystem_link($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,111 @@
<?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/>.
/**
* Types unit tests for the Subsystem Link.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\metadata\types\user_preference;
/**
* Tests for the \core_privacy API's types\user_preference functionality.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_privacy_metadata_types_user_preference extends advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs($name, $summary) {
$record = new user_preference($name, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_invalid_configs_debug_normal($name, $summary) {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new user_preference($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
*/
public function test_valid_configs($name, $summary) {
$record = new user_preference($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
'privacy:example:valid',
],
];
}
}
+81
View File
@@ -0,0 +1,81 @@
<?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 Moodle Content Writer.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\writer;
/**
* Tests for the \core_privacy API's moodle_content_writer functionality.
*
* Note: The \core_privacy\tests\request\content_writer will be used for these tests.
* This content writer has additional sugar methods for fetching infromation which are not part of the standard
* content_writer interface.
*
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class writer_test extends advanced_testcase {
/**
* Test that calling with_context multiple times will return the same write instance.
*/
public function test_with_context() {
$writer = writer::with_context(\context_system::instance());
$this->assertSame($writer, writer::with_context(\context_system::instance()));
}
/**
* Test that calling with_context multiple times will return the same write instance.
*/
public function test_with_context_different_context_same_instance() {
$writer = writer::with_context(\context_system::instance());
$this->assertSame($writer, writer::with_context(\context_user::instance(\core_user::get_user_by_username('admin')->id)));
}
/**
* Test that calling writer::reset() causes a new copy of the writer to be returned.
*/
public function test_reset() {
$writer = writer::with_context(\context_system::instance());
writer::reset();
$this->assertNotSame($writer, writer::with_context(\context_system::instance()));
}
/**
* Test that the export_user_preference calls the writer against the system context.
*/
public function test_export_user_preference_sets_system_context() {
$writer = writer::with_context(\context_user::instance(\core_user::get_user_by_username('admin')->id));
writer::export_user_preference('core_test', 'key', 'value', 'description');
$this->assertSame(\context_system::instance(), $writer->get_current_context());
}
}