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
 * Renderer for use with the badges output
19
 *
20
 * @package    core
21
 * @subpackage badges
22
 * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
25
 */
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
require_once($CFG->libdir . '/badgeslib.php');
30
require_once($CFG->libdir . '/tablelib.php');
31
 
32
/**
33
 * Standard HTML output renderer for badges
34
 */
35
class core_badges_renderer extends plugin_renderer_base {
36
 
37
    // Outputs badges list.
38
    public function print_badges_list($badges, $userid, $profile = false, $external = false) {
39
        global $USER, $CFG;
40
        foreach ($badges as $badge) {
41
            if (!$external) {
42
                $context = ($badge->type == BADGE_TYPE_SITE) ? context_system::instance() : context_course::instance($badge->courseid);
43
                $bname = $badge->name;
44
                $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f3', false);
45
            } else {
46
                $bname = '';
47
                $imageurl = '';
48
                if (!empty($badge->name)) {
49
                    $bname = s($badge->name);
50
                }
51
                if (!empty($badge->image)) {
52
                    if (is_object($badge->image)) {
53
                        if (!empty($badge->image->caption)) {
54
                            $badge->imagecaption = $badge->image->caption;
55
                        }
56
                        $imageurl = $badge->image->id;
57
                    } else {
58
                        $imageurl = $badge->image;
59
                    }
60
                }
61
                if (isset($badge->assertion->badge->name)) {
62
                    $bname = s($badge->assertion->badge->name);
63
                }
64
                if (isset($badge->imageUrl)) {
65
                    $imageurl = $badge->imageUrl;
66
                }
67
            }
68
 
69
            $name = html_writer::tag('span', $bname, array('class' => 'badge-name'));
70
 
71
            $imagecaption = $badge->imagecaption ?? '';
72
            $image = html_writer::empty_tag('img', ['src' => $imageurl, 'class' => 'badge-image', 'alt' => $imagecaption]);
73
            if (!empty($badge->dateexpire) && $badge->dateexpire < time()) {
74
                $image .= $this->output->pix_icon('i/expired',
75
                        get_string('expireddate', 'badges', userdate($badge->dateexpire)),
76
                        'moodle',
77
                        array('class' => 'expireimage'));
78
                $name .= '(' . get_string('expired', 'badges') . ')';
79
            }
80
 
81
            $download = $status = $push = '';
82
            if (($userid == $USER->id) && !$profile) {
83
                $params = array(
84
                    'download' => $badge->id,
85
                    'hash' => $badge->uniquehash,
86
                    'sesskey' => sesskey()
87
                );
88
                $url = new moodle_url(
89
                    'mybadges.php',
90
                    $params
91
                );
92
                $notexpiredbadge = (empty($badge->dateexpire) || $badge->dateexpire > time());
93
                $userbackpack = badges_get_user_backpack();
94
                if (!empty($CFG->badges_allowexternalbackpack) && $notexpiredbadge && $userbackpack) {
95
                    $assertion = new moodle_url('/badges/assertion.php', array('b' => $badge->uniquehash));
96
                    $icon = new pix_icon('t/backpack', get_string('addtobackpack', 'badges'));
97
                    if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2) {
98
                        $addurl = new moodle_url('/badges/backpack-add.php', array('hash' => $badge->uniquehash));
99
                        $push = $this->output->action_icon($addurl, $icon);
100
                    } else if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2P1) {
101
                        $addurl = new moodle_url('/badges/backpack-export.php', array('hash' => $badge->uniquehash));
102
                        $push = $this->output->action_icon($addurl, $icon);
103
                    }
104
                }
105
 
106
                $download = $this->output->action_icon($url, new pix_icon('t/download', get_string('download')));
107
                if ($badge->visible) {
108
                    $url = new moodle_url('mybadges.php', array('hide' => $badge->issuedid, 'sesskey' => sesskey()));
109
                    $status = $this->output->action_icon($url, new pix_icon('t/hide', get_string('makeprivate', 'badges')));
110
                } else {
111
                    $url = new moodle_url('mybadges.php', array('show' => $badge->issuedid, 'sesskey' => sesskey()));
112
                    $status = $this->output->action_icon($url, new pix_icon('t/show', get_string('makepublic', 'badges')));
113
                }
114
            }
115
 
116
            if (!$profile) {
117
                $url = new moodle_url('badge.php', array('hash' => $badge->uniquehash));
118
            } else {
119
                if (!$external) {
120
                    $url = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
121
                } else {
122
                    $hash = hash('md5', $badge->hostedUrl);
123
                    $url = new moodle_url('/badges/external.php', array('hash' => $hash, 'user' => $userid));
124
                }
125
            }
126
            $actions = html_writer::tag('div', $push . $download . $status, array('class' => 'badge-actions'));
127
            $items[] = html_writer::link($url, $image . $actions . $name, array('title' => $bname));
128
        }
129
 
130
        return html_writer::alist($items, array('class' => 'badges'));
131
    }
132
 
133
    // Recipients selection form.
134
    public function recipients_selection_form(user_selector_base $existinguc, user_selector_base $potentialuc) {
135
        $output = '';
136
        $formattributes = array();
137
        $formattributes['id'] = 'recipientform';
138
        $formattributes['action'] = $this->page->url;
139
        $formattributes['method'] = 'post';
140
        $output .= html_writer::start_tag('form', $formattributes);
141
        $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
142
 
143
        $existingcell = new html_table_cell();
144
        $existingcell->text = $existinguc->display(true);
145
        $existingcell->attributes['class'] = 'existing';
146
        $actioncell = new html_table_cell();
147
        $actioncell->text  = html_writer::start_tag('div', array());
148
        $actioncell->text .= html_writer::empty_tag('input', array(
149
                    'type' => 'submit',
150
                    'name' => 'award',
151
                    'value' => $this->output->larrow() . ' ' . get_string('award', 'badges'),
152
                    'class' => 'actionbutton btn btn-secondary')
153
                );
154
        $actioncell->text .= html_writer::empty_tag('input', array(
155
                    'type' => 'submit',
156
                    'name' => 'revoke',
157
                    'value' => get_string('revoke', 'badges') . ' ' . $this->output->rarrow(),
158
                    'class' => 'actionbutton btn btn-secondary')
159
                );
160
        $actioncell->text .= html_writer::end_tag('div', array());
161
        $actioncell->attributes['class'] = 'actions';
162
        $potentialcell = new html_table_cell();
163
        $potentialcell->text = $potentialuc->display(true);
164
        $potentialcell->attributes['class'] = 'potential';
165
 
166
        $table = new html_table();
167
        $table->attributes['class'] = 'recipienttable boxaligncenter';
168
        $table->data = array(new html_table_row(array($existingcell, $actioncell, $potentialcell)));
169
        $output .= html_writer::table($table);
170
 
171
        $output .= html_writer::end_tag('form');
172
        return $output;
173
    }
174
 
175
    // Prints a badge overview infomation.
176
    public function print_badge_overview($badge, $context) {
177
        $display = "";
178
        $languages = get_string_manager()->get_list_of_languages();
179
 
180
        // Badge details.
181
        $display .= $this->heading(get_string('badgedetails', 'badges'), 3);
182
        $dl = array();
183
        $dl[get_string('name')] = $badge->name;
184
        $dl[get_string('version', 'badges')] = $badge->version;
185
        $dl[get_string('language')] = $languages[$badge->language];
186
        $dl[get_string('description', 'badges')] = $badge->description;
187
        $dl[get_string('createdon', 'search')] = userdate($badge->timecreated);
188
        $dl[get_string('badgeimage', 'badges')] = print_badge_image($badge, $context, 'large');
189
        $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
190
        $dl[get_string('imageauthoremail', 'badges')] =
191
            html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
192
        $dl[get_string('imageauthorurl', 'badges')] =
193
            html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
194
        $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
195
        $tags = \core_tag_tag::get_item_tags('core_badges', 'badge', $badge->id);
196
        $dl[get_string('tags', 'badges')] = $this->output->tag_list($tags, '');
197
        $display .= $this->definition_list($dl);
198
 
199
        // Issuer details.
200
        $display .= $this->heading(get_string('issuerdetails', 'badges'), 3);
201
        $dl = array();
202
        $dl[get_string('issuername', 'badges')] = $badge->issuername;
203
        $dl[get_string('contact', 'badges')] = html_writer::tag('a', $badge->issuercontact, array('href' => 'mailto:' . $badge->issuercontact));
204
        $display .= $this->definition_list($dl);
205
 
206
        // Issuance details if any.
207
        $display .= $this->heading(get_string('issuancedetails', 'badges'), 3);
208
        if ($badge->can_expire()) {
209
            if ($badge->expiredate) {
210
                $display .= get_string('expiredate', 'badges', userdate($badge->expiredate));
211
            } else if ($badge->expireperiod) {
212
                if ($badge->expireperiod < 60) {
213
                    $display .= get_string('expireperiods', 'badges', round($badge->expireperiod, 2));
214
                } else if ($badge->expireperiod < 60 * 60) {
215
                    $display .= get_string('expireperiodm', 'badges', round($badge->expireperiod / 60, 2));
216
                } else if ($badge->expireperiod < 60 * 60 * 24) {
217
                    $display .= get_string('expireperiodh', 'badges', round($badge->expireperiod / 60 / 60, 2));
218
                } else {
219
                    $display .= get_string('expireperiod', 'badges', round($badge->expireperiod / 60 / 60 / 24, 2));
220
                }
221
            }
222
        } else {
223
            $display .= get_string('noexpiry', 'badges');
224
        }
225
 
226
        // Criteria details if any.
227
        $display .= $this->heading(get_string('bcriteria', 'badges'), 3);
228
        if ($badge->has_criteria()) {
229
            $display .= self::print_badge_criteria($badge);
230
        } else {
231
            $display .= get_string('nocriteria', 'badges');
232
            if (has_capability('moodle/badges:configurecriteria', $context)) {
233
                $display .= $this->output->single_button(
234
                    new moodle_url('/badges/criteria.php', array('id' => $badge->id)),
235
                    get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
236
            }
237
        }
238
 
239
        // Awards details if any.
240
        if (has_capability('moodle/badges:viewawarded', $context)) {
241
            $display .= $this->heading(get_string('awards', 'badges'), 3);
242
            if ($badge->has_awards()) {
243
                $url = new moodle_url('/badges/recipients.php', array('id' => $badge->id));
244
                $a = new stdClass();
245
                $a->link = $url->out();
246
                $a->count = count($badge->get_awards());
247
                $display .= get_string('numawards', 'badges', $a);
248
            } else {
249
                $display .= get_string('noawards', 'badges');
250
            }
251
 
252
            if (has_capability('moodle/badges:awardbadge', $context) &&
253
                $badge->has_manual_award_criteria() &&
254
                $badge->is_active()) {
255
                $display .= $this->output->single_button(
256
                        new moodle_url('/badges/award.php', array('id' => $badge->id)),
257
                        get_string('award', 'badges'), 'POST', array('class' => 'activatebadge'));
258
            }
259
        }
260
 
261
        $display .= self::print_badge_endorsement($badge);
262
        $display .= self::print_badge_related($badge);
263
        $display .= self::print_badge_alignments($badge);
264
 
265
        return html_writer::div($display, null, array('id' => 'badge-overview'));
266
    }
267
 
268
    /**
269
     * Prints action icons for the badge.
270
     *
271
     * @deprecated sinde Moodle 4.3
272
     * @param \core_badges\badge $badge
273
     * @param \context $context
274
     * @return string
275
     */
276
    public function print_badge_table_actions($badge, $context) {
277
        debugging("print_badge_table_actions() is deprecated.", DEBUG_DEVELOPER);
278
        $actions = "";
279
 
280
        if (has_capability('moodle/badges:configuredetails', $context) && $badge->has_criteria()) {
281
            // Activate/deactivate badge.
282
            if ($badge->status == BADGE_STATUS_INACTIVE || $badge->status == BADGE_STATUS_INACTIVE_LOCKED) {
283
                // "Activate" will go to another page and ask for confirmation.
284
                $url = new moodle_url('/badges/action.php');
285
                $url->param('id', $badge->id);
286
                $url->param('activate', true);
287
                $url->param('sesskey', sesskey());
288
                $return = new moodle_url(qualified_me());
289
                $url->param('return', $return->out_as_local_url(false));
290
                $actions .= $this->output->action_icon($url, new pix_icon('t/show', get_string('activate', 'badges'))) . " ";
291
            } else {
292
                $url = new moodle_url(qualified_me());
293
                $url->param('lock', $badge->id);
294
                $url->param('sesskey', sesskey());
295
                $actions .= $this->output->action_icon($url, new pix_icon('t/hide', get_string('deactivate', 'badges'))) . " ";
296
            }
297
        }
298
 
299
        // Award badge manually.
300
        if ($badge->has_manual_award_criteria() &&
301
                has_capability('moodle/badges:awardbadge', $context) &&
302
                $badge->is_active()) {
303
            $url = new moodle_url('/badges/award.php', array('id' => $badge->id));
304
            $actions .= $this->output->action_icon($url, new pix_icon('t/award', get_string('award', 'badges'))) . " ";
305
        }
306
 
307
        // Edit badge.
308
        if (has_capability('moodle/badges:configuredetails', $context)) {
309
            $url = new moodle_url('/badges/edit.php', array('id' => $badge->id, 'action' => 'badge'));
310
            $actions .= $this->output->action_icon($url, new pix_icon('t/edit', get_string('edit'))) . " ";
311
        }
312
 
313
        // Duplicate badge.
314
        if (has_capability('moodle/badges:createbadge', $context)) {
315
            $url = new moodle_url('/badges/action.php', array('copy' => '1', 'id' => $badge->id, 'sesskey' => sesskey()));
316
            $actions .= $this->output->action_icon($url, new pix_icon('t/copy', get_string('copy'))) . " ";
317
        }
318
 
319
        // Delete badge.
320
        if (has_capability('moodle/badges:deletebadge', $context)) {
321
            $url = new moodle_url(qualified_me());
322
            $url->param('delete', $badge->id);
323
            $actions .= $this->output->action_icon($url, new pix_icon('t/delete', get_string('delete'))) . " ";
324
        }
325
 
326
        return $actions;
327
    }
328
 
329
    /**
330
     * Render an issued badge.
331
     *
332
     * @param \core_badges\output\issued_badge $ibadge
333
     * @return string
334
     */
335
    protected function render_issued_badge(\core_badges\output\issued_badge $ibadge) {
336
        $data = $ibadge->export_for_template($this);
337
        return parent::render_from_template('core_badges/issued_badge', $data);
338
    }
339
 
340
    /**
341
     * Render an issued badge.
342
     *
343
     * @param \core_badges\output\badgeclass $badge
344
     * @return string
345
     */
346
    protected function render_badgeclass(\core_badges\output\badgeclass $badge) {
347
        $data = $badge->export_for_template($this);
348
        return parent::render_from_template('core_badges/issued_badge', $data);
349
    }
350
 
351
    /**
352
     * Render an external badge.
353
     *
354
     * @param \core_badges\output\external_badge $ibadge
355
     * @return string
356
     */
357
    protected function render_external_badge(\core_badges\output\external_badge $ibadge) {
358
        $data = $ibadge->export_for_template($this);
359
        return parent::render_from_template('core_badges/issued_badge', $data);
360
    }
361
 
362
    /**
363
     * Render a collection of user badges.
364
     *
365
     * @param \core_badges\output\badge_user_collection $badges
366
     * @return string
367
     */
368
    protected function render_badge_user_collection(\core_badges\output\badge_user_collection $badges) {
369
        global $CFG, $USER, $SITE;
370
        $backpack = $badges->backpack;
371
        $mybackpack = new moodle_url('/badges/mybackpack.php');
372
 
373
        $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
374
        $htmlpagingbar = $this->render($paging);
375
 
376
        // Set backpack connection string.
377
        $backpackconnect = '';
378
        if (!empty($CFG->badges_allowexternalbackpack) && is_null($backpack)) {
379
            $backpackconnect = $this->output->box(get_string('localconnectto', 'badges', $mybackpack->out()), 'noticebox');
380
        }
381
        // Search box.
382
        $searchform = $this->output->box($this->helper_search_form($badges->search), 'boxwidthwide boxaligncenter');
383
 
384
        // Download all button.
385
        $actionhtml = $this->output->single_button(
386
                    new moodle_url('/badges/mybadges.php', array('downloadall' => true, 'sesskey' => sesskey())),
387
                    get_string('downloadall'), 'POST', array('class' => 'activatebadge'));
388
        $downloadall = $this->output->box('', 'col-md-3');
389
        $downloadall .= $this->output->box($actionhtml, 'col-md-9');
390
        $downloadall = $this->output->box($downloadall, 'row ml-5');
391
 
392
        // Local badges.
393
        $localhtml = html_writer::start_tag('div', array('id' => 'issued-badge-table', 'class' => 'generalbox'));
394
        $sitename = format_string($SITE->fullname, true, array('context' => context_system::instance()));
395
        $heading = get_string('localbadges', 'badges', $sitename);
396
        $localhtml .= $this->output->heading_with_help($heading, 'localbadgesh', 'badges');
397
        if ($badges->badges) {
398
            $countmessage = $this->output->box(get_string('badgesearned', 'badges', $badges->totalcount));
399
 
400
            $htmllist = $this->print_badges_list($badges->badges, $USER->id);
401
            $localhtml .= $backpackconnect . $countmessage . $searchform;
402
            $localhtml .= $htmlpagingbar . $htmllist . $htmlpagingbar . $downloadall;
403
        } else {
404
            $localhtml .= $searchform . $this->output->notification(get_string('nobadges', 'badges'), 'info');
405
        }
406
        $localhtml .= html_writer::end_tag('div');
407
 
408
        // External badges.
409
        $externalhtml = "";
410
        if (!empty($CFG->badges_allowexternalbackpack)) {
411
            $externalhtml .= html_writer::start_tag('div', array('class' => 'generalbox'));
412
            $externalhtml .= $this->output->heading_with_help(get_string('externalbadges', 'badges'), 'externalbadges', 'badges');
413
            if (!is_null($backpack)) {
414
                if ($backpack->totalcollections == 0) {
415
                    $externalhtml .= get_string('nobackpackcollectionssummary', 'badges', $backpack);
416
                } else {
417
                    if ($backpack->totalbadges == 0) {
418
                        $externalhtml .= get_string('nobackpackbadgessummary', 'badges', $backpack);
419
                    } else {
420
                        $externalhtml .= get_string('backpackbadgessummary', 'badges', $backpack);
421
                        $externalhtml .= '<br/><br/>' . $this->print_badges_list($backpack->badges, $USER->id, true, true);
422
                    }
423
                }
424
            } else {
425
                $externalhtml .= get_string('externalconnectto', 'badges', $mybackpack->out());
426
            }
427
 
428
            $externalhtml .= html_writer::end_tag('div');
429
            $attr = ['class' => 'btn btn-secondary'];
430
            $label = get_string('backpackbadgessettings', 'badges');
431
            $backpacksettings = html_writer::link(new moodle_url('/badges/mybackpack.php'), $label, $attr);
432
            $actionshtml = $this->output->box('', 'col-md-3');
433
            $actionshtml .= $this->output->box($backpacksettings, 'col-md-9');
434
            $actionshtml = $this->output->box($actionshtml, 'row ml-5');
435
            $externalhtml .= $actionshtml;
436
        }
437
 
438
        return $localhtml . $externalhtml;
439
    }
440
 
441
    /**
442
     * Render a collection of badges.
443
     *
444
     * @param \core_badges\output\badge_collection $badges
445
     * @return string
446
     *
447
     * @deprecated since Moodle 4.4
448
     * @todo MDL-80455 this will be removed in Moodle 4.8
449
     */
450
    protected function render_badge_collection(\core_badges\output\badge_collection $badges) {
451
        debugging('The method render_badge_collection() has been deprecated', DEBUG_DEVELOPER);
452
        $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
453
        $htmlpagingbar = $this->render($paging);
454
        $table = new html_table();
455
        $table->attributes['class'] = 'table table-bordered table-striped';
456
 
457
        $sortbyname = $this->helper_sortable_heading(get_string('name'),
458
                'name', $badges->sort, $badges->dir);
459
        $sortbyawarded = $this->helper_sortable_heading(get_string('awardedtoyou', 'badges'),
460
                'dateissued', $badges->sort, $badges->dir);
461
        $table->head = array(
462
                    get_string('badgeimage', 'badges'),
463
                    $sortbyname,
464
                    get_string('description', 'badges'),
465
                    get_string('bcriteria', 'badges'),
466
                    $sortbyawarded
467
                );
468
        $table->colclasses = array('badgeimage', 'name', 'description', 'criteria', 'awards');
469
 
470
        foreach ($badges->badges as $badge) {
471
            $badgeimage = print_badge_image($badge, $this->page->context, 'large');
472
            $name = $badge->name;
473
            $description = $badge->description;
474
            $criteria = self::print_badge_criteria($badge);
475
            if ($badge->dateissued) {
476
                $icon = new pix_icon('i/valid',
477
                            get_string('dateearned', 'badges',
478
                                userdate($badge->dateissued, get_string('strftimedatefullshort', 'core_langconfig'))));
479
                $badgeurl = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
480
                $awarded = $this->output->action_icon($badgeurl, $icon, null, null, true);
481
            } else {
482
                $awarded = "";
483
            }
484
            $row = array($badgeimage, $name, $description, $criteria, $awarded);
485
            $table->data[] = $row;
486
        }
487
 
488
        $htmltable = html_writer::table($table);
489
 
490
        return $htmlpagingbar . $htmltable . $htmlpagingbar;
491
    }
492
 
493
    /**
494
     * Render a table of badges.
495
     *
496
     * @deprecated since Moodle 4.3
497
     * @param \core_badges\output\badge_management $badges
498
     * @return string
499
     */
500
    protected function render_badge_management(\core_badges\output\badge_management $badges) {
501
        debugging("render_badge_management() is deprecated.", DEBUG_DEVELOPER);
502
        $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
503
 
504
        // New badge button.
505
        $htmlnew = '';
506
        $htmlpagingbar = $this->render($paging);
507
        $table = new html_table();
508
        $table->attributes['class'] = 'table table-bordered table-striped';
509
 
510
        $sortbyname = $this->helper_sortable_heading(get_string('name'),
511
                'name', $badges->sort, $badges->dir);
512
        $sortbystatus = $this->helper_sortable_heading(get_string('status', 'badges'),
513
                'status', $badges->sort, $badges->dir);
514
        $table->head = array(
515
                $sortbyname,
516
                $sortbystatus,
517
                get_string('bcriteria', 'badges'),
518
                get_string('awards', 'badges'),
519
                get_string('actions')
520
            );
521
        $table->colclasses = array('name', 'status', 'criteria', 'awards', 'actions');
522
 
523
        foreach ($badges->badges as $b) {
524
            $style = !$b->is_active() ? array('class' => 'dimmed') : array();
525
            $forlink =  print_badge_image($b, $this->page->context) . ' ' .
526
                        html_writer::start_tag('span') . $b->name . html_writer::end_tag('span');
527
            $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $b->id)), $forlink, $style);
528
            $status = $b->statstring;
529
            $criteria = self::print_badge_criteria($b, 'short');
530
 
531
            if (has_capability('moodle/badges:viewawarded', $this->page->context)) {
532
                $awards = html_writer::link(new moodle_url('/badges/recipients.php', array('id' => $b->id)), $b->awards);
533
            } else {
534
                $awards = $b->awards;
535
            }
536
 
537
            $actions = self::print_badge_table_actions($b, $this->page->context);
538
 
539
            $row = array($name, $status, $criteria, $awards, $actions);
540
            $table->data[] = $row;
541
        }
542
        $htmltable = html_writer::table($table);
543
 
544
        return $htmlnew . $htmlpagingbar . $htmltable . $htmlpagingbar;
545
    }
546
 
547
    /**
548
     * @deprecated since Moodle 4.0 - Use the manage_badge_action_bar tertiary navigation instead.
549
     */
550
    public function print_badge_tabs() {
551
        throw new coding_exception(__FUNCTION__ . '() has been removed.');
552
    }
553
 
554
    /**
555
     * Prints badge status box.
556
     *
557
     * @param badge $badge
558
     * @return Either the status box html as a string or null
559
     */
560
    public function print_badge_status_box(badge $badge) {
561
        if (has_capability('moodle/badges:configurecriteria', $badge->get_context())) {
562
 
563
            if (!$badge->has_criteria()) {
564
                $criteriaurl = new moodle_url('/badges/criteria.php', array('id' => $badge->id));
565
                $status = get_string('nocriteria', 'badges');
566
                if ($this->page->url != $criteriaurl) {
567
                    $action = $this->output->single_button(
568
                        $criteriaurl,
569
                        get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
570
                } else {
571
                    $action = '';
572
                }
573
 
574
                $message = $status . $action;
575
            } else {
576
                $status = get_string('statusmessage_' . $badge->status, 'badges');
577
                if ($badge->is_active()) {
578
                    $action = $this->output->single_button(new moodle_url('/badges/action.php',
579
                                array('id' => $badge->id, 'lock' => 1, 'sesskey' => sesskey(),
580
                                      'return' => $this->page->url->out_as_local_url(false))),
581
                            get_string('deactivate', 'badges'), 'POST', array('class' => 'activatebadge'));
582
                } else {
583
                    $action = $this->output->single_button(new moodle_url('/badges/action.php',
584
                                array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(),
585
                                      'return' => $this->page->url->out_as_local_url(false))),
586
                            get_string('activate', 'badges'), 'POST', array('class' => 'activatebadge'));
587
                }
588
 
589
                $message = $status . $this->output->help_icon('status', 'badges') . $action;
590
 
591
            }
592
 
593
            $style = $badge->is_active() ? 'generalbox statusbox active' : 'generalbox statusbox inactive';
594
            return $this->output->box($message, $style);
595
        }
596
 
597
        return null;
598
    }
599
 
600
    /**
601
     * Returns information about badge criteria in a list form.
602
     *
603
     * @param badge $badge Badge objects
604
     * @param string $short Indicates whether to print full info about this badge
605
     * @return string $output HTML string to output
606
     */
607
    public function print_badge_criteria(badge $badge, $short = '') {
608
        $agg = $badge->get_aggregation_methods();
609
        if (empty($badge->criteria)) {
610
            return get_string('nocriteria', 'badges');
611
        }
612
 
613
        $overalldescr = '';
614
        $overall = $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL];
615
        if (!$short && !empty($overall->description)) {
616
            $overalldescr = $this->output->box(
617
                format_text($overall->description, $overall->descriptionformat, array('context' => $badge->get_context())),
618
                'criteria-description'
619
                );
620
        }
621
 
622
        // Get the condition string.
623
        $condition = '';
624
        if (count($badge->criteria) != 2) {
625
            $condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
626
                                      core_text::strtoupper($agg[$badge->get_aggregation_method()]));
627
        }
628
 
629
        unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
630
 
631
        $items = array();
632
        // If only one criterion left, make sure its description goe to the top.
633
        if (count($badge->criteria) == 1) {
634
            $c = reset($badge->criteria);
635
            if (!$short && !empty($c->description)) {
636
                $overalldescr = $this->output->box(
637
                    format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
638
                    'criteria-description'
639
                    );
640
            }
641
            if (count($c->params) == 1) {
642
                $items[] = get_string('criteria_descr_single_' . $short . $c->criteriatype , 'badges') .
643
                           $c->get_details($short);
644
            } else {
645
                $items[] = get_string('criteria_descr_' . $short . $c->criteriatype, 'badges',
646
                        core_text::strtoupper($agg[$badge->get_aggregation_method($c->criteriatype)])) .
647
                        $c->get_details($short);
648
            }
649
        } else {
650
            foreach ($badge->criteria as $type => $c) {
651
                $criteriadescr = '';
652
                if (!$short && !empty($c->description)) {
653
                    $criteriadescr = $this->output->box(
654
                        format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
655
                        'criteria-description'
656
                        );
657
                }
658
                if (count($c->params) == 1) {
659
                    $items[] = get_string('criteria_descr_single_' . $short . $type , 'badges') .
660
                               $c->get_details($short) . $criteriadescr;
661
                } else {
662
                    $items[] = get_string('criteria_descr_' . $short . $type , 'badges',
663
                            core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) .
664
                            $c->get_details($short) .
665
                            $criteriadescr;
666
                }
667
            }
668
        }
669
 
670
        return $overalldescr . $condition . html_writer::alist($items, array(), 'ul');;
671
    }
672
 
673
    /**
674
     * Prints criteria actions for badge editing.
675
     *
676
     * @param badge $badge
677
     * @return string
678
     */
679
    public function print_criteria_actions(badge $badge) {
680
        $output = '';
681
        if (!$badge->is_active() && !$badge->is_locked()) {
682
            $accepted = $badge->get_accepted_criteria();
683
            $potential = array_diff($accepted, array_keys($badge->criteria));
684
 
685
            if (!empty($potential)) {
686
                foreach ($potential as $p) {
687
                    if ($p != 0) {
688
                        $select[$p] = get_string('criteria_' . $p, 'badges');
689
                    }
690
                }
691
                $output .= $this->output->single_select(
692
                    new moodle_url('/badges/criteria_settings.php', array('badgeid' => $badge->id, 'add' => true)),
693
                    'type',
694
                    $select,
695
                    '',
696
                    array('' => 'choosedots'),
697
                    null,
698
                    array('label' => get_string('addbadgecriteria', 'badges'))
699
                );
700
            } else {
701
                $output .= $this->output->box(get_string('nothingtoadd', 'badges'), 'clearfix');
702
            }
703
        }
704
 
705
        return $output;
706
    }
707
 
708
    /**
709
     * Renders a table with users who have earned the badge.
710
     * Based on stamps collection plugin.
711
     *
712
     * @param \core_badges\output\badge_recipients $recipients
713
     * @return string
714
     *
715
     * @deprecated since Moodle 4.4
716
     * @todo MDL-80455 this will be removed in Moodle 4.8
717
     */
718
    protected function render_badge_recipients(\core_badges\output\badge_recipients $recipients) {
719
        debugging('The method render_badge_recipients() has been deprecated', DEBUG_DEVELOPER);
720
        $paging = new paging_bar($recipients->totalcount, $recipients->page, $recipients->perpage, $this->page->url, 'page');
721
        $htmlpagingbar = $this->render($paging);
722
        $table = new html_table();
723
        $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
724
 
725
        $sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'),
726
                'firstname', $recipients->sort, $recipients->dir);
727
        $sortbylastname = $this->helper_sortable_heading(get_string('lastname'),
728
                'lastname', $recipients->sort, $recipients->dir);
729
        if ($this->helper_fullname_format() == 'lf') {
730
            $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
731
        } else {
732
            $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
733
        }
734
 
735
        $sortbydate = $this->helper_sortable_heading(get_string('dateawarded', 'badges'),
736
                'dateissued', $recipients->sort, $recipients->dir);
737
 
738
        $table->head = array($sortbyname, $sortbydate, '');
739
 
740
        foreach ($recipients->userids as $holder) {
741
            $fullname = fullname($holder);
742
            $fullname = html_writer::link(
743
                            new moodle_url('/user/profile.php', array('id' => $holder->userid)),
744
                            $fullname
745
                        );
746
            $awarded  = userdate($holder->dateissued);
747
            $badgeurl = html_writer::link(
748
                            new moodle_url('/badges/badge.php', array('hash' => $holder->uniquehash)),
749
                            get_string('viewbadge', 'badges')
750
                        );
751
 
752
            $row = array($fullname, $awarded, $badgeurl);
753
            $table->data[] = $row;
754
        }
755
 
756
        $htmltable = html_writer::table($table);
757
 
758
        return $htmlpagingbar . $htmltable . $htmlpagingbar;
759
    }
760
 
761
    ////////////////////////////////////////////////////////////////////////////
762
    // Helper methods
763
    // Reused from stamps collection plugin
764
    ////////////////////////////////////////////////////////////////////////////
765
 
766
    /**
767
     * Renders a text with icons to sort by the given column
768
     *
769
     * This is intended for table headings.
770
     *
771
     * @param string $text    The heading text
772
     * @param string $sortid  The column id used for sorting
773
     * @param string $sortby  Currently sorted by (column id)
774
     * @param string $sorthow Currently sorted how (ASC|DESC)
775
     *
776
     * @return string
777
     */
778
    protected function helper_sortable_heading($text, $sortid = null, $sortby = null, $sorthow = null) {
779
        $out = html_writer::tag('span', $text, array('class' => 'text'));
780
 
781
        if (!is_null($sortid)) {
782
            if ($sortby !== $sortid || $sorthow !== 'ASC') {
783
                $url = new moodle_url($this->page->url);
784
                $url->params(array('sort' => $sortid, 'dir' => 'ASC'));
785
                $out .= $this->output->action_icon($url,
786
                        new pix_icon('t/sort_asc', get_string('sortbyx', 'core', s($text)), null, array('class' => 'iconsort')));
787
            }
788
            if ($sortby !== $sortid || $sorthow !== 'DESC') {
789
                $url = new moodle_url($this->page->url);
790
                $url->params(array('sort' => $sortid, 'dir' => 'DESC'));
791
                $out .= $this->output->action_icon($url,
792
                        new pix_icon('t/sort_desc', get_string('sortbyxreverse', 'core', s($text)), null, array('class' => 'iconsort')));
793
            }
794
        }
795
        return $out;
796
    }
797
    /**
798
     * Tries to guess the fullname format set at the site
799
     *
800
     * @return string fl|lf
801
     */
802
    protected function helper_fullname_format() {
803
        $fake = new stdClass();
804
        $fake->lastname = 'LLLL';
805
        $fake->firstname = 'FFFF';
806
        $fullname = get_string('fullnamedisplay', '', $fake);
807
        if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
808
            return 'lf';
809
        } else {
810
            return 'fl';
811
        }
812
    }
813
    /**
814
     * Renders a search form
815
     *
816
     * @param string $search Search string
817
     * @return string HTML
818
     */
819
    protected function helper_search_form($search) {
820
        global $CFG;
821
        require_once($CFG->libdir . '/formslib.php');
822
 
823
        $mform = new MoodleQuickForm('searchform', 'POST', $this->page->url);
824
 
825
        $mform->addElement('hidden', 'sesskey', sesskey());
826
 
827
        $el[] = $mform->createElement('text', 'search', get_string('search'), array('size' => 20));
828
        $mform->setDefault('search', $search);
829
        $el[] = $mform->createElement('submit', 'submitsearch', get_string('search'));
830
        $el[] = $mform->createElement('submit', 'clearsearch', get_string('clear'));
831
        $mform->addGroup($el, 'searchgroup', get_string('searchname', 'badges'), ' ', false);
832
 
833
        ob_start();
834
        $mform->display();
835
        $out = ob_get_clean();
836
 
837
        return $out;
838
    }
839
 
840
    /**
841
     * Renders a definition list
842
     *
843
     * @param array $items the list of items to define
844
     * @param array
845
     */
846
    protected function definition_list(array $items, array $attributes = array()) {
847
        $output = html_writer::start_tag('dl', $attributes);
848
        foreach ($items as $label => $value) {
849
            $output .= html_writer::tag('dt', $label);
850
            $output .= html_writer::tag('dd', $value);
851
        }
852
        $output .= html_writer::end_tag('dl');
853
        return $output;
854
    }
855
 
856
    /**
857
     * Outputs list en badges.
858
     *
859
     * @param badge $badge Badge object.
860
     * @return string $output content endorsement to output.
861
     */
862
    protected function print_badge_endorsement(badge $badge) {
863
        $output = '';
864
        $endorsement = $badge->get_endorsement();
865
        $dl = array();
866
        $output .= $this->heading(get_string('endorsement', 'badges'), 3);
867
        if (!empty($endorsement)) {
868
            $dl[get_string('issuername', 'badges')] = $endorsement->issuername;
869
            $dl[get_string('issueremail', 'badges')] =
870
                html_writer::tag('a', $endorsement->issueremail, array('href' => 'mailto:' . $endorsement->issueremail));
871
            $dl[get_string('issuerurl', 'badges')] = html_writer::link($endorsement->issuerurl, $endorsement->issuerurl,
872
                array('target' => '_blank'));
873
            $dl[get_string('dateawarded', 'badges')] = userdate($endorsement->dateissued);
874
            $dl[get_string('claimid', 'badges')] = html_writer::link($endorsement->claimid, $endorsement->claimid,
875
            array('target' => '_blank'));
876
            $dl[get_string('claimcomment', 'badges')] = $endorsement->claimcomment;
877
            $output .= $this->definition_list($dl);
878
        } else {
879
            $output .= get_string('noendorsement', 'badges');
880
        }
881
        return $output;
882
    }
883
 
884
    /**
885
     * Print list badges related.
886
     *
887
     * @param badge $badge Badge objects.
888
     * @return string $output List related badges to output.
889
     */
890
    protected function print_badge_related(badge $badge) {
891
        $output = '';
892
        $relatedbadges = $badge->get_related_badges();
893
        $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
894
        if (!empty($relatedbadges)) {
895
            $items = array();
896
            foreach ($relatedbadges as $related) {
897
                $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
898
                $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
899
            }
900
            $output .= html_writer::alist($items, array(), 'ul');
901
        } else {
902
            $output .= get_string('norelated', 'badges');
903
        }
904
        return $output;
905
    }
906
 
907
    /**
908
     * Print list badge alignments.
909
     *
910
     * @param badge $badge Badge objects.
911
     * @return string $output List alignments to output.
912
     */
913
    protected function print_badge_alignments(badge $badge) {
914
        $output = '';
915
        $output .= $this->heading(get_string('alignment', 'badges'), 3);
916
        $alignments = $badge->get_alignments();
917
        if (!empty($alignments)) {
918
            $items = array();
919
            foreach ($alignments as $alignment) {
920
                $urlaligment = new moodle_url('alignment.php',
921
                    array('id' => $badge->id, 'alignmentid' => $alignment->id)
922
                );
923
                $items[] = html_writer::link($urlaligment, $alignment->targetname, array('target' => '_blank'));
924
            }
925
            $output .= html_writer::alist($items, array(), 'ul');
926
        } else {
927
            $output .= get_string('noalignment', 'badges');
928
        }
929
        return $output;
930
    }
931
 
932
    /**
933
     * Renders a table for related badges.
934
     *
935
     * @param \core_badges\output\badge_related $related list related badges.
936
     * @return string list related badges to output.
937
     */
938
    protected function render_badge_related(\core_badges\output\badge_related $related) {
939
        $currentbadge = new badge($related->currentbadgeid);
940
        $languages = get_string_manager()->get_list_of_languages();
941
        $paging = new paging_bar($related->totalcount, $related->page, $related->perpage, $this->page->url, 'page');
942
        $htmlpagingbar = $this->render($paging);
943
        $table = new html_table();
944
        $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
945
        $table->head = array(
946
            get_string('name'),
947
            get_string('version', 'badges'),
948
            get_string('language', 'badges'),
949
            get_string('type', 'badges')
950
        );
951
        if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
952
            array_push($table->head, '');
953
        }
954
 
955
        foreach ($related->badges as $badge) {
956
            $badgeobject = new badge($badge->id);
957
            $style = array('title' => $badgeobject->name);
958
            if (!$badgeobject->is_active()) {
959
                $style['class'] = 'dimmed';
960
            }
961
            $context = ($badgeobject->type == BADGE_TYPE_SITE) ?
962
                context_system::instance() : context_course::instance($badgeobject->courseid);
963
            $forlink = print_badge_image($badgeobject, $context) . ' ' .
964
                html_writer::start_tag('span') . $badgeobject->name . html_writer::end_tag('span');
965
            $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $badgeobject->id)), $forlink, $style);
966
 
967
            $row = array(
968
                $name,
969
                $badge->version,
970
                $badge->language ? $languages[$badge->language] : '',
971
                $badge->type == BADGE_TYPE_COURSE ? get_string('badgesview', 'badges') : get_string('sitebadges', 'badges')
972
            );
973
            if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
974
                $action = $this->output->action_icon(
975
                    new moodle_url('/badges/related_action.php', [
976
                        'badgeid' => $related->currentbadgeid,
977
                        'relatedid' => $badge->id,
978
                        'sesskey' => sesskey(),
979
                        'action' => 'remove'
980
                    ]),
981
                    new pix_icon('t/delete', get_string('delete')));
982
                $actions = html_writer::tag('div', $action, array('class' => 'badge-actions'));
983
                array_push($row, $actions);
984
            }
985
            $table->data[] = $row;
986
        }
987
        $htmltable = html_writer::table($table);
988
 
989
        return $htmlpagingbar . $htmltable . $htmlpagingbar;
990
    }
991
 
992
    /**
993
     * Renders a table with alignment.
994
     *
995
     * @param core_badges\output\badge_alignments $alignments List alignments.
996
     * @return string List alignment to output.
997
     */
998
    protected function render_badge_alignments(\core_badges\output\badge_alignments $alignments) {
999
        $currentbadge = new badge($alignments->currentbadgeid);
1000
        $paging = new paging_bar($alignments->totalcount, $alignments->page, $alignments->perpage, $this->page->url, 'page');
1001
        $htmlpagingbar = $this->render($paging);
1002
        $table = new html_table();
1003
        $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1004
        $table->head = array('Name', 'URL', '');
1005
 
1006
        foreach ($alignments->alignments as $item) {
1007
            $urlaligment = new moodle_url('alignment.php',
1008
                array(
1009
                    'id' => $currentbadge->id,
1010
                    'alignmentid' => $item->id,
1011
                )
1012
            );
1013
            $row = array(
1014
                html_writer::link($urlaligment, $item->targetname),
1015
                html_writer::link($item->targeturl, $item->targeturl, array('target' => '_blank'))
1016
            );
1017
            if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1018
                $delete = $this->output->action_icon(
1019
                    new moodle_url('/badges/alignment_action.php', [
1020
                        'id' => $currentbadge->id,
1021
                        'alignmentid' => $item->id,
1022
                        'sesskey' => sesskey(),
1023
                        'action' => 'remove'
1024
                    ]),
1025
                    new pix_icon('t/delete', get_string('delete'))
1026
                );
1027
                $edit = $this->output->action_icon(
1028
                    new moodle_url('alignment.php',
1029
                        array(
1030
                            'id' => $currentbadge->id,
1031
                            'alignmentid' => $item->id,
1032
                            'action' => 'edit'
1033
                        )
1034
                    ), new pix_icon('t/edit', get_string('edit')));
1035
                $actions = html_writer::tag('div', $edit . $delete, array('class' => 'badge-actions'));
1036
                array_push($row, $actions);
1037
            }
1038
            $table->data[] = $row;
1039
        }
1040
        $htmltable = html_writer::table($table);
1041
 
1042
        return $htmlpagingbar . $htmltable . $htmlpagingbar;
1043
    }
1044
 
1045
    /**
1046
     * Defer to template.
1047
     *
1048
     * @param \core_badges\output\external_backpacks_page $page
1049
     * @return bool|string
1050
     */
1051
    public function render_external_backpacks_page(\core_badges\output\external_backpacks_page $page) {
1052
        $data = $page->export_for_template($this);
1053
        return parent::render_from_template('core_badges/external_backpacks_page', $data);
1054
    }
1055
 
1056
    /**
1057
     * Get the result of a backpack validation with its settings. It returns:
1058
     * - A informative message if the backpack version is different from OBv2.
1059
     * - A warning with the error if it's not possible to connect to this backpack.
1060
     * - A successful message if the connection has worked.
1061
     *
1062
     * @param  int    $backpackid The backpack identifier.
1063
     * @return string A message with the validation result.
1064
     */
1065
    public function render_test_backpack_result(int $backpackid): string {
1066
        // Get the backpack.
1067
        $backpack = badges_get_site_backpack($backpackid);
1068
 
1069
        // Add the header to the result.
1070
        $result = $this->heading(get_string('testbackpack', 'badges', $backpack->backpackweburl));
1071
 
1072
        if ($backpack->apiversion != OPEN_BADGES_V2) {
1073
            // Only OBv2 supports this validation.
1074
            $result .= get_string('backpackconnectionnottested', 'badges');
1075
        } else {
1076
            $message = badges_verify_backpack($backpackid);
1077
            if (empty($message)) {
1078
                $result .= get_string('backpackconnectionok', 'badges');
1079
            } else {
1080
                $result .= $message;
1081
            }
1082
        }
1083
 
1084
        return $result;
1085
    }
1086
 
1087
    /**
1088
     * Render the tertiary navigation for the page.
1089
     *
1090
     * @param \core_badges\output\base_action_bar $actionbar
1091
     * @return bool|string
1092
     */
1093
    public function render_tertiary_navigation(\core_badges\output\base_action_bar $actionbar) {
1094
        return $this->render_from_template($actionbar->get_template(), $actionbar->export_for_template($this));
1095
    }
1096
}