first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,88 @@
<?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/>.
/**
* Categories renderable.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\external\category_exporter;
/**
* Class containing the categories page renderable.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class categories extends crud_element implements renderable, templatable {
/** @var array $categories All system categories. */
protected $categories = [];
/**
* Construct this renderable.
*
* @param \tool_dataprivacy\category[] $categories
*/
public function __construct($categories) {
$this->categories = $categories;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$context = \context_system::instance();
$PAGE->requires->js_call_amd('tool_dataprivacy/categoriesactions', 'init');
$PAGE->requires->js_call_amd('tool_dataprivacy/add_category', 'getInstance', [$context->id]);
$data = new stdClass();
// Navigation links.
$data->navigation = [];
$navigationlinks = $this->get_navigation();
foreach ($navigationlinks as $navlink) {
$data->navigation[] = $navlink->export_for_template($output);
}
$data->categories = [];
foreach ($this->categories as $category) {
$exporter = new category_exporter($category, ['context' => \context_system::instance()]);
$exportedcategory = $exporter->export($output);
$actionmenu = $this->action_menu('category', $exportedcategory, $category);
$exportedcategory->actions = $actionmenu->export_for_template($output);
$data->categories[] = $exportedcategory;
}
return $data;
}
}
@@ -0,0 +1,91 @@
<?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/>.
/**
* Abstract renderer for independent renderable elements.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\external\purpose_exporter;
use tool_dataprivacy\external\category_exporter;
/**
* Abstract renderer for independent renderable elements.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class crud_element {
/**
* Returns the top navigation buttons.
*
* @return \action_link[]
*/
final protected function get_navigation() {
$back = new \action_link(
new \moodle_url('/admin/tool/dataprivacy/dataregistry.php'),
get_string('back'),
null,
['class' => 'btn btn-primary']
);
return [$back];
}
/**
* Adds an action menu for the provided element
*
* @param string $elementname 'purpose' or 'category'.
* @param \stdClass $exported
* @param \core\persistent $persistent
* @return \action_menu
*/
final protected function action_menu($elementname, $exported, $persistent) {
// Just in case, we are doing funny stuff below.
$elementname = clean_param($elementname, PARAM_ALPHA);
// Actions.
$actionmenu = new \action_menu();
$actionmenu->set_menu_trigger(get_string('actions'));
$actionmenu->set_owner_selector($elementname . '-' . $exported->id . '-actions');
$url = new \moodle_url('/admin/tool/dataprivacy/edit' . $elementname . '.php',
['id' => $exported->id]);
$link = new \action_menu_link_secondary($url, new \pix_icon('t/edit',
get_string('edit')), get_string('edit'));
$actionmenu->add($link);
if (!$persistent->is_used()) {
$url = new \moodle_url('#');
$attrs = ['data-id' => $exported->id, 'data-action' => 'delete' . $elementname, 'data-name' => $exported->name];
$link = new \action_menu_link_secondary($url, new \pix_icon('t/delete',
get_string('delete')), get_string('delete'), $attrs);
$actionmenu->add($link);
}
return $actionmenu;
}
}
@@ -0,0 +1,94 @@
<?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/>.
/**
* Class containing data for a user's data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use single_select;
use stdClass;
use templatable;
use tool_dataprivacy\data_request;
use tool_dataprivacy\local\helper;
/**
* Class containing data for a user's data requests.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_deletion_page implements renderable, templatable {
/** @var data_request[] $requests List of data requests. */
protected $filter = null;
/** @var data_request[] $requests List of data requests. */
protected $expiredcontextstable = [];
/**
* Construct this renderable.
*
* @param \tool_dataprivacy\data_request[] $filter
* @param expired_contexts_table $expiredcontextstable
*/
public function __construct($filter, expired_contexts_table $expiredcontextstable) {
$this->filter = $filter;
$this->expiredcontextstable = $expiredcontextstable;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
$url = new moodle_url('/admin/tool/dataprivacy/datadeletion.php');
$options = [
CONTEXT_USER => get_string('user'),
CONTEXT_COURSE => get_string('course'),
CONTEXT_MODULE => get_string('activitiesandresources', 'tool_dataprivacy'),
CONTEXT_BLOCK => get_string('blocks'),
];
$filterselector = new single_select($url, 'filter', $options, $this->filter, null);
$data->filter = $filterselector->export_for_template($output);
ob_start();
$this->expiredcontextstable->out(helper::DEFAULT_PAGE_SIZE, true);
$expiredcontexts = ob_get_contents();
ob_end_clean();
$data->expiredcontexts = $expiredcontexts;
$data->existingcontexts = $this->expiredcontextstable->rawdata ? true : false;
return $data;
}
}
@@ -0,0 +1,60 @@
<?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/>.
/**
* Contains the data registry compliance renderable.
*
* @package tool_dataprivacy
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
/**
* Class containing the data registry compliance renderable
*
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry_compliance_page implements renderable, templatable {
/** @var array meta-data to be displayed about the system. */
protected $metadata;
/**
* Constructor.
*
* @param array $metadata
*/
public function __construct($metadata) {
$this->metadata = $metadata;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
return ['types' => $this->metadata];
}
}
@@ -0,0 +1,475 @@
<?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/>.
/**
* Data registry renderable.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\data_registry;
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
require_once($CFG->libdir . '/blocklib.php');
/**
* Class containing the data registry renderable
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry_page implements renderable, templatable {
/**
* @var int
*/
private $defaultcontextlevel;
/**
* @var int
*/
private $defaultcontextid;
/**
* Constructor.
*
* @param int $defaultcontextlevel
* @param int $defaultcontextid
* @return null
*/
public function __construct($defaultcontextlevel = false, $defaultcontextid = false) {
$this->defaultcontextlevel = $defaultcontextlevel;
$this->defaultcontextid = $defaultcontextid;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$params = [\context_system::instance()->id, $this->defaultcontextlevel, $this->defaultcontextid];
$PAGE->requires->js_call_amd('tool_dataprivacy/data_registry', 'init', $params);
$data = new stdClass();
$defaultsbutton = new \action_link(
new \moodle_url('/admin/tool/dataprivacy/defaults.php'),
get_string('setdefaults', 'tool_dataprivacy'),
null,
['class' => 'btn btn-primary']
);
$data->defaultsbutton = $defaultsbutton->export_for_template($output);
$actionmenu = new \action_menu();
$actionmenu->set_menu_trigger(get_string('edit'), 'btn btn-primary');
$actionmenu->set_owner_selector('dataregistry-actions');
$url = new \moodle_url('/admin/tool/dataprivacy/categories.php');
$categories = new \action_menu_link_secondary($url, null, get_string('categories', 'tool_dataprivacy'));
$actionmenu->add($categories);
$url = new \moodle_url('/admin/tool/dataprivacy/purposes.php');
$purposes = new \action_menu_link_secondary($url, null, get_string('purposes', 'tool_dataprivacy'));
$actionmenu->add($purposes);
$data->actions = $actionmenu->export_for_template($output);
if (!data_registry::defaults_set()) {
$data->info = (object)[
'message' => get_string('dataregistryinfo', 'tool_dataprivacy'),
'announce' => 1
];
$data->nosystemdefaults = (object)[
'message' => get_string('nosystemdefaults', 'tool_dataprivacy'),
'announce' => 1
];
}
$data->tree = $this->get_default_tree_structure();
return $data;
}
/**
* Returns the tree default structure.
*
* @return array
*/
private function get_default_tree_structure() {
$frontpage = \context_course::instance(SITEID);
$categorybranches = $this->get_all_category_branches();
$elements = [
'text' => get_string('contextlevelname' . CONTEXT_SYSTEM, 'tool_dataprivacy'),
'contextlevel' => CONTEXT_SYSTEM,
'branches' => [
[
'text' => get_string('user'),
'contextlevel' => CONTEXT_USER,
], [
'text' => get_string('categories'),
'branches' => $categorybranches,
'expandelement' => 'category',
], [
'text' => get_string('frontpagecourse', 'tool_dataprivacy'),
'contextid' => $frontpage->id,
'branches' => [
[
'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
'expandcontextid' => $frontpage->id,
'expandelement' => 'module',
'expanded' => 0,
], [
'text' => get_string('blocks'),
'expandcontextid' => $frontpage->id,
'expandelement' => 'block',
'expanded' => 0,
],
]
]
]
];
// Returned as an array to follow a common array format.
return [self::complete($elements, $this->defaultcontextlevel, $this->defaultcontextid)];
}
/**
* Returns the hierarchy of system course categories.
*
* @return array
*/
private function get_all_category_branches() {
$categories = data_registry::get_site_categories();
$categoriesbranch = [];
while (count($categories) > 0) {
foreach ($categories as $key => $category) {
$context = \context_coursecat::instance($category->id);
$newnode = [
'text' => shorten_text(format_string($category->name, true, ['context' => $context])),
'categoryid' => $category->id,
'contextid' => $context->id,
];
if ($category->coursecount > 0) {
$newnode['branches'] = [
[
'text' => get_string('courses'),
'expandcontextid' => $context->id,
'expandelement' => 'course',
'expanded' => 0,
]
];
}
$added = false;
if ($category->parent == 0) {
// New categories root-level node.
$categoriesbranch[] = $newnode;
$added = true;
} else {
// Add the new node under the appropriate parent.
if ($this->add_to_parent_category_branch($category, $newnode, $categoriesbranch)) {
$added = true;
}
}
if ($added) {
unset($categories[$key]);
}
}
}
return $categoriesbranch;
}
/**
* Gets the courses branch for the provided category.
*
* @param \context $catcontext
* @return array
*/
public static function get_courses_branch(\context $catcontext) {
if ($catcontext->contextlevel !== CONTEXT_COURSECAT) {
throw new \coding_exception('A course category context should be provided');
}
$coursecat = \core_course_category::get($catcontext->instanceid);
$courses = $coursecat->get_courses();
$branches = [];
foreach ($courses as $course) {
$coursecontext = \context_course::instance($course->id);
$coursenode = [
'text' => shorten_text(format_string($course->shortname, true, ['context' => $coursecontext])),
'contextid' => $coursecontext->id,
'branches' => [
[
'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
'expandcontextid' => $coursecontext->id,
'expandelement' => 'module',
'expanded' => 0,
], [
'text' => get_string('blocks'),
'expandcontextid' => $coursecontext->id,
'expandelement' => 'block',
'expanded' => 0,
],
]
];
$branches[] = self::complete($coursenode);
}
return $branches;
}
/**
* Gets the modules branch for the provided course.
*
* @param \context $coursecontext
* @return array
*/
public static function get_modules_branch(\context $coursecontext) {
if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
throw new \coding_exception('A course context should be provided');
}
$branches = [];
// Using the current user.
$modinfo = get_fast_modinfo($coursecontext->instanceid);
foreach ($modinfo->get_instances() as $moduletype => $instances) {
foreach ($instances as $cm) {
if (!$cm->uservisible) {
continue;
}
$a = (object)[
'instancename' => shorten_text($cm->get_formatted_name()),
'modulename' => get_string('pluginname', 'mod_' . $moduletype),
];
$text = get_string('moduleinstancename', 'tool_dataprivacy', $a);
$branches[] = self::complete([
'text' => $text,
'contextid' => $cm->context->id,
]);
}
}
return $branches;
}
/**
* Gets the blocks branch for the provided course.
*
* @param \context $coursecontext
* @return null
*/
public static function get_blocks_branch(\context $coursecontext) {
global $DB;
if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
throw new \coding_exception('A course context should be provided');
}
$branches = [];
$children = $coursecontext->get_child_contexts();
foreach ($children as $childcontext) {
if ($childcontext->contextlevel !== CONTEXT_BLOCK) {
continue;
}
$blockinstance = block_instance_by_id($childcontext->instanceid);
$displayname = shorten_text(format_string($blockinstance->get_title(), true, ['context' => $childcontext]));
$branches[] = self::complete([
'text' => $displayname,
'contextid' => $childcontext->id,
]);
}
return $branches;
}
/**
* Adds the provided category to the categories branch.
*
* @param stdClass $category
* @param array $newnode
* @param array $categoriesbranch
* @return bool
*/
private function add_to_parent_category_branch($category, $newnode, &$categoriesbranch) {
foreach ($categoriesbranch as $key => $branch) {
if (!empty($branch['categoryid']) && $branch['categoryid'] == $category->parent) {
// It may be empty (if it does not contain courses and this is the first child cat).
if (!isset($categoriesbranch[$key]['branches'])) {
$categoriesbranch[$key]['branches'] = [];
}
$categoriesbranch[$key]['branches'][] = $newnode;
return true;
}
if (!empty($branch['branches'])) {
$parent = $this->add_to_parent_category_branch($category, $newnode, $categoriesbranch[$key]['branches']);
if ($parent) {
return true;
}
}
}
return false;
}
/**
* Completes tree nodes with default values.
*
* @param array $node
* @param int|false $currentcontextlevel
* @param int|false $currentcontextid
* @return array
*/
private static function complete($node, $currentcontextlevel = false, $currentcontextid = false) {
if (!isset($node['active'])) {
if ($currentcontextlevel && !empty($node['contextlevel']) &&
$currentcontextlevel == $node['contextlevel'] &&
empty($currentcontextid)) {
// This is the active context level, we also checked that there
// is no default contextid set.
$node['active'] = true;
} else if ($currentcontextid && !empty($node['contextid']) &&
$currentcontextid == $node['contextid']) {
$node['active'] = true;
} else {
$node['active'] = null;
}
}
if (!isset($node['branches'])) {
$node['branches'] = [];
} else {
foreach ($node['branches'] as $key => $childnode) {
$node['branches'][$key] = self::complete($childnode, $currentcontextlevel, $currentcontextid);
}
}
if (!isset($node['expandelement'])) {
$node['expandelement'] = null;
}
if (!isset($node['expandcontextid'])) {
$node['expandcontextid'] = null;
}
if (!isset($node['contextid'])) {
$node['contextid'] = null;
}
if (!isset($node['contextlevel'])) {
$node['contextlevel'] = null;
}
if (!isset($node['expanded'])) {
if (!empty($node['branches'])) {
$node['expanded'] = 1;
} else {
$node['expanded'] = 0;
}
}
return $node;
}
/**
* From a list of purpose persistents to a list of id => name purposes.
*
* @param \tool_dataprivacy\purpose[] $purposes
* @param bool $includenotset
* @param bool $includeinherit
* @return string[]
*/
public static function purpose_options($purposes, $includenotset = true, $includeinherit = true) {
$options = self::base_options($includenotset, $includeinherit);
foreach ($purposes as $purpose) {
$options[$purpose->get('id')] = $purpose->get('name');
}
return $options;
}
/**
* From a list of category persistents to a list of id => name categories.
*
* @param \tool_dataprivacy\category[] $categories
* @param bool $includenotset
* @param bool $includeinherit
* @return string[]
*/
public static function category_options($categories, $includenotset = true, $includeinherit = true) {
$options = self::base_options($includenotset, $includeinherit);
foreach ($categories as $category) {
$options[$category->get('id')] = $category->get('name');
}
return $options;
}
/**
* Base not set and inherit options.
*
* @param bool $includenotset
* @param bool $includeinherit
* @return array
*/
private static function base_options($includenotset = true, $includeinherit = true) {
$options = [];
if ($includenotset) {
$options[\tool_dataprivacy\context_instance::NOTSET] = get_string('notset', 'tool_dataprivacy');
}
if ($includeinherit) {
$options[\tool_dataprivacy\context_instance::INHERIT] = get_string('inherit', 'tool_dataprivacy');
}
return $options;
}
}
@@ -0,0 +1,96 @@
<?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/>.
/**
* Class containing data for a user's data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use dml_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use single_select;
use stdClass;
use templatable;
use tool_dataprivacy\api;
use tool_dataprivacy\local\helper;
/**
* Class containing data for a user's data requests.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_requests_page implements renderable, templatable {
/** @var data_requests_table $table The data requests table. */
protected $table;
/** @var int[] $filters The applied filters. */
protected $filters = [];
/**
* Construct this renderable.
*
* @param data_requests_table $table The data requests table.
* @param int[] $filters The applied filters.
*/
public function __construct($table, $filters) {
$this->table = $table;
$this->filters = $filters;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
$data->newdatarequesturl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php');
$data->newdatarequesturl->param('manage', true);
if (!is_https()) {
$httpwarningmessage = get_string('httpwarning', 'tool_dataprivacy');
$data->httpsite = array('message' => $httpwarningmessage, 'announce' => 1);
}
$url = new moodle_url('/admin/tool/dataprivacy/datarequests.php');
$filteroptions = helper::get_request_filter_options();
$filter = new request_filter($filteroptions, $this->filters, $url);
$data->filter = $filter->export_for_template($output);
ob_start();
$this->table->out($this->table->get_requests_per_page(), true);
$requests = ob_get_contents();
ob_end_clean();
$data->datarequests = $requests;
return $data;
}
}
@@ -0,0 +1,453 @@
<?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/>.
/**
* Contains the class used for the displaying the data requests table.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/tablelib.php');
use action_menu;
use action_menu_link_secondary;
use coding_exception;
use dml_exception;
use html_writer;
use moodle_url;
use stdClass;
use table_sql;
use tool_dataprivacy\api;
use tool_dataprivacy\external\data_request_exporter;
defined('MOODLE_INTERNAL') || die;
/**
* The class for displaying the data requests table.
*
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_requests_table extends table_sql {
/** @var int The user ID. */
protected $userid = 0;
/** @var int[] The status filters. */
protected $statuses = [];
/** @var int[] The request type filters. */
protected $types = [];
/** @var bool Whether this table is being rendered for managing data requests. */
protected $manage = false;
/** @var \tool_dataprivacy\data_request[] Array of data request persistents. */
protected $datarequests = [];
/** @var \stdClass[] List of userids and whether they have any ongoing active requests. */
protected $ongoingrequests = [];
/** @var int The number of data request to be displayed per page. */
protected $perpage;
/** @var int[] The available options for the number of data request to be displayed per page. */
protected $perpageoptions = [25, 50, 100, 250];
/** @var int[] The request creation method filters. */
protected array $creationmethods = [];
/**
* data_requests_table constructor.
*
* @param int $userid The user ID
* @param int[] $statuses
* @param int[] $types
* @param int[] $creationmethods
* @param bool $manage
* @throws coding_exception
*/
public function __construct($userid = 0, $statuses = [], $types = [], $creationmethods = [], $manage = false) {
parent::__construct('data-requests-table');
$this->userid = $userid;
$this->statuses = $statuses;
$this->types = $types;
$this->creationmethods = $creationmethods;
$this->manage = $manage;
$checkboxattrs = [
'title' => get_string('selectall'),
'data-action' => 'selectall'
];
$columnheaders = [
'select' => html_writer::checkbox('selectall', 1, false, null, $checkboxattrs),
'type' => get_string('requesttype', 'tool_dataprivacy'),
'userid' => get_string('user', 'tool_dataprivacy'),
'timecreated' => get_string('daterequested', 'tool_dataprivacy'),
'requestedby' => get_string('requestby', 'tool_dataprivacy'),
'status' => get_string('requeststatus', 'tool_dataprivacy'),
'comments' => get_string('message', 'tool_dataprivacy'),
'actions' => '',
];
$this->define_columns(array_keys($columnheaders));
$this->define_headers(array_values($columnheaders));
$this->no_sorting('select', 'actions');
}
/**
* The select column.
*
* @param stdClass $data The row data.
* @return string
* @throws \moodle_exception
* @throws coding_exception
*/
public function col_select($data) {
if ($data->status == \tool_dataprivacy\api::DATAREQUEST_STATUS_AWAITING_APPROVAL) {
if ($data->type == \tool_dataprivacy\api::DATAREQUEST_TYPE_DELETE
&& !api::can_create_data_deletion_request_for_other()) {
// Don't show checkbox if request's type is delete and user don't have permission.
return false;
}
$stringdata = [
'username' => $data->foruser->fullname,
'requesttype' => \core_text::strtolower($data->typenameshort)
];
return \html_writer::checkbox('requestids[]', $data->id, false, '',
['class' => 'selectrequests', 'title' => get_string('selectuserdatarequest',
'tool_dataprivacy', $stringdata)]);
}
}
/**
* The type column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_type($data) {
if ($this->manage) {
return $data->typenameshort;
}
return $data->typename;
}
/**
* The user column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_userid($data) {
$user = $data->foruser;
return html_writer::link($user->profileurl, $user->fullname, ['title' => get_string('viewprofile')]);
}
/**
* The context information column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_timecreated($data) {
return userdate($data->timecreated);
}
/**
* The requesting user's column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_requestedby($data) {
$user = $data->requestedbyuser;
return html_writer::link($user->profileurl, $user->fullname, ['title' => get_string('viewprofile')]);
}
/**
* The status column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_status($data) {
return html_writer::span($data->statuslabel, 'badge ' . $data->statuslabelclass);
}
/**
* The comments column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_comments($data) {
return shorten_text($data->comments, 60);
}
/**
* The actions column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_actions($data) {
global $OUTPUT;
$requestid = $data->id;
$status = $data->status;
$persistent = $this->datarequests[$requestid];
// Prepare actions.
$actions = [];
// View action.
$actionurl = new moodle_url('#');
$actiondata = [
'data-action' => 'view',
'data-requestid' => $requestid,
'data-contextid' => \context_system::instance()->id,
];
$actiontext = get_string('viewrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
switch ($status) {
case api::DATAREQUEST_STATUS_PENDING:
// Add action to mark a general enquiry request as complete.
if ($data->type == api::DATAREQUEST_TYPE_OTHERS) {
$actiondata['data-action'] = 'complete';
$nameemail = (object)[
'name' => $data->foruser->fullname,
'email' => $data->foruser->email
];
$actiondata['data-requestid'] = $data->id;
$actiondata['data-replytoemail'] = get_string('nameemail', 'tool_dataprivacy', $nameemail);
$actiontext = get_string('markcomplete', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
}
break;
case api::DATAREQUEST_STATUS_AWAITING_APPROVAL:
// Only show "Approve" and "Deny" button for deletion request if current user has permission.
if ($persistent->get('type') == api::DATAREQUEST_TYPE_DELETE &&
!api::can_create_data_deletion_request_for_other()) {
break;
}
// Approve.
$actiondata['data-action'] = 'approve';
if (get_config('tool_dataprivacy', 'allowfiltering') && $data->type == api::DATAREQUEST_TYPE_EXPORT) {
$actiontext = get_string('approverequestall', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
// Approve selected courses.
$actiontext = get_string('filterexportdata', 'tool_dataprivacy');
$actiondata = ['data-action' => 'approve-selected-courses', 'data-requestid' => $requestid,
'data-contextid' => \context_system::instance()->id];
$actions[] = new \action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
} else {
$actiontext = get_string('approverequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
}
// Deny.
$actiondata['data-action'] = 'deny';
$actiontext = get_string('denyrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
break;
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
$userid = $data->foruser->id;
$usercontext = \context_user::instance($userid, IGNORE_MISSING);
// If user has permission to view download link, show relevant action item.
if ($usercontext && api::can_download_data_request_for_user($userid, $data->requestedbyuser->id)) {
$actions[] = api::get_download_link($usercontext, $requestid);
}
break;
}
if ($this->manage) {
$canreset = $persistent->is_active() || empty($this->ongoingrequests[$data->foruser->id]->{$data->type});
$canreset = $canreset && $persistent->is_resettable();
// Prevent re-submmit deletion request if current user don't have permission.
$canreset = $canreset && ($persistent->get('type') != api::DATAREQUEST_TYPE_DELETE ||
api::can_create_data_deletion_request_for_other());
if ($canreset) {
$reseturl = new moodle_url('/admin/tool/dataprivacy/resubmitrequest.php', [
'requestid' => $requestid,
]);
$actiondata = ['data-action' => 'reset', 'data-requestid' => $requestid];
$actiontext = get_string('resubmitrequestasnew', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($reseturl, null, $actiontext, $actiondata);
}
}
$actionsmenu = new action_menu($actions);
$actionsmenu->set_menu_trigger(get_string('actions'));
$actionsmenu->set_owner_selector('request-actions-' . $requestid);
$actionsmenu->set_boundary('window');
return $OUTPUT->render($actionsmenu);
}
/**
* Query the database for results to display in the table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar.
* @throws dml_exception
* @throws coding_exception
*/
public function query_db($pagesize, $useinitialsbar = true) {
global $PAGE;
// Set dummy page total until we fetch full result set.
$this->pagesize($pagesize, $pagesize + 1);
$sort = $this->get_sql_sort();
// Get data requests from the given conditions.
$datarequests = api::get_data_requests($this->userid, $this->statuses, $this->types,
$this->creationmethods, $sort, $this->get_page_start(), $this->get_page_size());
// Count data requests from the given conditions.
$total = api::get_data_requests_count($this->userid, $this->statuses, $this->types,
$this->creationmethods);
$this->pagesize($pagesize, $total);
$this->rawdata = [];
$context = \context_system::instance();
$renderer = $PAGE->get_renderer('tool_dataprivacy');
$forusers = [];
foreach ($datarequests as $persistent) {
$this->datarequests[$persistent->get('id')] = $persistent;
$exporter = new data_request_exporter($persistent, ['context' => $context]);
$this->rawdata[] = $exporter->export($renderer);
$forusers[] = $persistent->get('userid');
}
// Fetch the list of all ongoing requests for the users currently shown.
// This is used to determine whether any non-active request can be resubmitted.
// There can only be one ongoing request of a type for each user.
$this->ongoingrequests = api::find_ongoing_request_types_for_users($forusers);
// Set initial bars.
if ($useinitialsbar) {
$this->initialbars($total > $pagesize);
}
}
/**
* Override default implementation to display a more meaningful information to the user.
*/
public function print_nothing_to_display() {
global $OUTPUT;
echo $this->render_reset_button();
$this->print_initials_bar();
if (!empty($this->statuses) || !empty($this->types)) {
$message = get_string('nodatarequestsmatchingfilter', 'tool_dataprivacy');
} else {
$message = get_string('nodatarequests', 'tool_dataprivacy');
}
echo $OUTPUT->notification($message, 'warning');
}
/**
* Override the table's show_hide_link method to prevent the show/hide links from rendering.
*
* @param string $column the column name, index into various names.
* @param int $index numerical index of the column.
* @return string HTML fragment.
*/
protected function show_hide_link($column, $index) {
return '';
}
/**
* Override the table's wrap_html_finish method in order to render the bulk actions and
* records per page options.
*/
public function wrap_html_finish() {
global $OUTPUT;
$data = new stdClass();
$data->options = [
[
'value' => 0,
'name' => ''
],
[
'value' => \tool_dataprivacy\api::DATAREQUEST_ACTION_APPROVE,
'name' => get_string('approve', 'tool_dataprivacy')
],
[
'value' => \tool_dataprivacy\api::DATAREQUEST_ACTION_REJECT,
'name' => get_string('deny', 'tool_dataprivacy')
]
];
$perpageoptions = array_combine($this->perpageoptions, $this->perpageoptions);
$perpageselect = new \single_select(new moodle_url(''), 'perpage',
$perpageoptions, get_user_preferences('tool_dataprivacy_request-perpage'), null, 'selectgroup');
$perpageselect->label = get_string('perpage', 'moodle');
$data->perpage = $OUTPUT->render($perpageselect);
echo $OUTPUT->render_from_template('tool_dataprivacy/data_requests_bulk_actions', $data);
}
/**
* Set the number of data request records to be displayed per page.
*
* @param int $perpage The number of data request records.
*/
public function set_requests_per_page(int $perpage) {
$this->perpage = $perpage;
}
/**
* Get the number of data request records to be displayed per page.
*
* @return int The number of data request records.
*/
public function get_requests_per_page(): int {
return $this->perpage;
}
/**
* Set the available options for the number of data request to be displayed per page.
*
* @param array $perpageoptions The available options for the number of data request to be displayed per page.
*/
public function set_requests_per_page_options(array $perpageoptions) {
$this->$perpageoptions = $perpageoptions;
}
/**
* Get the available options for the number of data request to be displayed per page.
*
* @return array The available options for the number of data request to be displayed per page.
*/
public function get_requests_per_page_options(): array {
return $this->perpageoptions;
}
}
@@ -0,0 +1,178 @@
<?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/>.
/**
* Class containing data for the data registry defaults.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use action_menu_link_primary;
use coding_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\data_registry;
use tool_dataprivacy\external\category_exporter;
use tool_dataprivacy\external\purpose_exporter;
/**
* Class containing data for the data registry defaults.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class defaults_page implements renderable, templatable {
/** @var int $mode The display mode. */
protected $mode = null;
/** @var int $category The default category for the given mode. */
protected $category = null;
/** @var int $purpose The default purpose for the given mode. */
protected $purpose = null;
/** @var stdClass[] $otherdefaults Other defaults for the given mode. */
protected $otherdefaults = [];
/** @var bool $canedit Whether editing is allowed. */
protected $canedit = false;
/**
* Construct this renderable.
*
* @param int $mode The display mode.
* @param int $category The default category for the given mode.
* @param int $purpose The default purpose for the given mode.
* @param stdClass[] $otherdefaults Other defaults for the given mode.
* @param bool $canedit Whether editing is allowed.
*/
public function __construct($mode, $category, $purpose, $otherdefaults = [], $canedit = false) {
$this->mode = $mode;
$this->category = $category;
$this->purpose = $purpose;
$this->otherdefaults = $otherdefaults;
$this->canedit = $canedit;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
// Set tab URLs.
$coursecaturl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSECAT]);
$courseurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSE]);
$moduleurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_MODULE]);
$blockurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_BLOCK]);
$data->coursecaturl = $coursecaturl;
$data->courseurl = $courseurl;
$data->moduleurl = $moduleurl;
$data->blockurl = $blockurl;
// Set display mode.
switch ($this->mode) {
case CONTEXT_COURSECAT:
$data->modecoursecat = true;
break;
case CONTEXT_COURSE:
$data->modecourse = true;
break;
case CONTEXT_MODULE:
$data->modemodule = true;
break;
case CONTEXT_BLOCK:
$data->modeblock = true;
break;
default:
$data->modecoursecat = true;
break;
}
// Set config variables.
$configname = \context_helper::get_class_for_level($this->mode);
list($purposevar, $categoryvar) = data_registry::var_names_from_context($configname);
$data->categoryvar = $categoryvar;
$data->purposevar = $purposevar;
// Set default category.
$data->categoryid = $this->category;
$data->category = category_exporter::get_name($this->category);
// Set default purpose.
$data->purposeid = $this->purpose;
$data->purpose = purpose_exporter::get_name($this->purpose);
// Set other defaults.
$otherdefaults = [];
$url = new moodle_url('#');
foreach ($this->otherdefaults as $pluginname => $values) {
$defaults = [
'name' => $values->name,
'category' => category_exporter::get_name($values->category),
'purpose' => purpose_exporter::get_name($values->purpose),
];
if ($this->canedit) {
$actions = [];
// Edit link.
$editattrs = [
'data-action' => 'edit-activity-defaults',
'data-contextlevel' => $this->mode,
'data-activityname' => $pluginname,
'data-category' => $values->category,
'data-purpose' => $values->purpose,
];
$editlink = new action_menu_link_primary($url, new \pix_icon('t/edit', get_string('edit')),
get_string('edit'), $editattrs);
$actions[] = $editlink->export_for_template($output);
// Delete link.
$deleteattrs = [
'data-action' => 'delete-activity-defaults',
'data-contextlevel' => $this->mode,
'data-activityname' => $pluginname,
'data-activitydisplayname' => $values->name,
];
$deletelink = new action_menu_link_primary($url, new \pix_icon('t/delete', get_string('delete')),
get_string('delete'), $deleteattrs);
$actions[] = $deletelink->export_for_template($output);
$defaults['actions'] = $actions;
}
$otherdefaults[] = (object)$defaults;
}
$data->otherdefaults = $otherdefaults;
$data->canedit = $this->canedit;
$data->contextlevel = $this->mode;
return $data;
}
}
@@ -0,0 +1,410 @@
<?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/>.
/**
* Contains the class used for the displaying the expired contexts table.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/tablelib.php');
use coding_exception;
use context_helper;
use dml_exception;
use Exception;
use html_writer;
use pix_icon;
use stdClass;
use table_sql;
use tool_dataprivacy\api;
use tool_dataprivacy\expired_context;
use tool_dataprivacy\external\purpose_exporter;
use tool_dataprivacy\purpose;
defined('MOODLE_INTERNAL') || die;
/**
* The class for displaying the expired contexts table.
*
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class expired_contexts_table extends table_sql {
/** @var int The context level acting as a filter for this table. */
protected $contextlevel = null;
/**
* @var bool $selectall Has the user selected all users on the page? True by default.
*/
protected $selectall = true;
/** @var purpose[] Array of purposes by their id. */
protected $purposes = [];
/** @var purpose[] Map of context => purpose. */
protected $purposemap = [];
/** @var array List of roles. */
protected $roles = [];
/**
* expired_contexts_table constructor.
*
* @param int|null $contextlevel
* @throws coding_exception
*/
public function __construct($contextlevel = null) {
parent::__construct('expired-contexts-table');
$this->contextlevel = $contextlevel;
$columnheaders = [
'name' => get_string('name'),
'info' => get_string('info'),
'purpose' => get_string('purpose', 'tool_dataprivacy'),
'category' => get_string('category', 'tool_dataprivacy'),
'retentionperiod' => get_string('retentionperiod', 'tool_dataprivacy'),
'tobedeleted' => get_string('tobedeleted', 'tool_dataprivacy'),
'timecreated' => get_string('expiry', 'tool_dataprivacy'),
];
$checkboxattrs = [
'title' => get_string('selectall'),
'data-action' => 'selectall'
];
$columnheaders['select'] = html_writer::checkbox('selectall', 1, true, null, $checkboxattrs);
$this->define_columns(array_keys($columnheaders));
$this->define_headers(array_values($columnheaders));
$this->no_sorting('name');
$this->no_sorting('select');
$this->no_sorting('info');
$this->no_sorting('purpose');
$this->no_sorting('category');
$this->no_sorting('retentionperiod');
$this->no_sorting('tobedeleted');
// Make this table sorted by first name by default.
$this->sortable(true, 'timecreated');
// We use roles in several places.
$this->roles = role_get_names();
}
/**
* The context name column.
*
* @param stdClass $expiredctx The row data.
* @return string
* @throws coding_exception
*/
public function col_name($expiredctx) {
global $OUTPUT;
$context = context_helper::instance_by_id($expiredctx->get('contextid'));
$parent = $context->get_parent_context();
$contextdata = (object)[
'name' => $context->get_context_name(false, true),
'parent' => $parent->get_context_name(false, true),
];
$fullcontexts = $context->get_parent_contexts(true);
$contextsinpath = [];
foreach ($fullcontexts as $contextinpath) {
$contextsinpath[] = $contextinpath->get_context_name(false, true);
}
$infoicon = new pix_icon('i/info', implode(' / ', array_reverse($contextsinpath)));
$infoiconhtml = $OUTPUT->render($infoicon);
$name = html_writer::span(get_string('nameandparent', 'tool_dataprivacy', $contextdata), 'mr-1');
return $name . $infoiconhtml;
}
/**
* The context information column.
*
* @param stdClass $expiredctx The row data.
* @return string
* @throws coding_exception
*/
public function col_info($expiredctx) {
global $OUTPUT;
$context = context_helper::instance_by_id($expiredctx->get('contextid'));
$children = $context->get_child_contexts();
if (empty($children)) {
return get_string('none');
} else {
$childnames = [];
foreach ($children as $child) {
$childnames[] = $child->get_context_name(false, true);
}
$infoicon = new pix_icon('i/info', implode(', ', $childnames));
$infoiconhtml = $OUTPUT->render($infoicon);
$name = html_writer::span(get_string('nchildren', 'tool_dataprivacy', count($children)), 'mr-1');
return $name . $infoiconhtml;
}
}
/**
* The category name column.
*
* @param stdClass $expiredctx The row data.
* @return mixed
* @throws coding_exception
* @throws dml_exception
*/
public function col_category($expiredctx) {
$context = context_helper::instance_by_id($expiredctx->get('contextid'));
$category = api::get_effective_context_category($context);
return s($category->get('name'));
}
/**
* The purpose column.
*
* @param stdClass $expiredctx The row data.
* @return string
* @throws coding_exception
*/
public function col_purpose($expiredctx) {
$purpose = $this->get_purpose_for_expiry($expiredctx);
return s($purpose->get('name'));
}
/**
* The retention period column.
*
* @param stdClass $expiredctx The row data.
* @return string
*/
public function col_retentionperiod($expiredctx) {
$purpose = $this->get_purpose_for_expiry($expiredctx);
$expiries = [];
$expiry = html_writer::tag('dt', get_string('default'), ['class' => 'col-sm-3']);
if ($expiredctx->get('defaultexpired')) {
$expiries[get_string('default')] = get_string('expiredrolewithretention', 'tool_dataprivacy', (object) [
'retention' => api::format_retention_period(new \DateInterval($purpose->get('retentionperiod'))),
]);
} else {
$expiries[get_string('default')] = get_string('unexpiredrolewithretention', 'tool_dataprivacy', (object) [
'retention' => api::format_retention_period(new \DateInterval($purpose->get('retentionperiod'))),
]);
}
if (!$expiredctx->is_fully_expired()) {
$purposeoverrides = $purpose->get_purpose_overrides();
foreach ($expiredctx->get('unexpiredroles') as $roleid) {
$role = $this->roles[$roleid];
$override = $purposeoverrides[$roleid];
$expiries[$role->localname] = get_string('unexpiredrolewithretention', 'tool_dataprivacy', (object) [
'retention' => api::format_retention_period(new \DateInterval($override->get('retentionperiod'))),
]);
}
foreach ($expiredctx->get('expiredroles') as $roleid) {
$role = $this->roles[$roleid];
$override = $purposeoverrides[$roleid];
$expiries[$role->localname] = get_string('expiredrolewithretention', 'tool_dataprivacy', (object) [
'retention' => api::format_retention_period(new \DateInterval($override->get('retentionperiod'))),
]);
}
}
$output = array_map(function($rolename, $expiry) {
$return = html_writer::tag('dt', $rolename, ['class' => 'col-sm-3']);
$return .= html_writer::tag('dd', $expiry, ['class' => 'col-sm-9']);
return $return;
}, array_keys($expiries), $expiries);
return html_writer::tag('dl', implode($output), ['class' => 'row']);
}
/**
* The timecreated a.k.a. the context expiry date column.
*
* @param stdClass $expiredctx The row data.
* @return string
*/
public function col_timecreated($expiredctx) {
return userdate($expiredctx->get('timecreated'));
}
/**
* Generate the select column.
*
* @param stdClass $expiredctx The row data.
* @return string
*/
public function col_select($expiredctx) {
$id = $expiredctx->get('id');
return html_writer::checkbox('expiredcontext_' . $id, $id, $this->selectall, '', ['class' => 'selectcontext']);
}
/**
* Formatting for the 'tobedeleted' column which indicates in a friendlier fashion whose data will be removed.
*
* @param stdClass $expiredctx The row data.
* @return string
*/
public function col_tobedeleted($expiredctx) {
if ($expiredctx->is_fully_expired()) {
return get_string('defaultexpired', 'tool_dataprivacy');
}
$purpose = $this->get_purpose_for_expiry($expiredctx);
$a = (object) [];
$expiredroles = [];
foreach ($expiredctx->get('expiredroles') as $roleid) {
$expiredroles[] = html_writer::tag('li', $this->roles[$roleid]->localname);
}
$a->expired = html_writer::tag('ul', implode($expiredroles));
$unexpiredroles = [];
foreach ($expiredctx->get('unexpiredroles') as $roleid) {
$unexpiredroles[] = html_writer::tag('li', $this->roles[$roleid]->localname);
}
$a->unexpired = html_writer::tag('ul', implode($unexpiredroles));
if ($expiredctx->get('defaultexpired')) {
return get_string('defaultexpiredexcept', 'tool_dataprivacy', $a);
} else if (empty($unexpiredroles)) {
return get_string('defaultunexpired', 'tool_dataprivacy', $a);
} else {
return get_string('defaultunexpiredwithexceptions', 'tool_dataprivacy', $a);
}
}
/**
* Query the database for results to display in the table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar.
* @throws dml_exception
* @throws coding_exception
*/
public function query_db($pagesize, $useinitialsbar = true) {
// Only count expired contexts that are awaiting confirmation.
$total = expired_context::get_record_count_by_contextlevel($this->contextlevel, expired_context::STATUS_EXPIRED);
$this->pagesize($pagesize, $total);
$sort = $this->get_sql_sort();
if (empty($sort)) {
$sort = 'timecreated';
}
// Only load expired contexts that are awaiting confirmation.
$expiredcontexts = expired_context::get_records_by_contextlevel($this->contextlevel, expired_context::STATUS_EXPIRED,
$sort, $this->get_page_start(), $this->get_page_size());
$this->rawdata = [];
$contextids = [];
foreach ($expiredcontexts as $persistent) {
$this->rawdata[] = $persistent;
$contextids[] = $persistent->get('contextid');
}
$this->preload_contexts($contextids);
// Set initial bars.
if ($useinitialsbar) {
$this->initialbars($total > $pagesize);
}
}
/**
* Override default implementation to display a more meaningful information to the user.
*/
public function print_nothing_to_display() {
global $OUTPUT;
echo $this->render_reset_button();
$this->print_initials_bar();
echo $OUTPUT->notification(get_string('noexpiredcontexts', 'tool_dataprivacy'), 'warning');
}
/**
* Override the table's show_hide_link method to prevent the show/hide link for the select column from rendering.
*
* @param string $column the column name, index into various names.
* @param int $index numerical index of the column.
* @return string HTML fragment.
*/
protected function show_hide_link($column, $index) {
if ($index < 6) {
return parent::show_hide_link($column, $index);
}
return '';
}
/**
* Get the purpose for the specified expired context.
*
* @param expired_context $expiredcontext
* @return purpose
*/
protected function get_purpose_for_expiry(expired_context $expiredcontext): purpose {
$context = context_helper::instance_by_id($expiredcontext->get('contextid'));
if (empty($this->purposemap[$context->id])) {
$purpose = api::get_effective_context_purpose($context);
$this->purposemap[$context->id] = $purpose->get('id');
if (empty($this->purposes[$purpose->get('id')])) {
$this->purposes[$purpose->get('id')] = $purpose;
}
}
return $this->purposes[$this->purposemap[$context->id]];
}
/**
* Preload context records given a set of contextids.
*
* @param array $contextids
*/
protected function preload_contexts(array $contextids) {
global $DB;
if (empty($contextids)) {
return;
}
$ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$sql = "SELECT {$ctxfields} FROM {context} ctx WHERE ctx.id {$insql}";
$contextlist = $DB->get_recordset_sql($sql, $inparams);
foreach ($contextlist as $contextdata) {
\context_helper::preload_from_record($contextdata);
}
$contextlist->close();
}
}
@@ -0,0 +1,164 @@
<?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/>.
/**
* Class containing data for a user's data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use action_menu;
use action_menu_link_secondary;
use coding_exception;
use context_user;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\api;
use tool_dataprivacy\data_request;
use tool_dataprivacy\external\data_request_exporter;
/**
* Class containing data for a user's data requests.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class my_data_requests_page implements renderable, templatable {
/** @var array $requests List of data requests. */
protected $requests = [];
/**
* Construct this renderable.
*
* @param data_request[] $requests
*/
public function __construct($requests) {
$this->requests = $requests;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
global $USER;
$data = new stdClass();
$data->newdatarequesturl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php');
if (!is_https()) {
$httpwarningmessage = get_string('httpwarning', 'tool_dataprivacy');
$data->httpsite = array('message' => $httpwarningmessage, 'announce' => 1);
}
$requests = [];
foreach ($this->requests as $request) {
$requestid = $request->get('id');
$status = $request->get('status');
$userid = $request->get('userid');
$type = $request->get('type');
$usercontext = context_user::instance($userid, IGNORE_MISSING);
if (!$usercontext) {
// Use the context system.
$outputcontext = \context_system::instance();
} else {
$outputcontext = $usercontext;
}
$requestexporter = new data_request_exporter($request, ['context' => $outputcontext]);
$item = $requestexporter->export($output);
$self = $request->get('userid') == $USER->id;
if (!$self) {
// Append user name if it differs from $USER.
$a = (object)['typename' => $item->typename, 'user' => $item->foruser->fullname];
$item->typename = get_string('requesttypeuser', 'tool_dataprivacy', $a);
}
$candownload = false;
$cancancel = true;
switch ($status) {
case api::DATAREQUEST_STATUS_COMPLETE:
$item->statuslabelclass = 'bg-success text-white';
$item->statuslabel = get_string('statuscomplete', 'tool_dataprivacy');
$cancancel = false;
break;
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
$item->statuslabelclass = 'bg-success text-white';
$item->statuslabel = get_string('statusready', 'tool_dataprivacy');
$cancancel = false;
$candownload = true;
if ($usercontext) {
$candownload = api::can_download_data_request_for_user(
$request->get('userid'), $request->get('requestedby'));
}
break;
case api::DATAREQUEST_STATUS_DELETED:
$item->statuslabelclass = 'bg-success text-white';
$item->statuslabel = get_string('statusdeleted', 'tool_dataprivacy');
$cancancel = false;
break;
case api::DATAREQUEST_STATUS_EXPIRED:
$item->statuslabelclass = 'bg-secondary text-dark';
$item->statuslabel = get_string('statusexpired', 'tool_dataprivacy');
$item->statuslabeltitle = get_string('downloadexpireduser', 'tool_dataprivacy');
$cancancel = false;
break;
case api::DATAREQUEST_STATUS_CANCELLED:
case api::DATAREQUEST_STATUS_REJECTED:
$cancancel = false;
break;
}
// Prepare actions.
$actions = [];
if ($cancancel) {
$cancelurl = new moodle_url('#');
$canceldata = ['data-action' => 'cancel', 'data-requestid' => $requestid];
$canceltext = get_string('cancelrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($cancelurl, null, $canceltext, $canceldata);
}
if ($candownload && $usercontext) {
$actions[] = api::get_download_link($usercontext, $requestid);
}
if (!empty($actions)) {
$actionsmenu = new action_menu($actions);
$actionsmenu->set_menu_trigger(get_string('actions'));
$actionsmenu->set_owner_selector('request-actions-' . $requestid);
$item->actions = $actionsmenu->export_for_template($output);
}
$requests[] = $item;
}
$data->requests = $requests;
return $data;
}
}
@@ -0,0 +1,88 @@
<?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/>.
/**
* Purposes renderable.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\external\purpose_exporter;
/**
* Class containing the purposes page renderable.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class purposes extends crud_element implements renderable, templatable {
/** @var array $purposes All system purposes. */
protected $purposes = [];
/**
* Construct this renderable.
*
* @param \tool_dataprivacy\purpose[] $purposes
*/
public function __construct($purposes) {
$this->purposes = $purposes;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$context = \context_system::instance();
$PAGE->requires->js_call_amd('tool_dataprivacy/purposesactions', 'init');
$PAGE->requires->js_call_amd('tool_dataprivacy/add_purpose', 'getInstance', [$context->id]);
$data = new stdClass();
// Navigation links.
$data->navigation = [];
$navigationlinks = $this->get_navigation();
foreach ($navigationlinks as $navlink) {
$data->navigation[] = $navlink->export_for_template($output);
}
$data->purposes = [];
foreach ($this->purposes as $purpose) {
$exporter = new purpose_exporter($purpose, ['context' => \context_system::instance()]);
$exportedpurpose = $exporter->export($output);
$actionmenu = $this->action_menu('purpose', $exportedpurpose, $purpose);
$exportedpurpose->actions = $actionmenu->export_for_template($output);
$data->purposes[] = $exportedpurpose;
}
return $data;
}
}
@@ -0,0 +1,149 @@
<?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/>.
/**
* Renderer class for tool_dataprivacy
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use html_writer;
use moodle_exception;
use plugin_renderer_base;
/**
* Renderer class for tool_dataprivacy.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Render the user's data requests page.
*
* @param my_data_requests_page $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_my_data_requests_page(my_data_requests_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/my_data_requests', $data);
}
/**
* Render the contact DPO link.
*
* @return string The HTML for the link.
*/
public function render_contact_dpo_link() {
$params = [
'data-action' => 'contactdpo',
];
return html_writer::link('#', get_string('contactdataprotectionofficer', 'tool_dataprivacy'), $params);
}
/**
* Render the data requests page for the DPO.
*
* @param data_requests_page $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_data_requests_page(data_requests_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/data_requests', $data);
}
/**
* Render the data registry.
*
* @param data_registry_page $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_data_registry_page(data_registry_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/data_registry', $data);
}
/**
* Render the data compliance registry.
*
* @param data_registry_compliance_page $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_data_registry_compliance_page(data_registry_compliance_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/data_registry_compliance', $data);
}
/**
* Render the purposes management page.
*
* @param purposes $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_purposes(purposes $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/purposes', $data);
}
/**
* Render the categories management page.
*
* @param categories $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_categories(categories $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/categories', $data);
}
/**
* Render the review page for the deletion of expired contexts.
*
* @param data_deletion_page $page
* @return string html for the page
* @throws moodle_exception
*/
public function render_data_deletion_page(data_deletion_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/data_deletion', $data);
}
/**
* Render the user data retention summary page.
*
* @param summary_page $page
* @return string html for the page.
*/
public function render_summary_page(summary_page $page) {
$data = $page->export_for_template($this);
return parent::render_from_template('tool_dataprivacy/summary', $data);
}
}
@@ -0,0 +1,98 @@
<?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/>.
/**
* Class containing the filter options data for rendering the autocomplete element for the data requests page.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
use moodle_url;
use renderable;
use renderer_base;
use stdClass;
use templatable;
defined('MOODLE_INTERNAL') || die();
/**
* Class containing the filter options data for rendering the autocomplete element for the data requests page.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class request_filter implements renderable, templatable {
/** @var array $filteroptions The filter options. */
protected $filteroptions;
/** @var array $selectedoptions The list of selected filter option values. */
protected $selectedoptions;
/** @var moodle_url|string $baseurl The url with params needed to call up this page. */
protected $baseurl;
/**
* request_filter constructor.
*
* @param array $filteroptions The filter options.
* @param array $selectedoptions The list of selected filter option values.
* @param string|moodle_url $baseurl The url with params needed to call up this page.
*/
public function __construct($filteroptions, $selectedoptions, $baseurl = null) {
$this->filteroptions = $filteroptions;
$this->selectedoptions = $selectedoptions;
if (!empty($baseurl)) {
$this->baseurl = new moodle_url($baseurl);
}
}
/**
* Function to export the renderer data in a format that is suitable for a mustache template.
*
* @param renderer_base $output Used to do a final render of any components that need to be rendered for export.
* @return stdClass|array
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$data = new stdClass();
if (empty($this->baseurl)) {
$this->baseurl = $PAGE->url;
}
$data->action = $this->baseurl->out(false);
foreach ($this->selectedoptions as $option) {
if (!isset($this->filteroptions[$option])) {
$this->filteroptions[$option] = $option;
}
}
$data->filteroptions = [];
foreach ($this->filteroptions as $value => $label) {
$selected = in_array($value, $this->selectedoptions);
$filteroption = (object)[
'value' => $value,
'label' => $label
];
$filteroption->selected = $selected;
$data->filteroptions[] = $filteroption;
}
return $data;
}
}
@@ -0,0 +1,132 @@
<?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/>.
/**
* Summary page renderable.
*
* @package tool_dataprivacy
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
/**
* Class containing the summary page renderable.
*
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class summary_page implements renderable, templatable {
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
$contextlevels = [
'contextlevelname10' => CONTEXT_SYSTEM,
'contextlevelname30' => CONTEXT_USER,
'contextlevelname40' => CONTEXT_COURSECAT,
'contextlevelname50' => CONTEXT_COURSE,
'contextlevelname70' => CONTEXT_MODULE,
'contextlevelname80' => CONTEXT_BLOCK
];
$data = [];
$context = \context_system::instance();
foreach ($contextlevels as $levelname => $level) {
$classname = \context_helper::get_class_for_level($level);
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
$purposeid = get_config('tool_dataprivacy', $purposevar);
$categoryid = get_config('tool_dataprivacy', $categoryvar);
$section = [];
$section['contextname'] = get_string($levelname, 'tool_dataprivacy');
if (empty($purposeid)) {
list($purposeid, $categoryid) =
\tool_dataprivacy\data_registry::get_effective_default_contextlevel_purpose_and_category($level);
}
if ($purposeid == -1) {
$purposeid = 0;
}
$purpose = new \tool_dataprivacy\purpose($purposeid);
$export = new \tool_dataprivacy\external\purpose_exporter($purpose, ['context' => $context]);
$purposedata = $export->export($output);
$section['purpose'] = $purposedata;
if (empty($categoryid)) {
list($purposeid, $categoryid) =
\tool_dataprivacy\data_registry::get_effective_default_contextlevel_purpose_and_category($level);
}
if ($categoryid == -1) {
$categoryid = 0;
}
$category = new \tool_dataprivacy\category($categoryid);
$export = new \tool_dataprivacy\external\category_exporter($category, ['context' => $context]);
$categorydata = $export->export($output);
$section['category'] = $categorydata;
$data['contexts'][] = $section;
}
// Get activity module plugin info.
$pluginmanager = \core_plugin_manager::instance();
$modplugins = $pluginmanager->get_enabled_plugins('mod');
foreach ($modplugins as $name) {
$classname = \context_helper::get_class_for_level($contextlevels['contextlevelname70']);
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname, $name);
$categoryid = get_config('tool_dataprivacy', $categoryvar);
$purposeid = get_config('tool_dataprivacy', $purposevar);
if ($categoryid === false && $purposeid === false) {
// If no purpose and category has been set for this plugin, then there's no need to show this on the list.
continue;
}
$section = [];
$section['contextname'] = $pluginmanager->plugin_name('mod_' . $name);
if ($purposeid == -1) {
$purposeid = 0;
}
$purpose = new \tool_dataprivacy\purpose($purposeid);
$export = new \tool_dataprivacy\external\purpose_exporter($purpose, ['context' => $context]);
$purposedata = $export->export($output);
$section['purpose'] = $purposedata;
if ($categoryid == -1) {
$categoryid = 0;
}
$category = new \tool_dataprivacy\category($categoryid);
$export = new \tool_dataprivacy\external\category_exporter($category, ['context' => $context]);
$categorydata = $export->export($output);
$section['category'] = $categorydata;
$data['contexts'][] = $section;
}
return $data;
}
}