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 participants table.
19
 *
20
 * @package    core_user
21
 * @copyright  2017 Mark Nelson <markn@moodle.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
declare(strict_types=1);
25
 
26
namespace core_user\table;
27
 
28
use DateTime;
29
use context;
30
use core_table\dynamic as dynamic_table;
31
use core_table\local\filter\filterset;
32
use core_user\output\status_field;
33
use core_user\table\participants_search;
34
use moodle_url;
35
 
36
defined('MOODLE_INTERNAL') || die;
37
 
38
global $CFG;
39
 
40
require_once($CFG->libdir . '/tablelib.php');
41
require_once($CFG->dirroot . '/user/lib.php');
42
 
43
/**
44
 * Class for the displaying the participants table.
45
 *
46
 * @package    core_user
47
 * @copyright  2017 Mark Nelson <markn@moodle.com>
48
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
49
 */
50
class participants extends \table_sql implements dynamic_table {
51
 
52
    /**
53
     * @var int $courseid The course id
54
     */
55
    protected $courseid;
56
 
57
    /**
58
     * @var string[] The list of countries.
59
     */
60
    protected $countries;
61
 
62
    /**
63
     * @var \stdClass[] The list of groups with membership info for the course.
64
     */
65
    protected $groups;
66
 
67
    /**
68
     * @var string[] Extra fields to display.
69
     */
70
    protected $extrafields;
71
 
72
    /**
73
     * @var \stdClass $course The course details.
74
     */
75
    protected $course;
76
 
77
    /**
78
     * @var  context $context The course context.
79
     */
80
    protected $context;
81
 
82
    /**
83
     * @var \stdClass[] List of roles indexed by roleid.
84
     */
85
    protected $allroles;
86
 
87
    /**
88
     * @var \stdClass[] List of roles indexed by roleid.
89
     */
90
    protected $allroleassignments;
91
 
92
    /**
93
     * @var \stdClass[] Assignable roles in this course.
94
     */
95
    protected $assignableroles;
96
 
97
    /**
98
     * @var \stdClass[] Profile roles in this course.
99
     */
100
    protected $profileroles;
101
 
102
    /**
103
     * @var filterset Filterset describing which participants to include.
104
     */
105
    protected $filterset;
106
 
107
    /** @var \stdClass[] $viewableroles */
108
    private $viewableroles;
109
 
110
    /** @var moodle_url $baseurl The base URL for the report. */
111
    public $baseurl;
112
 
113
    /**
114
     * Render the participants table.
115
     *
116
     * @param int $pagesize Size of page for paginated displayed table.
117
     * @param bool $useinitialsbar Whether to use the initials bar which will only be used if there is a fullname column defined.
118
     * @param string $downloadhelpbutton
119
     */
120
    public function out($pagesize, $useinitialsbar, $downloadhelpbutton = '') {
121
        global $CFG, $OUTPUT, $PAGE;
122
 
123
        // Define the headers and columns.
124
        $headers = [];
125
        $columns = [];
126
 
127
        // At the very least, the user viewing this table will be able to use bulk actions to export it, so add 'select' column.
128
        $mastercheckbox = new \core\output\checkbox_toggleall('participants-table', true, [
129
            'id' => 'select-all-participants',
130
            'name' => 'select-all-participants',
131
            'label' => get_string('selectall'),
132
            'labelclasses' => 'sr-only',
133
            'classes' => 'm-1',
134
            'checked' => false,
135
        ]);
136
        $headers[] = $OUTPUT->render($mastercheckbox);
137
        $columns[] = 'select';
138
 
139
        $headers[] = get_string('fullname');
140
        $columns[] = 'fullname';
141
 
142
        $extrafields = \core_user\fields::get_identity_fields($this->context);
143
        foreach ($extrafields as $field) {
144
            $headers[] = \core_user\fields::get_display_name($field);
145
            $columns[] = $field;
146
        }
147
 
148
        $headers[] = get_string('roles');
149
        $columns[] = 'roles';
150
 
151
        // Get the list of fields we have to hide.
152
        $hiddenfields = array();
153
        if (!has_capability('moodle/course:viewhiddenuserfields', $this->context)) {
154
            $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
155
        }
156
 
157
        // Add column for groups if the user can view them.
158
        $canseegroups = !isset($hiddenfields['groups']);
159
        if ($canseegroups) {
160
            $headers[] = get_string('groups');
161
            $columns[] = 'groups';
162
        }
163
 
164
        // Do not show the columns if it exists in the hiddenfields array.
165
        if (!isset($hiddenfields['lastaccess'])) {
166
            if ($this->courseid == SITEID) {
167
                $headers[] = get_string('lastsiteaccess');
168
            } else {
169
                $headers[] = get_string('lastcourseaccess');
170
            }
171
            $columns[] = 'lastaccess';
172
        }
173
 
174
        $canreviewenrol = has_capability('moodle/course:enrolreview', $this->context);
175
        if ($canreviewenrol && $this->courseid != SITEID) {
176
            $columns[] = 'status';
177
            $headers[] = get_string('participationstatus', 'enrol');
178
            $this->no_sorting('status');
179
        };
180
 
181
        $this->define_columns($columns);
182
        $this->define_headers($headers);
183
 
184
        // The name column is a header.
185
        $this->define_header_column('fullname');
186
 
187
        // Make this table sorted by last name by default.
188
        $this->sortable(true, 'lastname');
189
 
190
        $this->no_sorting('select');
191
        $this->no_sorting('roles');
192
        if ($canseegroups) {
193
            $this->no_sorting('groups');
194
        }
195
 
196
        $this->set_default_per_page(20);
197
 
198
        $this->set_attribute('id', 'participants');
199
 
200
        $this->countries = get_string_manager()->get_list_of_countries(true);
201
        $this->extrafields = $extrafields;
202
        if ($canseegroups) {
203
            $this->groups = groups_get_all_groups($this->courseid, 0, 0, 'g.*', true);
204
        }
205
 
206
        // If user has capability to review enrol, show them both role names.
207
        $allrolesnamedisplay = ($canreviewenrol ? ROLENAME_BOTH : ROLENAME_ALIAS);
208
        $this->allroles = role_fix_names(get_all_roles($this->context), $this->context, $allrolesnamedisplay);
209
        $this->assignableroles = get_assignable_roles($this->context, ROLENAME_BOTH, false);
210
        $this->profileroles = get_profile_roles($this->context);
211
        $this->viewableroles = get_viewable_roles($this->context);
212
 
213
        parent::out($pagesize, $useinitialsbar, $downloadhelpbutton);
214
 
215
        if (has_capability('moodle/course:enrolreview', $this->context)) {
216
            $params = [
217
                'contextid' => $this->context->id,
218
                'uniqueid' => $this->uniqueid,
219
            ];
220
            $PAGE->requires->js_call_amd('core_user/status_field', 'init', [$params]);
221
        }
222
    }
223
 
224
    /**
225
     * Generate the select column.
226
     *
227
     * @param \stdClass $data
228
     * @return string
229
     */
230
    public function col_select($data) {
231
        global $OUTPUT;
232
 
233
        $checkbox = new \core\output\checkbox_toggleall('participants-table', false, [
234
            'classes' => 'usercheckbox m-1',
235
            'id' => 'user' . $data->id,
236
            'name' => 'user' . $data->id,
237
            'checked' => false,
238
            'label' => get_string('selectitem', 'moodle', fullname($data)),
239
            'labelclasses' => 'accesshide',
240
        ]);
241
 
242
        return $OUTPUT->render($checkbox);
243
    }
244
 
245
    /**
246
     * Generate the fullname column.
247
     *
248
     * @param \stdClass $data
249
     * @return string
250
     */
251
    public function col_fullname($data) {
252
        global $OUTPUT;
253
        return $OUTPUT->render(\core_user::get_profile_picture($data, null,
254
            ['courseid' => $this->course->id, 'includefullname' => true]));
255
    }
256
 
257
    /**
258
     * User roles column.
259
     *
260
     * @param \stdClass $data
261
     * @return string
262
     */
263
    public function col_roles($data) {
264
        global $OUTPUT;
265
 
266
        $roles = isset($this->allroleassignments[$data->id]) ? $this->allroleassignments[$data->id] : [];
267
        $editable = new \core_user\output\user_roles_editable($this->course,
268
                                                              $this->context,
269
                                                              $data,
270
                                                              $this->allroles,
271
                                                              $this->assignableroles,
272
                                                              $this->profileroles,
273
                                                              $roles,
274
                                                              $this->viewableroles);
275
 
276
        return $OUTPUT->render_from_template('core/inplace_editable', $editable->export_for_template($OUTPUT));
277
    }
278
 
279
    /**
280
     * Generate the groups column.
281
     *
282
     * @param \stdClass $data
283
     * @return string
284
     */
285
    public function col_groups($data) {
286
        global $OUTPUT;
287
 
288
        $usergroups = [];
289
        foreach ($this->groups as $coursegroup) {
290
            if (isset($coursegroup->members[$data->id])) {
291
                $usergroups[] = $coursegroup->id;
292
            }
293
        }
294
        $editable = new \core_group\output\user_groups_editable($this->course, $this->context, $data, $this->groups, $usergroups);
295
        return $OUTPUT->render_from_template('core/inplace_editable', $editable->export_for_template($OUTPUT));
296
    }
297
 
298
    /**
299
     * Generate the country column.
300
     *
301
     * @param \stdClass $data
302
     * @return string
303
     */
304
    public function col_country($data) {
305
        if (!empty($this->countries[$data->country])) {
306
            return $this->countries[$data->country];
307
        }
308
        return '';
309
    }
310
 
311
    /**
312
     * Generate the last access column.
313
     *
314
     * @param \stdClass $data
315
     * @return string
316
     */
317
    public function col_lastaccess($data) {
318
        if ($data->lastaccess) {
319
            return format_time(time() - $data->lastaccess);
320
        }
321
 
322
        return get_string('never');
323
    }
324
 
325
    /**
326
     * Generate the status column.
327
     *
328
     * @param \stdClass $data The data object.
329
     * @return string
330
     */
331
    public function col_status($data) {
332
        global $CFG, $OUTPUT, $PAGE;
333
 
334
        $enrolstatusoutput = '';
335
        $canreviewenrol = has_capability('moodle/course:enrolreview', $this->context);
336
        if ($canreviewenrol) {
337
            $canviewfullnames = has_capability('moodle/site:viewfullnames', $this->context);
338
            $fullname = htmlspecialchars(fullname($data, $canviewfullnames), ENT_QUOTES, 'utf-8');
339
            $coursename = format_string($this->course->fullname, true, array('context' => $this->context));
340
            require_once($CFG->dirroot . '/enrol/locallib.php');
341
            $manager = new \course_enrolment_manager($PAGE, $this->course);
342
            $userenrolments = $manager->get_user_enrolments($data->id);
343
            foreach ($userenrolments as $ue) {
344
                $timestart = $ue->timestart;
345
                $timeend = $ue->timeend;
346
                $timeenrolled = $ue->timecreated;
347
                $actions = $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue);
348
                $instancename = $ue->enrolmentinstancename;
349
 
350
                // Default status field label and value.
351
                $status = get_string('participationactive', 'enrol');
352
                $statusval = status_field::STATUS_ACTIVE;
353
                switch ($ue->status) {
354
                    case ENROL_USER_ACTIVE:
355
                        $currentdate = new DateTime();
356
                        $now = $currentdate->getTimestamp();
357
                        $isexpired = $timestart > $now || ($timeend > 0 && $timeend < $now);
358
                        $enrolmentdisabled = $ue->enrolmentinstance->status == ENROL_INSTANCE_DISABLED;
359
                        // If user enrolment status has not yet started/already ended or the enrolment instance is disabled.
360
                        if ($isexpired || $enrolmentdisabled) {
361
                            $status = get_string('participationnotcurrent', 'enrol');
362
                            $statusval = status_field::STATUS_NOT_CURRENT;
363
                        }
364
                        break;
365
                    case ENROL_USER_SUSPENDED:
366
                        $status = get_string('participationsuspended', 'enrol');
367
                        $statusval = status_field::STATUS_SUSPENDED;
368
                        break;
369
                }
370
 
371
                $statusfield = new status_field($instancename, $coursename, $fullname, $status, $timestart, $timeend,
372
                    $actions, $timeenrolled);
373
                $statusfielddata = $statusfield->set_status($statusval)->export_for_template($OUTPUT);
374
                $enrolstatusoutput .= $OUTPUT->render_from_template('core_user/status_field', $statusfielddata);
375
            }
376
        }
377
        return $enrolstatusoutput;
378
    }
379
 
380
    /**
381
     * This function is used for the extra user fields.
382
     *
383
     * These are being dynamically added to the table so there are no functions 'col_<userfieldname>' as
384
     * the list has the potential to increase in the future and we don't want to have to remember to add
385
     * a new method to this class. We also don't want to pollute this class with unnecessary methods.
386
     *
387
     * @param string $colname The column name
388
     * @param \stdClass $data
389
     * @return string
390
     */
391
    public function other_cols($colname, $data) {
392
        // Do not process if it is not a part of the extra fields.
393
        if (!in_array($colname, $this->extrafields)) {
394
            return '';
395
        }
396
 
397
        return s($data->{$colname});
398
    }
399
 
400
    /**
401
     * Query the database for results to display in the table.
402
     *
403
     * @param int $pagesize size of page for paginated displayed table.
404
     * @param bool $useinitialsbar do you want to use the initials bar.
405
     */
406
    public function query_db($pagesize, $useinitialsbar = true) {
407
        list($twhere, $tparams) = $this->get_sql_where();
408
        $psearch = new participants_search($this->course, $this->context, $this->filterset);
409
 
410
        $total = $psearch->get_total_participants_count($twhere, $tparams);
411
 
412
        $this->pagesize($pagesize, $total);
413
 
414
        $sort = $this->get_sql_sort();
415
        if ($sort) {
416
            $sort = 'ORDER BY ' . $sort;
417
        }
418
 
419
        $rawdata = $psearch->get_participants($twhere, $tparams, $sort, $this->get_page_start(), $this->get_page_size());
420
 
421
        $this->rawdata = [];
422
        foreach ($rawdata as $user) {
423
            $this->rawdata[$user->id] = $user;
424
        }
425
        $rawdata->close();
426
 
427
        if ($this->rawdata) {
428
            $this->allroleassignments = get_users_roles($this->context, array_keys($this->rawdata),
429
                    true, 'c.contextlevel DESC, r.sortorder ASC');
430
        } else {
431
            $this->allroleassignments = [];
432
        }
433
 
434
        // Set initial bars.
435
        if ($useinitialsbar) {
436
            $this->initialbars(true);
437
        }
438
    }
439
 
440
    /**
441
     * Override the table show_hide_link to not show for select column.
442
     *
443
     * @param string $column the column name, index into various names.
444
     * @param int $index numerical index of the column.
445
     * @return string HTML fragment.
446
     */
447
    protected function show_hide_link($column, $index) {
448
        if ($index > 0) {
449
            return parent::show_hide_link($column, $index);
450
        }
451
        return '';
452
    }
453
 
454
    /**
455
     * Set filters and build table structure.
456
     *
457
     * @param filterset $filterset The filterset object to get the filters from.
458
     */
459
    public function set_filterset(filterset $filterset): void {
460
        // Get the context.
461
        $this->courseid = $filterset->get_filter('courseid')->current();
462
        $this->course = get_course($this->courseid);
463
        $this->context = \context_course::instance($this->courseid, MUST_EXIST);
464
 
465
        // Process the filterset.
466
        parent::set_filterset($filterset);
467
    }
468
 
469
    /**
470
     * Guess the base url for the participants table.
471
     */
472
    public function guess_base_url(): void {
473
        $this->baseurl = new moodle_url('/user/index.php', ['id' => $this->courseid]);
474
    }
475
 
476
    /**
477
     * Get the context of the current table.
478
     *
479
     * Note: This function should not be called until after the filterset has been provided.
480
     *
481
     * @return context
482
     */
483
    public function get_context(): context {
484
        return $this->context;
485
    }
486
}