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
 * Contains the class used for the displaying the expired contexts table.
19
 *
20
 * @package    tool_dataprivacy
21
 * @copyright  2018 Jun Pataleta <jun@moodle.com>
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
require_once($CFG->libdir . '/tablelib.php');
28
 
29
use coding_exception;
30
use context_helper;
31
use dml_exception;
32
use Exception;
33
use html_writer;
34
use pix_icon;
35
use stdClass;
36
use table_sql;
37
use tool_dataprivacy\api;
38
use tool_dataprivacy\expired_context;
39
use tool_dataprivacy\external\purpose_exporter;
40
use tool_dataprivacy\purpose;
41
 
42
defined('MOODLE_INTERNAL') || die;
43
 
44
/**
45
 * The class for displaying the expired contexts table.
46
 *
47
 * @copyright  2018 Jun Pataleta <jun@moodle.com>
48
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
49
 */
50
class expired_contexts_table extends table_sql {
51
 
52
    /** @var int The context level acting as a filter for this table. */
53
    protected $contextlevel = null;
54
 
55
    /**
56
     * @var bool $selectall Has the user selected all users on the page? True by default.
57
     */
58
    protected $selectall = true;
59
 
60
    /** @var purpose[] Array of purposes by their id. */
61
    protected $purposes = [];
62
 
63
    /** @var purpose[] Map of context => purpose. */
64
    protected $purposemap = [];
65
 
66
    /** @var array List of roles. */
67
    protected $roles = [];
68
 
69
    /**
70
     * expired_contexts_table constructor.
71
     *
72
     * @param int|null $contextlevel
73
     * @throws coding_exception
74
     */
75
    public function __construct($contextlevel = null) {
76
        parent::__construct('expired-contexts-table');
77
 
78
        $this->contextlevel = $contextlevel;
79
 
80
        $columnheaders = [
81
            'name' => get_string('name'),
82
            'info' => get_string('info'),
83
            'purpose' => get_string('purpose', 'tool_dataprivacy'),
84
            'category' => get_string('category', 'tool_dataprivacy'),
85
            'retentionperiod' => get_string('retentionperiod', 'tool_dataprivacy'),
86
            'tobedeleted' => get_string('tobedeleted', 'tool_dataprivacy'),
87
            'timecreated' => get_string('expiry', 'tool_dataprivacy'),
88
        ];
89
        $checkboxattrs = [
90
            'title' => get_string('selectall'),
91
            'data-action' => 'selectall'
92
        ];
93
        $columnheaders['select'] = html_writer::checkbox('selectall', 1, true, null, $checkboxattrs);
94
 
95
        $this->define_columns(array_keys($columnheaders));
96
        $this->define_headers(array_values($columnheaders));
97
        $this->no_sorting('name');
98
        $this->no_sorting('select');
99
        $this->no_sorting('info');
100
        $this->no_sorting('purpose');
101
        $this->no_sorting('category');
102
        $this->no_sorting('retentionperiod');
103
        $this->no_sorting('tobedeleted');
104
 
105
        // Make this table sorted by first name by default.
106
        $this->sortable(true, 'timecreated');
107
 
108
        // We use roles in several places.
109
        $this->roles = role_get_names();
110
    }
111
 
112
    /**
113
     * The context name column.
114
     *
115
     * @param stdClass $expiredctx The row data.
116
     * @return string
117
     * @throws coding_exception
118
     */
119
    public function col_name($expiredctx) {
120
        global $OUTPUT;
121
        $context = context_helper::instance_by_id($expiredctx->get('contextid'));
122
        $parent = $context->get_parent_context();
123
        $contextdata = (object)[
124
            'name' => $context->get_context_name(false, true),
125
            'parent' => $parent->get_context_name(false, true),
126
        ];
127
        $fullcontexts = $context->get_parent_contexts(true);
128
        $contextsinpath = [];
129
        foreach ($fullcontexts as $contextinpath) {
130
            $contextsinpath[] = $contextinpath->get_context_name(false, true);
131
        }
132
        $infoicon = new pix_icon('i/info', implode(' / ', array_reverse($contextsinpath)));
133
        $infoiconhtml = $OUTPUT->render($infoicon);
134
        $name = html_writer::span(get_string('nameandparent', 'tool_dataprivacy', $contextdata), 'mr-1');
135
 
136
        return  $name . $infoiconhtml;
137
    }
138
 
139
    /**
140
     * The context information column.
141
     *
142
     * @param stdClass $expiredctx The row data.
143
     * @return string
144
     * @throws coding_exception
145
     */
146
    public function col_info($expiredctx) {
147
        global $OUTPUT;
148
 
149
        $context = context_helper::instance_by_id($expiredctx->get('contextid'));
150
 
151
        $children = $context->get_child_contexts();
152
        if (empty($children)) {
153
            return get_string('none');
154
        } else {
155
            $childnames = [];
156
            foreach ($children as $child) {
157
                $childnames[] = $child->get_context_name(false, true);
158
            }
159
            $infoicon = new pix_icon('i/info', implode(', ', $childnames));
160
            $infoiconhtml = $OUTPUT->render($infoicon);
161
            $name = html_writer::span(get_string('nchildren', 'tool_dataprivacy', count($children)), 'mr-1');
162
 
163
            return  $name . $infoiconhtml;
164
        }
165
    }
166
 
167
    /**
168
     * The category name column.
169
     *
170
     * @param stdClass $expiredctx The row data.
171
     * @return mixed
172
     * @throws coding_exception
173
     * @throws dml_exception
174
     */
175
    public function col_category($expiredctx) {
176
        $context = context_helper::instance_by_id($expiredctx->get('contextid'));
177
        $category = api::get_effective_context_category($context);
178
 
179
        return s($category->get('name'));
180
    }
181
 
182
    /**
183
     * The purpose column.
184
     *
185
     * @param stdClass $expiredctx The row data.
186
     * @return string
187
     * @throws coding_exception
188
     */
189
    public function col_purpose($expiredctx) {
190
        $purpose = $this->get_purpose_for_expiry($expiredctx);
191
 
192
        return s($purpose->get('name'));
193
    }
194
 
195
    /**
196
     * The retention period column.
197
     *
198
     * @param stdClass $expiredctx The row data.
199
     * @return string
200
     */
201
    public function col_retentionperiod($expiredctx) {
202
        $purpose = $this->get_purpose_for_expiry($expiredctx);
203
 
204
        $expiries = [];
205
 
206
        $expiry = html_writer::tag('dt', get_string('default'), ['class' => 'col-sm-3']);
207
        if ($expiredctx->get('defaultexpired')) {
208
            $expiries[get_string('default')] = get_string('expiredrolewithretention', 'tool_dataprivacy', (object) [
209
                    'retention' => api::format_retention_period(new \DateInterval($purpose->get('retentionperiod'))),
210
                ]);
211
        } else {
212
            $expiries[get_string('default')] = get_string('unexpiredrolewithretention', 'tool_dataprivacy', (object) [
213
                    'retention' => api::format_retention_period(new \DateInterval($purpose->get('retentionperiod'))),
214
                ]);
215
        }
216
 
217
        if (!$expiredctx->is_fully_expired()) {
218
            $purposeoverrides = $purpose->get_purpose_overrides();
219
 
220
            foreach ($expiredctx->get('unexpiredroles') as $roleid) {
221
                $role = $this->roles[$roleid];
222
                $override = $purposeoverrides[$roleid];
223
 
224
                $expiries[$role->localname] = get_string('unexpiredrolewithretention', 'tool_dataprivacy', (object) [
225
                        'retention' => api::format_retention_period(new \DateInterval($override->get('retentionperiod'))),
226
                    ]);
227
            }
228
 
229
            foreach ($expiredctx->get('expiredroles') as $roleid) {
230
                $role = $this->roles[$roleid];
231
                $override = $purposeoverrides[$roleid];
232
 
233
                $expiries[$role->localname] = get_string('expiredrolewithretention', 'tool_dataprivacy', (object) [
234
                        'retention' => api::format_retention_period(new \DateInterval($override->get('retentionperiod'))),
235
                    ]);
236
            }
237
        }
238
 
239
        $output = array_map(function($rolename, $expiry) {
240
            $return = html_writer::tag('dt', $rolename, ['class' => 'col-sm-3']);
241
            $return .= html_writer::tag('dd', $expiry, ['class' => 'col-sm-9']);
242
 
243
            return $return;
244
        }, array_keys($expiries), $expiries);
245
 
246
        return html_writer::tag('dl', implode($output), ['class' => 'row']);
247
    }
248
 
249
    /**
250
     * The timecreated a.k.a. the context expiry date column.
251
     *
252
     * @param stdClass $expiredctx The row data.
253
     * @return string
254
     */
255
    public function col_timecreated($expiredctx) {
256
        return userdate($expiredctx->get('timecreated'));
257
    }
258
 
259
    /**
260
     * Generate the select column.
261
     *
262
     * @param stdClass $expiredctx The row data.
263
     * @return string
264
     */
265
    public function col_select($expiredctx) {
266
        $id = $expiredctx->get('id');
267
        return html_writer::checkbox('expiredcontext_' . $id, $id, $this->selectall, '', ['class' => 'selectcontext']);
268
    }
269
 
270
    /**
271
     * Formatting for the 'tobedeleted' column which indicates in a friendlier fashion whose data will be removed.
272
     *
273
     * @param stdClass $expiredctx The row data.
274
     * @return string
275
     */
276
    public function col_tobedeleted($expiredctx) {
277
        if ($expiredctx->is_fully_expired()) {
278
            return get_string('defaultexpired', 'tool_dataprivacy');
279
        }
280
 
281
        $purpose = $this->get_purpose_for_expiry($expiredctx);
282
 
283
        $a = (object) [];
284
 
285
        $expiredroles = [];
286
        foreach ($expiredctx->get('expiredroles') as $roleid) {
287
            $expiredroles[] = html_writer::tag('li', $this->roles[$roleid]->localname);
288
        }
289
        $a->expired = html_writer::tag('ul', implode($expiredroles));
290
 
291
        $unexpiredroles = [];
292
        foreach ($expiredctx->get('unexpiredroles') as $roleid) {
293
            $unexpiredroles[] = html_writer::tag('li', $this->roles[$roleid]->localname);
294
        }
295
        $a->unexpired = html_writer::tag('ul', implode($unexpiredroles));
296
 
297
        if ($expiredctx->get('defaultexpired')) {
298
            return get_string('defaultexpiredexcept', 'tool_dataprivacy', $a);
299
        } else if (empty($unexpiredroles)) {
300
            return get_string('defaultunexpired', 'tool_dataprivacy', $a);
301
        } else {
302
            return get_string('defaultunexpiredwithexceptions', 'tool_dataprivacy', $a);
303
        }
304
    }
305
 
306
    /**
307
     * Query the database for results to display in the table.
308
     *
309
     * @param int $pagesize size of page for paginated displayed table.
310
     * @param bool $useinitialsbar do you want to use the initials bar.
311
     * @throws dml_exception
312
     * @throws coding_exception
313
     */
314
    public function query_db($pagesize, $useinitialsbar = true) {
315
        // Only count expired contexts that are awaiting confirmation.
316
        $total = expired_context::get_record_count_by_contextlevel($this->contextlevel, expired_context::STATUS_EXPIRED);
317
        $this->pagesize($pagesize, $total);
318
 
319
        $sort = $this->get_sql_sort();
320
        if (empty($sort)) {
321
            $sort = 'timecreated';
322
        }
323
 
324
        // Only load expired contexts that are awaiting confirmation.
325
        $expiredcontexts = expired_context::get_records_by_contextlevel($this->contextlevel, expired_context::STATUS_EXPIRED,
326
            $sort, $this->get_page_start(), $this->get_page_size());
327
 
328
        $this->rawdata = [];
329
        $contextids = [];
330
        foreach ($expiredcontexts as $persistent) {
331
            $this->rawdata[] = $persistent;
332
            $contextids[] = $persistent->get('contextid');
333
        }
334
 
335
        $this->preload_contexts($contextids);
336
 
337
        // Set initial bars.
338
        if ($useinitialsbar) {
339
            $this->initialbars($total > $pagesize);
340
        }
341
    }
342
 
343
    /**
344
     * Override default implementation to display a more meaningful information to the user.
345
     */
346
    public function print_nothing_to_display() {
347
        global $OUTPUT;
348
        echo $this->render_reset_button();
349
        $this->print_initials_bar();
350
        echo $OUTPUT->notification(get_string('noexpiredcontexts', 'tool_dataprivacy'), 'warning');
351
    }
352
 
353
    /**
354
     * Override the table's show_hide_link method to prevent the show/hide link for the select column from rendering.
355
     *
356
     * @param string $column the column name, index into various names.
357
     * @param int $index numerical index of the column.
358
     * @return string HTML fragment.
359
     */
360
    protected function show_hide_link($column, $index) {
361
        if ($index < 6) {
362
            return parent::show_hide_link($column, $index);
363
        }
364
        return '';
365
    }
366
 
367
    /**
368
     * Get the purpose for the specified expired context.
369
     *
370
     * @param   expired_context $expiredcontext
371
     * @return  purpose
372
     */
373
    protected function get_purpose_for_expiry(expired_context $expiredcontext): purpose {
374
        $context = context_helper::instance_by_id($expiredcontext->get('contextid'));
375
 
376
        if (empty($this->purposemap[$context->id])) {
377
            $purpose = api::get_effective_context_purpose($context);
378
            $this->purposemap[$context->id] = $purpose->get('id');
379
 
380
            if (empty($this->purposes[$purpose->get('id')])) {
381
                $this->purposes[$purpose->get('id')] = $purpose;
382
            }
383
        }
384
 
385
        return $this->purposes[$this->purposemap[$context->id]];
386
    }
387
 
388
    /**
389
     * Preload context records given a set of contextids.
390
     *
391
     * @param   array   $contextids
392
     */
393
    protected function preload_contexts(array $contextids) {
394
        global $DB;
395
 
396
        if (empty($contextids)) {
397
            return;
398
        }
399
 
400
        $ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
401
        list($insql, $inparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
402
        $sql = "SELECT {$ctxfields} FROM {context} ctx WHERE ctx.id {$insql}";
403
        $contextlist = $DB->get_recordset_sql($sql, $inparams);
404
        foreach ($contextlist as $contextdata) {
405
            \context_helper::preload_from_record($contextdata);
406
        }
407
        $contextlist->close();
408
 
409
    }
410
}