Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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
 * Output the grading actionbar for this activity.
19
 *
20
 * @package   mod_assign
21
 * @copyright 2021 Adrian Greeve <adrian@moodle.com>
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace mod_assign\output;
26
 
1441 ariadna 27
use assign;
28
use context_module;
29
use core_course\output\actionbar\group_selector;
30
use core_course\output\actionbar\user_selector;
1 efrain 31
use templatable;
32
use renderable;
33
use moodle_url;
1441 ariadna 34
use core\output\local\dropdown\dialog;
1 efrain 35
 
36
/**
37
 * Output the grading actionbar for this activity.
38
 *
39
 * @package   mod_assign
40
 * @copyright 2021 Adrian Greeve <adrian@moodle.com>
41
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42
 */
43
class grading_actionmenu implements templatable, renderable {
44
 
45
    /** @var int Course module ID. */
1441 ariadna 46
    protected int $cmid;
1 efrain 47
    /** @var bool If any submission plugins are enabled. */
1441 ariadna 48
    protected bool $submissionpluginenabled;
1 efrain 49
    /** @var int The number of submissions made. */
1441 ariadna 50
    protected int $submissioncount;
51
    /** @var assign The assign instance. */
52
    protected assign $assign;
1 efrain 53
 
1441 ariadna 54
    /** @var bool If there are submissions to download. */
55
    protected bool $showdownload;
1 efrain 56
 
1441 ariadna 57
    /** @var array Applied user initials filters, containing 'firstname' and 'lastname'. **/
58
    protected array $userinitials;
59
 
60
    /** @var bool true if the user has this capability. Otherwise false. */
61
    private bool $hasviewblind;
62
 
1 efrain 63
    /**
64
     * Constructor for this object.
65
     *
66
     * @param int $cmid Course module ID.
1441 ariadna 67
     * @param null|bool $submissionpluginenabled This parameter has been deprecated since 4.5 and should not be used anymore.
68
     * @param null|int $submissioncount This parameter has been deprecated since 4.5 and should not be used anymore.
69
     * @param assign|null $assign The assign instance. If not provided, it will be loaded based on the cmid.
70
     * @param array $userinitials The user initials to filter the table by.
1 efrain 71
     */
1441 ariadna 72
    public function __construct(
73
        int $cmid,
74
        ?bool $submissionpluginenabled = null,
75
        ?int $submissioncount = null,
76
        ?assign $assign = null,
77
        array $userinitials = []
78
    ) {
1 efrain 79
        $this->cmid = $cmid;
1441 ariadna 80
        if (!$assign) {
81
            $context = context_module::instance($cmid);
82
            $assign = new assign($context, null, null);
83
        }
84
        $this->assign = $assign;
85
        $this->showdownload = $this->assign->is_any_submission_plugin_enabled() && $this->assign->count_submissions();
86
        $this->userinitials = $userinitials;
1 efrain 87
 
1441 ariadna 88
        // Check if we have the elevated view capablities to see the blind details.
89
        $this->hasviewblind = has_capability('mod/assign:viewblinddetails', $this->assign->get_context());
1 efrain 90
    }
91
 
92
    /**
93
     * Data to render in a template.
94
     *
95
     * @param \renderer_base $output renderer base output.
96
     * @return array Data to render.
97
     */
98
    public function export_for_template(\renderer_base $output): array {
1441 ariadna 99
        global $PAGE;
100
 
101
        $course = $this->assign->get_course();
102
        $cm = get_coursemodule_from_id('assign', $this->cmid);
103
        $data = [];
104
 
105
        $userid = optional_param('userid', null, PARAM_INT);
106
        // If the user ID is set, it indicates that a user has been selected. In this case, override the user search
107
        // string with the full name of the selected user.
108
        $usersearch = $userid ? fullname(\core_user::get_user($userid)) : optional_param('search', '', PARAM_NOTAGS);
109
 
110
        $isblind = $this->assign->is_blind_marking() && !$this->hasviewblind;
111
        if ($isblind) {
112
            $usersearch = $userid ? get_string('hiddenuser', 'assign') . $this->assign->get_uniqueid_for_user($userid) : $usersearch;
1 efrain 113
        }
1441 ariadna 114
 
115
        $resetlink = new moodle_url('/mod/assign/view.php', ['id' => $this->cmid, 'action' => 'grading']);
116
        $groupid = groups_get_course_group($course, true);
117
        $userselector = new user_selector(
118
            course: $course,
119
            resetlink: $resetlink,
120
            userid: !$isblind ? $userid : null,
121
            groupid: $groupid,
122
            usersearch: $usersearch,
123
            instanceid: $this->assign->get_instance()->id
124
        );
125
        $data['userselector'] = $userselector->export_for_template($output);
126
 
127
        $hasinitials = !empty($this->userinitials['firstname']) || !empty($this->userinitials['lastname']);
128
        $additionalparams = ['action' => 'grading', 'id' => $this->cmid];
129
 
130
        if (!empty($userid)) {
131
            $additionalparams['userid'] = $userid;
132
        } else if (!empty($usersearch)) {
133
            $additionalparams['search'] = $usersearch;
134
        }
135
 
136
        $initialselector = new \core_course\output\actionbar\initials_selector(
137
            course: $course,
138
            targeturl: 'mod/assign/view.php',
139
            firstinitial: $this->userinitials['firstname'] ?? '',
140
            lastinitial: $this->userinitials['lastname'] ?? '',
141
            firstinitialparam: 'tifirst',
142
            lastinitialparam: 'tilast',
143
            additionalparams: $additionalparams
144
        );
145
 
146
        $data['initialselector'] = $initialselector->export_for_template($output);
147
 
148
        if (groups_get_activity_groupmode($cm, $course)) {
149
            $gs = new group_selector($PAGE->context);
150
            $data['groupselector'] = $gs->export_for_template($output);
151
        }
152
 
153
        if ($extrafiltersdropdown = $this->get_extra_filters_dropdown()) {
154
            $PAGE->requires->js_call_amd('mod_assign/actionbar/grading/extra_filters_dropdown', 'init', []);
155
            $data['extrafiltersdropdown'] = $extrafiltersdropdown->export_for_template($output);
156
        }
157
 
158
        $activitygroup = groups_get_activity_group($cm);
159
        $hasuserfilter = get_user_preferences('assign_filter');
160
        $hasextrafilters = $this->get_applied_extra_filters_count() > 0;
161
        if ($activitygroup || $hasuserfilter || $hasextrafilters || $hasinitials) {
162
            $url = new moodle_url('/mod/assign/view.php', [
163
                'id' => $this->cmid,
164
                'action' => 'grading',
165
                'group' => 0,
166
                'status' => '',
167
                'workflowfilter' => '',
168
                'markingallocationfilter' => '',
169
                'suspendedparticipantsfilter' => 0,
170
                'tifirst' => '',
171
                'tilast' => '',
172
            ]);
173
            $data['pagereset'] = $url->out(false);
174
        }
175
 
176
        if ($this->assign->is_any_submission_plugin_enabled()) {
177
            ['statusmenu' => $statusmenu, 'currentvalue' => $currentvalue] = $this->get_status_menu();
178
            $statusselect = new \core\output\select_menu('status', $statusmenu, $currentvalue);
179
            $statusselect->set_label(get_string('status', 'mod_assign'), [], true);
180
            $data['statusselector'] = $statusselect->export_for_template($output);
181
        }
182
 
183
        if ($this->assign->can_grade()) {
184
            $url = new moodle_url('/mod/assign/view.php', [
185
                'id' => $this->assign->get_course_module()->id,
186
                'action' => 'grader',
187
            ]);
188
            $data['graderurl'] = $url->out(false);
189
        }
190
 
191
        $gradingmanager = get_grading_manager($this->assign->get_context(), 'mod_assign', 'submissions');
192
        $controller = $gradingmanager->get_active_controller();
193
        $showquickgrading = empty($controller) && $this->assign->can_grade();
194
        if ($showquickgrading) {
195
            $quickgradingbaseurl = new moodle_url('/mod/assign/view.php', [
196
                'id' => $this->assign->get_course_module()->id,
197
                'action' => 'grading',
198
            ]);
199
            if ($userid) {
200
                $quickgradingbaseurl->param('userid', $userid);
201
            } else if ($usersearch) {
202
                $quickgradingbaseurl->param('search', $usersearch);
203
            }
204
 
205
            $data['quickgrading'] = [
206
                'baseurl' => $quickgradingbaseurl->out(false),
207
                'enabled' => get_user_preferences('assign_quickgrading', false),
208
            ];
209
        }
210
 
211
        if ($this->showdownload) {
212
            $downloadasfoldersbaseurl = new moodle_url('/mod/assign/view.php', [
213
                'id' => $this->assign->get_course_module()->id,
214
                'action' => 'grading',
215
            ]);
216
            if ($userid) {
217
                $downloadasfoldersbaseurl->param('userid', $userid);
218
            } else if ($usersearch) {
219
                $downloadasfoldersbaseurl->param('search', $usersearch);
220
            }
221
            $downloadasfolders = get_user_preferences('assign_downloadasfolders', 1);
222
            $data['downloadasfolders'] = [
223
                'baseurl' => $downloadasfoldersbaseurl->out(false),
224
                'enabled' => $downloadasfolders,
225
            ];
226
        }
227
 
228
        $actions = $this->get_actions();
229
        if ($actions) {
230
            $menu = new \action_menu();
231
            $menu->set_menu_trigger(get_string('actions'), 'btn btn-outline-primary');
232
            foreach ($actions as $groupkey => $actiongroup) {
233
                foreach ($actiongroup as $label => $url) {
234
                    $menu->add(new \action_menu_link_secondary(new \moodle_url($url), null, $label));
235
                }
236
                if ($groupkey !== array_key_last($actions)) {
237
                    $divider = new \action_menu_filler();
238
                    $divider->primary = false;
239
                    $menu->add($divider);
240
                }
241
            }
242
 
243
            $renderer = $PAGE->get_renderer('core');
244
            $data['actions'] = $renderer->render($menu);
245
        }
246
 
247
        return $data;
248
    }
249
 
250
    /**
251
     * Get the actions for the grading action menu.
252
     *
253
     * @return array A 2D array of actions grouped by a key in the form of key => label => URL.
254
     */
255
    private function get_actions() {
256
        $actions = [];
257
        if (
258
            has_capability('gradereport/grader:view', $this->assign->get_course_context())
259
            && has_capability('moodle/grade:viewall', $this->assign->get_course_context())
260
        ) {
261
            $url = new moodle_url('/grade/report/grader/index.php', ['id' => $this->assign->get_course()->id]);
262
            $actions['gradebook'][get_string('viewgradebook', 'assign')] = $url->out(false);
263
        }
264
        if ($this->assign->is_blind_marking() && has_capability('mod/assign:revealidentities', $this->assign->get_context())) {
265
            $url = new moodle_url('/mod/assign/view.php', [
266
                'id' => $this->assign->get_course_module()->id,
267
                'action' => 'revealidentities',
268
            ]);
269
            $actions['blindmarking'][get_string('revealidentities', 'assign')] = $url->out(false);
270
        }
271
        foreach ($this->assign->get_feedback_plugins() as $plugin) {
272
            if ($plugin->is_enabled() && $plugin->is_visible()) {
273
                foreach ($plugin->get_grading_actions() as $action => $description) {
274
                    $url = new moodle_url('/mod/assign/view.php', [
275
                        'id' => $this->assign->get_course_module()->id,
276
                        'plugin' => $plugin->get_type(),
277
                        'pluginsubtype' => 'assignfeedback',
278
                        'action' => 'viewpluginpage',
279
                        'pluginaction' => $action,
280
                    ]);
281
                    $actions['assignfeedback_' . $plugin->get_type()][$description] = $url->out(false);
282
                }
283
            }
284
        }
285
        if ($this->showdownload) {
286
            $url = new moodle_url('/mod/assign/view.php', [
287
                'id' => $this->assign->get_course_module()->id,
288
                'action' => 'downloadall',
289
            ]);
290
            $actions['downloadall'][get_string('downloadall', 'mod_assign')] = $url->out(false);
291
        }
292
 
293
        return $actions;
294
    }
295
 
296
    /**
297
     * Get the status menu for the grading action menu.
298
     *
299
     * @return array An array containing the status menu and the current value.
300
     */
301
    private function get_status_menu(): array {
302
        $statusmenu = [];
303
        $currentvalue = '';
304
 
305
        $groupedfilters = $this->assign->get_filters(true);
306
        foreach ($groupedfilters as $group => $filters) {
307
            foreach ($filters as $filter) {
308
                if ($filter['key'] === ASSIGN_FILTER_NONE) {
309
                    // The 'none' filter is not a real filter.
310
                    $filter['key'] = '';
311
                }
312
                $url = new moodle_url('/mod/assign/view.php', [
313
                    'id' => $this->assign->get_course_module()->id,
314
                    'action' => 'grading',
315
                    'status' => $filter['key'],
316
                ]);
317
                $statusmenu[$url->out(false)] = $filter['name'];
318
 
319
                if ($filter['active']) {
320
                    $currentvalue = $url->out(false);
321
                }
322
            }
323
            if ($group !== array_key_last($groupedfilters)) {
324
                $statusmenu[] = '';
325
            }
326
        }
327
 
1 efrain 328
        return [
1441 ariadna 329
            'statusmenu' => $statusmenu,
330
            'currentvalue' => $currentvalue,
1 efrain 331
        ];
332
    }
1441 ariadna 333
 
334
    /**
335
     * The renderable for the extra filters dropdown, if available.
336
     *
337
     * @return dialog|null The renderable for the extra filters dropdown, if available.
338
     */
339
    private function get_extra_filters_dropdown(): ?dialog {
340
        global $OUTPUT;
341
 
342
        $dropdowncontentdata = [
343
            'actionurl' => (new moodle_url('/mod/assign/view.php'))->out(false),
344
            'id' => $this->assign->get_course_module()->id,
345
            'action' => 'grading',
346
            'filters' => [],
347
        ];
348
 
349
        // If marking workflow is enabled.
350
        if ($this->assign->get_instance()->markingworkflow) {
351
            $dropdowncontentdata['filters']['markingworkflow'] = [
352
                'workflowfilteroptions' => $this->assign->get_marking_workflow_filters(true),
353
            ];
354
 
355
            // If marking allocation is enabled and the user has the capability to manage marker allocations.
356
            if ($this->assign->get_instance()->markingallocation &&
357
                    has_capability('mod/assign:manageallocations', $this->assign->get_context())) {
358
                $dropdowncontentdata['filters']['markingallocation'] = [
359
                    'markingallocationoptions' => $this->assign->get_marking_allocation_filters(true),
360
                ];
361
            }
362
        }
363
 
364
        if (has_capability('moodle/course:viewsuspendedusers', $this->assign->get_context())) {
365
            $dropdowncontentdata['filters']['suspendedparticipants'] = [
366
                'active' => !$this->assign->show_only_active_users(),
367
            ];
368
        }
369
 
370
        // If there are no available filters, return null.
371
        if (empty($dropdowncontentdata['filters'])) {
372
            return null;
373
        }
374
 
375
        // Define the content output for the extra filters dropdown menu.
376
        $dropdowncontent = $OUTPUT->render_from_template(
377
            'mod_assign/actionbar/grading/extra_filters_dropdown_body',
378
            $dropdowncontentdata
379
        );
380
 
381
        // Define the output for the extra filters dropdown trigger.
382
        $buttoncontent = $OUTPUT->render_from_template(
383
            'mod_assign/actionbar/grading/extra_filters_dropdown_trigger',
384
            ['appliedfilterscount' => $this->get_applied_extra_filters_count()]
385
        );
386
 
387
        return new dialog(
388
            $buttoncontent,
389
            $dropdowncontent,
390
            [
391
                'classes' => 'extrafilters d-flex',
392
                'buttonclasses' => 'btn d-flex border-none align-items-center dropdown-toggle p-0',
393
                'autoclose' => 'outside',
394
            ]
395
        );
396
    }
397
 
398
    /**
399
     * Returns the number of applied extra filters.
400
     *
401
     * @return int The number of applied extra filters.
402
     */
403
    private function get_applied_extra_filters_count(): int {
404
        $appliedextrafilterscount = 0;
405
 
406
        // If marking workflow is enabled.
407
        if ($this->assign->get_instance()->markingworkflow) {
408
            if (get_user_preferences('assign_workflowfilter')) {
409
                $appliedextrafilterscount++;
410
            }
411
 
412
            $canallocatemarker = $this->assign->get_instance()->markingallocation &&
413
                has_capability('mod/assign:manageallocations', $this->assign->get_context());
414
 
415
            if ($canallocatemarker && get_user_preferences('assign_markerfilter')) {
416
                $appliedextrafilterscount++;
417
            }
418
        }
419
 
420
        // If suspended participants are included.
421
        if (!$this->assign->show_only_active_users()) {
422
            $appliedextrafilterscount++;
423
        }
424
 
425
        return $appliedextrafilterscount;
426
    }
1 efrain 427
}