Skip to content

Commit f560f36

Browse files
author
David Monllao
committed
Merge branch 'MDL-63619-master' of git://github.com/andrewnicols/moodle
2 parents 66de50c + d95ad08 commit f560f36

File tree

6 files changed

+515
-283
lines changed

6 files changed

+515
-283
lines changed

admin/tool/dataprivacy/classes/api.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ public static function set_contextlevel($record) {
914914
* @param int $forcedvalue Use this categoryid value as if this was this context instance category.
915915
* @return category|false
916916
*/
917-
public static function get_effective_context_category(\context $context, $forcedvalue=false) {
917+
public static function get_effective_context_category(\context $context, $forcedvalue = false) {
918918
if (!data_registry::defaults_set()) {
919919
return false;
920920
}
@@ -941,15 +941,14 @@ public static function get_effective_context_purpose(\context $context, $forcedv
941941
* Returns the effective category given a context level.
942942
*
943943
* @param int $contextlevel
944-
* @param int $forcedvalue Use this categoryid value as if this was this context level category.
945944
* @return category|false
946945
*/
947-
public static function get_effective_contextlevel_category($contextlevel, $forcedvalue=false) {
946+
public static function get_effective_contextlevel_category($contextlevel) {
948947
if (!data_registry::defaults_set()) {
949948
return false;
950949
}
951950

952-
return data_registry::get_effective_contextlevel_value($contextlevel, 'category', $forcedvalue);
951+
return data_registry::get_effective_contextlevel_value($contextlevel, 'category');
953952
}
954953

955954
/**

admin/tool/dataprivacy/classes/data_registry.php

Lines changed: 86 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,6 @@
3939
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4040
*/
4141
class data_registry {
42-
43-
/**
44-
* @var array Inheritance between context levels.
45-
*/
46-
private static $contextlevelinheritance = [
47-
CONTEXT_USER => [CONTEXT_SYSTEM],
48-
CONTEXT_COURSECAT => [CONTEXT_SYSTEM],
49-
CONTEXT_COURSE => [CONTEXT_COURSECAT, CONTEXT_SYSTEM],
50-
CONTEXT_MODULE => [CONTEXT_COURSE, CONTEXT_COURSECAT, CONTEXT_SYSTEM],
51-
CONTEXT_BLOCK => [CONTEXT_COURSE, CONTEXT_COURSECAT, CONTEXT_SYSTEM],
52-
];
53-
5442
/**
5543
* Returns purpose and category var names from a context class name
5644
*
@@ -83,7 +71,6 @@ public static function var_names_from_context($classname, $pluginname = '') {
8371
* @return int[]|false[]
8472
*/
8573
public static function get_defaults($contextlevel, $pluginname = '') {
86-
8774
$classname = \context_helper::get_class_for_level($contextlevel);
8875
list($purposevar, $categoryvar) = self::var_names_from_context($classname, $pluginname);
8976

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

10693
if (empty($purposeid)) {
107-
$purposeid = false;
94+
$purposeid = context_instance::NOTSET;
10895
}
10996
if (empty($categoryid)) {
110-
$categoryid = false;
97+
$categoryid = context_instance::NOTSET;
11198
}
11299

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

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

199-
if (empty($forcedvalue)) {
200-
$instance = context_instance::get_record_by_contextid($context->id, false);
201-
202-
if (!$instance) {
203-
// If the instance does not have a value defaults to not set, so we grab the context level default as its value.
204-
$instancevalue = context_instance::NOTSET;
205-
} else {
206-
$instancevalue = $instance->get($fieldname);
207-
}
187+
if (!empty($forcedvalue) && ($forcedvalue === context_instance::INHERIT)) {
188+
// Do not include the current context when calculating the value.
189+
// This has the effect that an inheritted value is calculated.
190+
$parentcontextids = $context->get_parent_context_ids(false);
191+
} else if (!empty($forcedvalue) && ($forcedvalue !== context_instance::NOTSET)) {
192+
return self::get_element_instance($element, $forcedvalue);
208193
} else {
209-
$instancevalue = $forcedvalue;
194+
// Fetch all parent contexts, including self.
195+
$parentcontextids = $context->get_parent_context_ids(true);
210196
}
197+
list($insql, $inparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED);
198+
$inparams['contextmodule'] = CONTEXT_MODULE;
211199

212-
// Not set.
213-
if ($instancevalue == context_instance::NOTSET) {
214-
215-
// The effective value varies depending on the context level.
216-
if ($context->contextlevel == CONTEXT_USER) {
217-
// Use the context level value as we don't allow people to set specific instances values.
200+
if ('purpose' === $element) {
201+
$elementjoin = 'LEFT JOIN {tool_dataprivacy_purpose} ele ON ctxins.purposeid = ele.id';
202+
$elementfields = purpose::get_sql_fields('ele', 'ele');
203+
} else {
204+
$elementjoin = 'LEFT JOIN {tool_dataprivacy_category} ele ON ctxins.categoryid = ele.id';
205+
$elementfields = category::get_sql_fields('ele', 'ele');
206+
}
207+
$contextfields = \context_helper::get_preload_record_columns_sql('ctx');
208+
$fields = implode(', ', ['ctx.id', 'm.name AS modname', $contextfields, $elementfields]);
209+
210+
$sql = "SELECT $fields
211+
FROM {context} ctx
212+
LEFT JOIN {tool_dataprivacy_ctxinstance} ctxins ON ctx.id = ctxins.contextid
213+
LEFT JOIN {course_modules} cm ON ctx.contextlevel = :contextmodule AND ctx.instanceid = cm.id
214+
LEFT JOIN {modules} m ON m.id = cm.module
215+
{$elementjoin}
216+
WHERE ctx.id {$insql}
217+
ORDER BY ctx.path DESC";
218+
$contextinstances = $DB->get_records_sql($sql, $inparams);
219+
220+
// Check whether this context is a user context, or a child of a user context.
221+
// All children of a User context share the same context and cannot be set individually.
222+
foreach ($contextinstances as $record) {
223+
\context_helper::preload_from_record($record);
224+
$parent = \context::instance_by_id($record->id, false);
225+
226+
if ($parent->contextlevel == CONTEXT_USER) {
227+
// Use the context level value for the user.
218228
return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
219229
}
230+
}
220231

221-
$parents = $context->get_parent_contexts(true);
222-
foreach ($parents as $parent) {
223-
if ($parent->contextlevel == CONTEXT_USER) {
224-
// Use the context level value as we don't allow people to set specific instances values.
225-
return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
226-
}
232+
foreach ($contextinstances as $record) {
233+
$parent = \context::instance_by_id($record->id, false);
234+
235+
$checkcontextlevel = false;
236+
if (empty($record->eleid)) {
237+
$checkcontextlevel = true;
227238
}
228239

229-
// Check if we need to pass the plugin name of an activity.
230-
$forplugin = '';
231-
if ($context->contextlevel == CONTEXT_MODULE) {
232-
list($course, $cm) = get_course_and_cm_from_cmid($context->instanceid);
233-
$forplugin = $cm->modname;
240+
if (!empty($forcedvalue) && context_instance::NOTSET === $forcedvalue) {
241+
$checkcontextlevel = true;
234242
}
235-
// Use the default context level value.
236-
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
237-
$context->contextlevel, false, false, $forplugin
238-
);
239243

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

243-
// Specific value for this context instance.
244-
if ($instancevalue != context_instance::INHERIT) {
245-
return self::get_element_instance($element, $instancevalue);
246-
}
250+
$instancevalue = $$fieldname;
247251

248-
// This context is using inherited so let's return the parent effective value.
249-
$parentcontext = $context->get_parent_context();
250-
if (!$parentcontext) {
251-
return false;
252+
if (context_instance::NOTSET !== $instancevalue && context_instance::INHERIT !== $instancevalue) {
253+
// There is an actual value. Return it.
254+
return self::get_element_instance($element, $instancevalue);
255+
}
256+
} else {
257+
$elementclass = "\\tool_dataprivacy\\{$element}";
258+
$instance = new $elementclass(null, $elementclass::extract_record($record, 'ele'));
259+
$instance->validate();
260+
261+
return $instance;
262+
}
252263
}
253264

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

258268
/**
@@ -264,11 +274,9 @@ public static function get_effective_context_value(\context $context, $element,
264274
*
265275
* @param int $contextlevel
266276
* @param string $element 'category' or 'purpose'
267-
* @param int $forcedvalue Use this value as if this was this context level purpose.
268277
* @return \tool_dataprivacy\purpose|false
269278
*/
270-
public static function get_effective_contextlevel_value($contextlevel, $element, $forcedvalue = false) {
271-
279+
public static function get_effective_contextlevel_value($contextlevel, $element) {
272280
if ($element !== 'purpose' && $element !== 'category') {
273281
throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
274282
}
@@ -279,39 +287,15 @@ public static function get_effective_contextlevel_value($contextlevel, $element,
279287
'have a purpose or a category.');
280288
}
281289

282-
if ($forcedvalue === false) {
283-
$instance = contextlevel::get_record_by_contextlevel($contextlevel, false);
284-
if (!$instance) {
285-
// If the context level does not have a value defaults to not set, so we grab the context level default as
286-
// its value.
287-
$instancevalue = context_instance::NOTSET;
288-
} else {
289-
$instancevalue = $instance->get($fieldname);
290-
}
291-
} else {
292-
$instancevalue = $forcedvalue;
293-
}
290+
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);
294291

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

301-
// Specific value for this context instance.
302-
if ($instancevalue != context_instance::INHERIT) {
303-
return self::get_element_instance($element, $instancevalue);
304-
}
305-
306-
if ($contextlevel == CONTEXT_SYSTEM) {
307-
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
308-
}
309-
310-
// If we reach this point is that we are inheriting so get the parent context level and repeat.
311-
$parentcontextlevel = reset(self::$contextlevelinheritance[$contextlevel]);
312-
313-
// Forced value are intentionally not passed as the force value should only affect the immediate context level.
314-
return self::get_effective_contextlevel_value($parentcontextlevel, $element);
298+
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
315299
}
316300

317301
/**
@@ -320,13 +304,13 @@ public static function get_effective_contextlevel_value($contextlevel, $element,
320304
* @param int $contextlevel
321305
* @param int|bool $forcedpurposevalue Use this value as if this was this context level purpose.
322306
* @param int|bool $forcedcategoryvalue Use this value as if this was this context level category.
323-
* @param string $activity The plugin name of the activity.
307+
* @param string $component The name of the component to check.
324308
* @return int[]
325309
*/
326310
public static function get_effective_default_contextlevel_purpose_and_category($contextlevel, $forcedpurposevalue = false,
327-
$forcedcategoryvalue = false, $activity = '') {
328-
329-
list($purposeid, $categoryid) = self::get_defaults($contextlevel, $activity);
311+
$forcedcategoryvalue = false, $component = '') {
312+
// Get the defaults for this context level.
313+
list($purposeid, $categoryid) = self::get_defaults($contextlevel, $component);
330314

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

339-
// Not set == INHERIT for defaults.
340-
if ($purposeid == context_instance::INHERIT || $purposeid == context_instance::NOTSET) {
341-
$purposeid = false;
342-
}
343-
if ($categoryid == context_instance::INHERIT || $categoryid == context_instance::NOTSET) {
344-
$categoryid = false;
345-
}
346-
347-
if ($contextlevel != CONTEXT_SYSTEM && ($purposeid === false || $categoryid === false)) {
348-
foreach (self::$contextlevelinheritance[$contextlevel] as $parent) {
323+
if ($contextlevel == CONTEXT_USER) {
324+
// Only user context levels inherit from a parent context level.
325+
list($parentpurposeid, $parentcategoryid) = self::get_defaults(CONTEXT_SYSTEM);
349326

350-
list($parentpurposeid, $parentcategoryid) = self::get_defaults($parent);
351-
// Not set == INHERIT for defaults.
352-
if ($parentpurposeid == context_instance::INHERIT || $parentpurposeid == context_instance::NOTSET) {
353-
$parentpurposeid = false;
354-
}
355-
if ($parentcategoryid == context_instance::INHERIT || $parentcategoryid == context_instance::NOTSET) {
356-
$parentcategoryid = false;
357-
}
358-
359-
if ($purposeid === false && $parentpurposeid) {
360-
$purposeid = $parentpurposeid;
361-
}
327+
if (context_instance::INHERIT == $purposeid || context_instance::NOTSET == $purposeid) {
328+
$purposeid = $parentpurposeid;
329+
}
362330

363-
if ($categoryid === false && $parentcategoryid) {
364-
$categoryid = $parentcategoryid;
365-
}
331+
if (context_instance::INHERIT == $categoryid || context_instance::NOTSET == $categoryid) {
332+
$categoryid = $parentcategoryid;
366333
}
367334
}
368335

369-
// They may still be false, but we return anyway.
370336
return [$purposeid, $categoryid];
371337
}
372338

@@ -379,7 +345,6 @@ public static function get_effective_default_contextlevel_purpose_and_category($
379345
* @return \core\persistent
380346
*/
381347
private static function get_element_instance($element, $id) {
382-
383348
if ($element !== 'purpose' && $element !== 'category') {
384349
throw new coding_exception('No other elements than purpose and category are allowed');
385350
}

admin/tool/dataprivacy/classes/form/context_instance.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,12 @@ public static function get_context_instance_customdata(\context $context) {
145145
$persistent->set('contextid', $context->id);
146146
}
147147

148-
$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options(
149-
api::get_purposes()
150-
);
151-
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(
152-
api::get_categories()
153-
);
148+
$purposes = [];
149+
foreach (api::get_purposes() as $purpose) {
150+
$purposes[$purpose->get('id')] = $purpose;
151+
}
152+
$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options($purposes);
153+
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(api::get_categories());
154154

155155
$customdata = [
156156
'context' => $context,
@@ -168,9 +168,14 @@ public static function get_context_instance_customdata(\context $context) {
168168
$context);
169169

170170
$customdata['purposeretentionperiods'] = [];
171-
foreach ($purposeoptions as $optionvalue => $unused) {
172-
// Get the effective purpose if $optionvalue would be the selected value.
173-
$purpose = api::get_effective_context_purpose($context, $optionvalue);
171+
foreach (array_keys($purposeoptions) as $optionvalue) {
172+
173+
if (isset($purposes[$optionvalue])) {
174+
$purpose = $purposes[$optionvalue];
175+
} else {
176+
// Get the effective purpose if $optionvalue would be the selected value.
177+
$purpose = api::get_effective_context_purpose($context, $optionvalue);
178+
}
174179

175180
$retentionperiod = self::get_retention_display_text(
176181
$purpose,

0 commit comments

Comments
 (0)