Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'MDL-63619-master' of git://github.com/andrewnicols/moodle
  • Loading branch information
David Monllao committed Oct 24, 2018
2 parents 66de50c + d95ad08 commit f560f36
Show file tree
Hide file tree
Showing 6 changed files with 515 additions and 283 deletions.
7 changes: 3 additions & 4 deletions admin/tool/dataprivacy/classes/api.php
Expand Up @@ -914,7 +914,7 @@ public static function set_contextlevel($record) {
* @param int $forcedvalue Use this categoryid value as if this was this context instance category.
* @return category|false
*/
public static function get_effective_context_category(\context $context, $forcedvalue=false) {
public static function get_effective_context_category(\context $context, $forcedvalue = false) {
if (!data_registry::defaults_set()) {
return false;
}
Expand All @@ -941,15 +941,14 @@ public static function get_effective_context_purpose(\context $context, $forcedv
* Returns the effective category given a context level.
*
* @param int $contextlevel
* @param int $forcedvalue Use this categoryid value as if this was this context level category.
* @return category|false
*/
public static function get_effective_contextlevel_category($contextlevel, $forcedvalue=false) {
public static function get_effective_contextlevel_category($contextlevel) {
if (!data_registry::defaults_set()) {
return false;
}

return data_registry::get_effective_contextlevel_value($contextlevel, 'category', $forcedvalue);
return data_registry::get_effective_contextlevel_value($contextlevel, 'category');
}

/**
Expand Down
207 changes: 86 additions & 121 deletions admin/tool/dataprivacy/classes/data_registry.php
Expand Up @@ -39,18 +39,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry {

/**
* @var array Inheritance between context levels.
*/
private static $contextlevelinheritance = [
CONTEXT_USER => [CONTEXT_SYSTEM],
CONTEXT_COURSECAT => [CONTEXT_SYSTEM],
CONTEXT_COURSE => [CONTEXT_COURSECAT, CONTEXT_SYSTEM],
CONTEXT_MODULE => [CONTEXT_COURSE, CONTEXT_COURSECAT, CONTEXT_SYSTEM],
CONTEXT_BLOCK => [CONTEXT_COURSE, CONTEXT_COURSECAT, CONTEXT_SYSTEM],
];

/**
* Returns purpose and category var names from a context class name
*
Expand Down Expand Up @@ -83,7 +71,6 @@ public static function var_names_from_context($classname, $pluginname = '') {
* @return int[]|false[]
*/
public static function get_defaults($contextlevel, $pluginname = '') {

$classname = \context_helper::get_class_for_level($contextlevel);
list($purposevar, $categoryvar) = self::var_names_from_context($classname, $pluginname);

Expand All @@ -104,10 +91,10 @@ public static function get_defaults($contextlevel, $pluginname = '') {
}

if (empty($purposeid)) {
$purposeid = false;
$purposeid = context_instance::NOTSET;
}
if (empty($categoryid)) {
$categoryid = false;
$categoryid = context_instance::NOTSET;
}

return [$purposeid, $categoryid];
Expand Down Expand Up @@ -190,69 +177,92 @@ public static function get_subject_scope(\context $context) {
* @return persistent|false It return a 'purpose' instance or a 'category' instance, depending on $element
*/
public static function get_effective_context_value(\context $context, $element, $forcedvalue = false) {
global $DB;

if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
}
$fieldname = $element . 'id';

if (empty($forcedvalue)) {
$instance = context_instance::get_record_by_contextid($context->id, false);

if (!$instance) {
// If the instance does not have a value defaults to not set, so we grab the context level default as its value.
$instancevalue = context_instance::NOTSET;
} else {
$instancevalue = $instance->get($fieldname);
}
if (!empty($forcedvalue) && ($forcedvalue === context_instance::INHERIT)) {
// Do not include the current context when calculating the value.
// This has the effect that an inheritted value is calculated.
$parentcontextids = $context->get_parent_context_ids(false);
} else if (!empty($forcedvalue) && ($forcedvalue !== context_instance::NOTSET)) {
return self::get_element_instance($element, $forcedvalue);
} else {
$instancevalue = $forcedvalue;
// Fetch all parent contexts, including self.
$parentcontextids = $context->get_parent_context_ids(true);
}
list($insql, $inparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED);
$inparams['contextmodule'] = CONTEXT_MODULE;

// Not set.
if ($instancevalue == context_instance::NOTSET) {

// The effective value varies depending on the context level.
if ($context->contextlevel == CONTEXT_USER) {
// Use the context level value as we don't allow people to set specific instances values.
if ('purpose' === $element) {
$elementjoin = 'LEFT JOIN {tool_dataprivacy_purpose} ele ON ctxins.purposeid = ele.id';
$elementfields = purpose::get_sql_fields('ele', 'ele');
} else {
$elementjoin = 'LEFT JOIN {tool_dataprivacy_category} ele ON ctxins.categoryid = ele.id';
$elementfields = category::get_sql_fields('ele', 'ele');
}
$contextfields = \context_helper::get_preload_record_columns_sql('ctx');
$fields = implode(', ', ['ctx.id', 'm.name AS modname', $contextfields, $elementfields]);

$sql = "SELECT $fields
FROM {context} ctx
LEFT JOIN {tool_dataprivacy_ctxinstance} ctxins ON ctx.id = ctxins.contextid
LEFT JOIN {course_modules} cm ON ctx.contextlevel = :contextmodule AND ctx.instanceid = cm.id
LEFT JOIN {modules} m ON m.id = cm.module
{$elementjoin}
WHERE ctx.id {$insql}
ORDER BY ctx.path DESC";
$contextinstances = $DB->get_records_sql($sql, $inparams);

// Check whether this context is a user context, or a child of a user context.
// All children of a User context share the same context and cannot be set individually.
foreach ($contextinstances as $record) {
\context_helper::preload_from_record($record);
$parent = \context::instance_by_id($record->id, false);

if ($parent->contextlevel == CONTEXT_USER) {
// Use the context level value for the user.
return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
}
}

$parents = $context->get_parent_contexts(true);
foreach ($parents as $parent) {
if ($parent->contextlevel == CONTEXT_USER) {
// Use the context level value as we don't allow people to set specific instances values.
return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
}
foreach ($contextinstances as $record) {
$parent = \context::instance_by_id($record->id, false);

$checkcontextlevel = false;
if (empty($record->eleid)) {
$checkcontextlevel = true;
}

// Check if we need to pass the plugin name of an activity.
$forplugin = '';
if ($context->contextlevel == CONTEXT_MODULE) {
list($course, $cm) = get_course_and_cm_from_cmid($context->instanceid);
$forplugin = $cm->modname;
if (!empty($forcedvalue) && context_instance::NOTSET === $forcedvalue) {
$checkcontextlevel = true;
}
// Use the default context level value.
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
$context->contextlevel, false, false, $forplugin
);

return self::get_element_instance($element, $$fieldname);
}
if ($checkcontextlevel) {
// Check for a value at the contextlevel
$forplugin = empty($record->modname) ? '' : $record->modname;
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
$parent->contextlevel, false, false, $forplugin);

// Specific value for this context instance.
if ($instancevalue != context_instance::INHERIT) {
return self::get_element_instance($element, $instancevalue);
}
$instancevalue = $$fieldname;

// This context is using inherited so let's return the parent effective value.
$parentcontext = $context->get_parent_context();
if (!$parentcontext) {
return false;
if (context_instance::NOTSET !== $instancevalue && context_instance::INHERIT !== $instancevalue) {
// There is an actual value. Return it.
return self::get_element_instance($element, $instancevalue);
}
} else {
$elementclass = "\\tool_dataprivacy\\{$element}";
$instance = new $elementclass(null, $elementclass::extract_record($record, 'ele'));
$instance->validate();

return $instance;
}
}

// The forced value should not be transmitted to parent contexts.
return self::get_effective_context_value($parentcontext, $element);
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
}

/**
Expand All @@ -264,11 +274,9 @@ public static function get_effective_context_value(\context $context, $element,
*
* @param int $contextlevel
* @param string $element 'category' or 'purpose'
* @param int $forcedvalue Use this value as if this was this context level purpose.
* @return \tool_dataprivacy\purpose|false
*/
public static function get_effective_contextlevel_value($contextlevel, $element, $forcedvalue = false) {

public static function get_effective_contextlevel_value($contextlevel, $element) {
if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
}
Expand All @@ -279,39 +287,15 @@ public static function get_effective_contextlevel_value($contextlevel, $element,
'have a purpose or a category.');
}

if ($forcedvalue === false) {
$instance = contextlevel::get_record_by_contextlevel($contextlevel, false);
if (!$instance) {
// If the context level does not have a value defaults to not set, so we grab the context level default as
// its value.
$instancevalue = context_instance::NOTSET;
} else {
$instancevalue = $instance->get($fieldname);
}
} else {
$instancevalue = $forcedvalue;
}
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);

// Not set -> Use the default context level value.
if ($instancevalue == context_instance::NOTSET) {
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);
// Note: The $$fieldname points to either $purposeid, or $categoryid.
if (context_instance::NOTSET !== $$fieldname && context_instance::INHERIT !== $$fieldname) {
// There is a specific value set.
return self::get_element_instance($element, $$fieldname);
}

// Specific value for this context instance.
if ($instancevalue != context_instance::INHERIT) {
return self::get_element_instance($element, $instancevalue);
}

if ($contextlevel == CONTEXT_SYSTEM) {
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
}

// If we reach this point is that we are inheriting so get the parent context level and repeat.
$parentcontextlevel = reset(self::$contextlevelinheritance[$contextlevel]);

// Forced value are intentionally not passed as the force value should only affect the immediate context level.
return self::get_effective_contextlevel_value($parentcontextlevel, $element);
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
}

/**
Expand All @@ -320,13 +304,13 @@ public static function get_effective_contextlevel_value($contextlevel, $element,
* @param int $contextlevel
* @param int|bool $forcedpurposevalue Use this value as if this was this context level purpose.
* @param int|bool $forcedcategoryvalue Use this value as if this was this context level category.
* @param string $activity The plugin name of the activity.
* @param string $component The name of the component to check.
* @return int[]
*/
public static function get_effective_default_contextlevel_purpose_and_category($contextlevel, $forcedpurposevalue = false,
$forcedcategoryvalue = false, $activity = '') {

list($purposeid, $categoryid) = self::get_defaults($contextlevel, $activity);
$forcedcategoryvalue = false, $component = '') {
// Get the defaults for this context level.
list($purposeid, $categoryid) = self::get_defaults($contextlevel, $component);

// Honour forced values.
if ($forcedpurposevalue) {
Expand All @@ -336,37 +320,19 @@ public static function get_effective_default_contextlevel_purpose_and_category($
$categoryid = $forcedcategoryvalue;
}

// Not set == INHERIT for defaults.
if ($purposeid == context_instance::INHERIT || $purposeid == context_instance::NOTSET) {
$purposeid = false;
}
if ($categoryid == context_instance::INHERIT || $categoryid == context_instance::NOTSET) {
$categoryid = false;
}

if ($contextlevel != CONTEXT_SYSTEM && ($purposeid === false || $categoryid === false)) {
foreach (self::$contextlevelinheritance[$contextlevel] as $parent) {
if ($contextlevel == CONTEXT_USER) {
// Only user context levels inherit from a parent context level.
list($parentpurposeid, $parentcategoryid) = self::get_defaults(CONTEXT_SYSTEM);

list($parentpurposeid, $parentcategoryid) = self::get_defaults($parent);
// Not set == INHERIT for defaults.
if ($parentpurposeid == context_instance::INHERIT || $parentpurposeid == context_instance::NOTSET) {
$parentpurposeid = false;
}
if ($parentcategoryid == context_instance::INHERIT || $parentcategoryid == context_instance::NOTSET) {
$parentcategoryid = false;
}

if ($purposeid === false && $parentpurposeid) {
$purposeid = $parentpurposeid;
}
if (context_instance::INHERIT == $purposeid || context_instance::NOTSET == $purposeid) {
$purposeid = $parentpurposeid;
}

if ($categoryid === false && $parentcategoryid) {
$categoryid = $parentcategoryid;
}
if (context_instance::INHERIT == $categoryid || context_instance::NOTSET == $categoryid) {
$categoryid = $parentcategoryid;
}
}

// They may still be false, but we return anyway.
return [$purposeid, $categoryid];
}

Expand All @@ -379,7 +345,6 @@ public static function get_effective_default_contextlevel_purpose_and_category($
* @return \core\persistent
*/
private static function get_element_instance($element, $id) {

if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('No other elements than purpose and category are allowed');
}
Expand Down
23 changes: 14 additions & 9 deletions admin/tool/dataprivacy/classes/form/context_instance.php
Expand Up @@ -145,12 +145,12 @@ public static function get_context_instance_customdata(\context $context) {
$persistent->set('contextid', $context->id);
}

$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options(
api::get_purposes()
);
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(
api::get_categories()
);
$purposes = [];
foreach (api::get_purposes() as $purpose) {
$purposes[$purpose->get('id')] = $purpose;
}
$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options($purposes);
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(api::get_categories());

$customdata = [
'context' => $context,
Expand All @@ -168,9 +168,14 @@ public static function get_context_instance_customdata(\context $context) {
$context);

$customdata['purposeretentionperiods'] = [];
foreach ($purposeoptions as $optionvalue => $unused) {
// Get the effective purpose if $optionvalue would be the selected value.
$purpose = api::get_effective_context_purpose($context, $optionvalue);
foreach (array_keys($purposeoptions) as $optionvalue) {

if (isset($purposes[$optionvalue])) {
$purpose = $purposes[$optionvalue];
} else {
// Get the effective purpose if $optionvalue would be the selected value.
$purpose = api::get_effective_context_purpose($context, $optionvalue);
}

$retentionperiod = self::get_retention_display_text(
$purpose,
Expand Down

0 comments on commit f560f36

Please sign in to comment.