Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Data registry renderable.
19
 *
20
 * @package    tool_dataprivacy
21
 * @copyright  2018 David Monllao
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
namespace tool_dataprivacy\output;
25
defined('MOODLE_INTERNAL') || die();
26
 
27
use renderable;
28
use renderer_base;
29
use stdClass;
30
use templatable;
31
use tool_dataprivacy\data_registry;
32
 
33
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
34
require_once($CFG->libdir . '/blocklib.php');
35
 
36
/**
37
 * Class containing the data registry renderable
38
 *
39
 * @copyright  2018 David Monllao
40
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41
 */
42
class data_registry_page implements renderable, templatable {
43
 
44
    /**
45
     * @var int
46
     */
47
    private $defaultcontextlevel;
48
 
49
    /**
50
     * @var int
51
     */
52
    private $defaultcontextid;
53
 
54
    /**
55
     * Constructor.
56
     *
57
     * @param int $defaultcontextlevel
58
     * @param int $defaultcontextid
59
     * @return null
60
     */
61
    public function __construct($defaultcontextlevel = false, $defaultcontextid = false) {
62
        $this->defaultcontextlevel = $defaultcontextlevel;
63
        $this->defaultcontextid = $defaultcontextid;
64
    }
65
 
66
    /**
67
     * Export this data so it can be used as the context for a mustache template.
68
     *
69
     * @param renderer_base $output
70
     * @return stdClass
71
     */
72
    public function export_for_template(renderer_base $output) {
73
        global $PAGE;
74
 
75
        $params = [\context_system::instance()->id, $this->defaultcontextlevel, $this->defaultcontextid];
76
        $PAGE->requires->js_call_amd('tool_dataprivacy/data_registry', 'init', $params);
77
 
78
        $data = new stdClass();
79
        $defaultsbutton = new \action_link(
80
            new \moodle_url('/admin/tool/dataprivacy/defaults.php'),
81
            get_string('setdefaults', 'tool_dataprivacy'),
82
            null,
83
            ['class' => 'btn btn-primary']
84
        );
85
        $data->defaultsbutton = $defaultsbutton->export_for_template($output);
86
 
87
        $actionmenu = new \action_menu();
88
        $actionmenu->set_menu_trigger(get_string('edit'), 'btn btn-primary');
89
        $actionmenu->set_owner_selector('dataregistry-actions');
90
 
91
        $url = new \moodle_url('/admin/tool/dataprivacy/categories.php');
92
        $categories = new \action_menu_link_secondary($url, null, get_string('categories', 'tool_dataprivacy'));
93
        $actionmenu->add($categories);
94
 
95
        $url = new \moodle_url('/admin/tool/dataprivacy/purposes.php');
96
        $purposes = new \action_menu_link_secondary($url, null, get_string('purposes', 'tool_dataprivacy'));
97
        $actionmenu->add($purposes);
98
 
99
        $data->actions = $actionmenu->export_for_template($output);
100
 
101
        if (!data_registry::defaults_set()) {
102
            $data->info = (object)[
103
                    'message' => get_string('dataregistryinfo', 'tool_dataprivacy'),
104
                    'announce' => 1
105
            ];
106
            $data->nosystemdefaults = (object)[
107
                'message' => get_string('nosystemdefaults', 'tool_dataprivacy'),
108
                'announce' => 1
109
            ];
110
        }
111
 
112
        $data->tree = $this->get_default_tree_structure();
113
 
114
        return $data;
115
    }
116
 
117
    /**
118
     * Returns the tree default structure.
119
     *
120
     * @return array
121
     */
122
    private function get_default_tree_structure() {
123
 
124
        $frontpage = \context_course::instance(SITEID);
125
 
126
        $categorybranches = $this->get_all_category_branches();
127
 
128
        $elements = [
129
            'text' => get_string('contextlevelname' . CONTEXT_SYSTEM, 'tool_dataprivacy'),
130
            'contextlevel' => CONTEXT_SYSTEM,
131
            'branches' => [
132
                [
133
                    'text' => get_string('user'),
134
                    'contextlevel' => CONTEXT_USER,
135
                ], [
136
                    'text' => get_string('categories'),
137
                    'branches' => $categorybranches,
138
                    'expandelement' => 'category',
139
                ], [
140
                    'text' => get_string('frontpagecourse', 'tool_dataprivacy'),
141
                    'contextid' => $frontpage->id,
142
                    'branches' => [
143
                        [
144
                            'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
145
                            'expandcontextid' => $frontpage->id,
146
                            'expandelement' => 'module',
147
                            'expanded' => 0,
148
                        ], [
149
                            'text' => get_string('blocks'),
150
                            'expandcontextid' => $frontpage->id,
151
                            'expandelement' => 'block',
152
                            'expanded' => 0,
153
                        ],
154
                    ]
155
                ]
156
            ]
157
        ];
158
 
159
        // Returned as an array to follow a common array format.
160
        return [self::complete($elements, $this->defaultcontextlevel, $this->defaultcontextid)];
161
    }
162
 
163
    /**
164
     * Returns the hierarchy of system course categories.
165
     *
166
     * @return array
167
     */
168
    private function get_all_category_branches() {
169
 
170
        $categories = data_registry::get_site_categories();
171
 
172
        $categoriesbranch = [];
173
        while (count($categories) > 0) {
174
            foreach ($categories as $key => $category) {
175
 
176
                $context = \context_coursecat::instance($category->id);
177
                $newnode = [
178
                    'text' => shorten_text(format_string($category->name, true, ['context' => $context])),
179
                    'categoryid' => $category->id,
180
                    'contextid' => $context->id,
181
                ];
182
                if ($category->coursecount > 0) {
183
                    $newnode['branches'] = [
184
                        [
185
                            'text' => get_string('courses'),
186
                            'expandcontextid' => $context->id,
187
                            'expandelement' => 'course',
188
                            'expanded' => 0,
189
                        ]
190
                    ];
191
                }
192
 
193
                $added = false;
194
                if ($category->parent == 0) {
195
                    // New categories root-level node.
196
                    $categoriesbranch[] = $newnode;
197
                    $added = true;
198
 
199
                } else {
200
                    // Add the new node under the appropriate parent.
201
                    if ($this->add_to_parent_category_branch($category, $newnode, $categoriesbranch)) {
202
                        $added = true;
203
                    }
204
                }
205
 
206
                if ($added) {
207
                    unset($categories[$key]);
208
                }
209
            }
210
        }
211
 
212
        return $categoriesbranch;
213
    }
214
 
215
    /**
216
     * Gets the courses branch for the provided category.
217
     *
218
     * @param \context $catcontext
219
     * @return array
220
     */
221
    public static function get_courses_branch(\context $catcontext) {
222
 
223
        if ($catcontext->contextlevel !== CONTEXT_COURSECAT) {
224
            throw new \coding_exception('A course category context should be provided');
225
        }
226
 
227
        $coursecat = \core_course_category::get($catcontext->instanceid);
228
        $courses = $coursecat->get_courses();
229
 
230
        $branches = [];
231
 
232
        foreach ($courses as $course) {
233
 
234
            $coursecontext = \context_course::instance($course->id);
235
 
236
            $coursenode = [
237
                'text' => shorten_text(format_string($course->shortname, true, ['context' => $coursecontext])),
238
                'contextid' => $coursecontext->id,
239
                'branches' => [
240
                    [
241
                        'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
242
                        'expandcontextid' => $coursecontext->id,
243
                        'expandelement' => 'module',
244
                        'expanded' => 0,
245
                    ], [
246
                        'text' => get_string('blocks'),
247
                        'expandcontextid' => $coursecontext->id,
248
                        'expandelement' => 'block',
249
                        'expanded' => 0,
250
                    ],
251
                ]
252
            ];
253
            $branches[] = self::complete($coursenode);
254
        }
255
 
256
        return $branches;
257
    }
258
 
259
    /**
260
     * Gets the modules branch for the provided course.
261
     *
262
     * @param \context $coursecontext
263
     * @return array
264
     */
265
    public static function get_modules_branch(\context $coursecontext) {
266
 
267
        if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
268
            throw new \coding_exception('A course context should be provided');
269
        }
270
 
271
        $branches = [];
272
 
273
        // Using the current user.
274
        $modinfo = get_fast_modinfo($coursecontext->instanceid);
275
        foreach ($modinfo->get_instances() as $moduletype => $instances) {
276
            foreach ($instances as $cm) {
277
 
278
                if (!$cm->uservisible) {
279
                    continue;
280
                }
281
 
282
                $a = (object)[
283
                    'instancename' => shorten_text($cm->get_formatted_name()),
284
                    'modulename' => get_string('pluginname', 'mod_' . $moduletype),
285
                ];
286
 
287
                $text = get_string('moduleinstancename', 'tool_dataprivacy', $a);
288
                $branches[] = self::complete([
289
                    'text' => $text,
290
                    'contextid' => $cm->context->id,
291
                ]);
292
            }
293
        }
294
 
295
        return $branches;
296
    }
297
 
298
    /**
299
     * Gets the blocks branch for the provided course.
300
     *
301
     * @param \context $coursecontext
302
     * @return null
303
     */
304
    public static function get_blocks_branch(\context $coursecontext) {
305
        global $DB;
306
 
307
        if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
308
            throw new \coding_exception('A course context should be provided');
309
        }
310
 
311
        $branches = [];
312
 
313
        $children = $coursecontext->get_child_contexts();
314
        foreach ($children as $childcontext) {
315
 
316
            if ($childcontext->contextlevel !== CONTEXT_BLOCK) {
317
                continue;
318
            }
319
 
320
            $blockinstance = block_instance_by_id($childcontext->instanceid);
321
            $displayname = shorten_text(format_string($blockinstance->get_title(), true, ['context' => $childcontext]));
322
            $branches[] = self::complete([
323
                'text' => $displayname,
324
                'contextid' => $childcontext->id,
325
            ]);
326
 
327
        }
328
 
329
        return $branches;
330
    }
331
 
332
    /**
333
     * Adds the provided category to the categories branch.
334
     *
335
     * @param stdClass $category
336
     * @param array $newnode
337
     * @param array $categoriesbranch
338
     * @return bool
339
     */
340
    private function add_to_parent_category_branch($category, $newnode, &$categoriesbranch) {
341
 
342
        foreach ($categoriesbranch as $key => $branch) {
343
            if (!empty($branch['categoryid']) && $branch['categoryid'] == $category->parent) {
344
                // It may be empty (if it does not contain courses and this is the first child cat).
345
                if (!isset($categoriesbranch[$key]['branches'])) {
346
                    $categoriesbranch[$key]['branches'] = [];
347
                }
348
                $categoriesbranch[$key]['branches'][] = $newnode;
349
                return true;
350
            }
351
            if (!empty($branch['branches'])) {
352
                $parent = $this->add_to_parent_category_branch($category, $newnode, $categoriesbranch[$key]['branches']);
353
                if ($parent) {
354
                    return true;
355
                }
356
            }
357
        }
358
 
359
        return false;
360
    }
361
 
362
    /**
363
     * Completes tree nodes with default values.
364
     *
365
     * @param array $node
366
     * @param int|false $currentcontextlevel
367
     * @param int|false $currentcontextid
368
     * @return array
369
     */
370
    private static function complete($node, $currentcontextlevel = false, $currentcontextid = false) {
371
        if (!isset($node['active'])) {
372
            if ($currentcontextlevel && !empty($node['contextlevel']) &&
373
                    $currentcontextlevel == $node['contextlevel'] &&
374
                    empty($currentcontextid)) {
375
                // This is the active context level, we also checked that there
376
                // is no default contextid set.
377
                $node['active'] = true;
378
            } else if ($currentcontextid && !empty($node['contextid']) &&
379
                    $currentcontextid == $node['contextid']) {
380
                $node['active'] = true;
381
            } else {
382
                $node['active'] = null;
383
            }
384
        }
385
 
386
        if (!isset($node['branches'])) {
387
            $node['branches'] = [];
388
        } else {
389
            foreach ($node['branches'] as $key => $childnode) {
390
                $node['branches'][$key] = self::complete($childnode, $currentcontextlevel, $currentcontextid);
391
            }
392
        }
393
 
394
        if (!isset($node['expandelement'])) {
395
            $node['expandelement'] = null;
396
        }
397
 
398
        if (!isset($node['expandcontextid'])) {
399
            $node['expandcontextid'] = null;
400
        }
401
 
402
        if (!isset($node['contextid'])) {
403
            $node['contextid'] = null;
404
        }
405
 
406
        if (!isset($node['contextlevel'])) {
407
            $node['contextlevel'] = null;
408
        }
409
 
410
        if (!isset($node['expanded'])) {
411
            if (!empty($node['branches'])) {
412
                $node['expanded'] = 1;
413
            } else {
414
                $node['expanded'] = 0;
415
            }
416
        }
417
        return $node;
418
    }
419
 
420
    /**
421
     * From a list of purpose persistents to a list of id => name purposes.
422
     *
423
     * @param \tool_dataprivacy\purpose[] $purposes
424
     * @param bool $includenotset
425
     * @param bool $includeinherit
426
     * @return string[]
427
     */
428
    public static function purpose_options($purposes, $includenotset = true, $includeinherit = true) {
429
        $options = self::base_options($includenotset, $includeinherit);
430
        foreach ($purposes as $purpose) {
431
            $options[$purpose->get('id')] = $purpose->get('name');
432
        }
433
 
434
        return $options;
435
    }
436
 
437
    /**
438
     * From a list of category persistents to a list of id => name categories.
439
     *
440
     * @param \tool_dataprivacy\category[] $categories
441
     * @param bool $includenotset
442
     * @param bool $includeinherit
443
     * @return string[]
444
     */
445
    public static function category_options($categories, $includenotset = true, $includeinherit = true) {
446
        $options = self::base_options($includenotset, $includeinherit);
447
        foreach ($categories as $category) {
448
            $options[$category->get('id')] = $category->get('name');
449
        }
450
 
451
        return $options;
452
    }
453
 
454
    /**
455
     * Base not set and inherit options.
456
     *
457
     * @param bool $includenotset
458
     * @param bool $includeinherit
459
     * @return array
460
     */
461
    private static function base_options($includenotset = true, $includeinherit = true) {
462
 
463
        $options = [];
464
 
465
        if ($includenotset) {
466
            $options[\tool_dataprivacy\context_instance::NOTSET] = get_string('notset', 'tool_dataprivacy');
467
        }
468
 
469
        if ($includeinherit) {
470
            $options[\tool_dataprivacy\context_instance::INHERIT] = get_string('inherit', 'tool_dataprivacy');
471
        }
472
 
473
        return $options;
474
    }
475
}