28a182bed4ef2550acca9c41ff959129a1969ca2
[moodle.git] / badges / renderer.php
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/>.
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  */
27 require_once($CFG->libdir . '/badgeslib.php');
28 require_once($CFG->libdir . '/tablelib.php');
30 /**
31  * Standard HTML output renderer for badges
32  */
33 class core_badges_renderer extends plugin_renderer_base {
35     // Outputs badges list.
36     public function print_badges_list($badges, $userid, $profile = false, $external = false) {
37         global $USER, $CFG;
38         foreach ($badges as $badge) {
39             if (!$external) {
40                 $context = ($badge->type == BADGE_TYPE_SITE) ? context_system::instance() : context_course::instance($badge->courseid);
41                 $bname = $badge->name;
42                 $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false);
43             } else {
44                 $bname = '';
45                 $imageurl = '';
46                 if (!empty($badge->name)) {
47                     $bname = s($badge->name);
48                 }
49                 if (!empty($badge->image)) {
50                     $imageurl = $badge->image;
51                 }
52                 if (isset($badge->assertion->badge->name)) {
53                     $bname = s($badge->assertion->badge->name);
54                 }
55                 if (isset($badge->imageUrl)) {
56                     $imageurl = $badge->imageUrl;
57                 }
58             }
60             $name = html_writer::tag('span', $bname, array('class' => 'badge-name'));
62             $image = html_writer::empty_tag('img', array('src' => $imageurl, 'class' => 'badge-image'));
63             if (!empty($badge->dateexpire) && $badge->dateexpire < time()) {
64                 $image .= $this->output->pix_icon('i/expired',
65                         get_string('expireddate', 'badges', userdate($badge->dateexpire)),
66                         'moodle',
67                         array('class' => 'expireimage'));
68                 $name .= '(' . get_string('expired', 'badges') . ')';
69             }
71             $download = $status = $push = '';
72             if (($userid == $USER->id) && !$profile) {
73                 $params = array(
74                     'download' => $badge->id,
75                     'hash' => $badge->uniquehash,
76                     'sesskey' => sesskey()
77                 );
78                 $url = new moodle_url(
79                     'mybadges.php',
80                     $params
81                 );
82                 $notexpiredbadge = (empty($badge->dateexpire) || $badge->dateexpire > time());
83                 $backpackexists = badges_user_has_backpack($USER->id);
84                 if (!empty($CFG->badges_allowexternalbackpack) && $notexpiredbadge && $backpackexists) {
85                     $assertion = new moodle_url('/badges/assertion.php', array('b' => $badge->uniquehash));
86                     $action = null;
87                     if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
88                         $action = new component_action('click', 'addtobackpack', array('assertion' => $assertion->out(false)));
89                         $addurl = new moodle_url('#');
90                     } else if (badges_open_badges_backpack_api() == OPEN_BADGES_V2P1) {
91                         $addurl = new moodle_url('/badges/backpack-export.php', array('hash' => $badge->uniquehash));
92                     } else {
93                         $addurl = new moodle_url('/badges/backpack-add.php', array('hash' => $badge->uniquehash));
94                     }
95                     $icon = new pix_icon('t/backpack', get_string('addtobackpack', 'badges'));
96                     $push = $this->output->action_icon($addurl, $icon, $action);
97                 }
99                 $download = $this->output->action_icon($url, new pix_icon('t/download', get_string('download')));
100                 if ($badge->visible) {
101                     $url = new moodle_url('mybadges.php', array('hide' => $badge->issuedid, 'sesskey' => sesskey()));
102                     $status = $this->output->action_icon($url, new pix_icon('t/hide', get_string('makeprivate', 'badges')));
103                 } else {
104                     $url = new moodle_url('mybadges.php', array('show' => $badge->issuedid, 'sesskey' => sesskey()));
105                     $status = $this->output->action_icon($url, new pix_icon('t/show', get_string('makepublic', 'badges')));
106                 }
107             }
109             if (!$profile) {
110                 $url = new moodle_url('badge.php', array('hash' => $badge->uniquehash));
111             } else {
112                 if (!$external) {
113                     $url = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
114                 } else {
115                     $hash = hash('md5', $badge->hostedUrl);
116                     $url = new moodle_url('/badges/external.php', array('hash' => $hash, 'user' => $userid));
117                 }
118             }
119             $actions = html_writer::tag('div', $push . $download . $status, array('class' => 'badge-actions'));
120             $items[] = html_writer::link($url, $image . $actions . $name, array('title' => $bname));
121         }
123         return html_writer::alist($items, array('class' => 'badges'));
124     }
126     // Recipients selection form.
127     public function recipients_selection_form(user_selector_base $existinguc, user_selector_base $potentialuc) {
128         $output = '';
129         $formattributes = array();
130         $formattributes['id'] = 'recipientform';
131         $formattributes['action'] = $this->page->url;
132         $formattributes['method'] = 'post';
133         $output .= html_writer::start_tag('form', $formattributes);
134         $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
136         $existingcell = new html_table_cell();
137         $existingcell->text = $existinguc->display(true);
138         $existingcell->attributes['class'] = 'existing';
139         $actioncell = new html_table_cell();
140         $actioncell->text  = html_writer::start_tag('div', array());
141         $actioncell->text .= html_writer::empty_tag('input', array(
142                     'type' => 'submit',
143                     'name' => 'award',
144                     'value' => $this->output->larrow() . ' ' . get_string('award', 'badges'),
145                     'class' => 'actionbutton btn btn-secondary')
146                 );
147         $actioncell->text .= html_writer::empty_tag('input', array(
148                     'type' => 'submit',
149                     'name' => 'revoke',
150                     'value' => get_string('revoke', 'badges') . ' ' . $this->output->rarrow(),
151                     'class' => 'actionbutton btn btn-secondary')
152                 );
153         $actioncell->text .= html_writer::end_tag('div', array());
154         $actioncell->attributes['class'] = 'actions';
155         $potentialcell = new html_table_cell();
156         $potentialcell->text = $potentialuc->display(true);
157         $potentialcell->attributes['class'] = 'potential';
159         $table = new html_table();
160         $table->attributes['class'] = 'recipienttable boxaligncenter';
161         $table->data = array(new html_table_row(array($existingcell, $actioncell, $potentialcell)));
162         $output .= html_writer::table($table);
164         $output .= html_writer::end_tag('form');
165         return $output;
166     }
168     // Prints a badge overview infomation.
169     public function print_badge_overview($badge, $context) {
170         $display = "";
171         $languages = get_string_manager()->get_list_of_languages();
173         // Badge details.
174         $display .= $this->heading(get_string('badgedetails', 'badges'), 3);
175         $dl = array();
176         $dl[get_string('name')] = $badge->name;
177         $dl[get_string('version', 'badges')] = $badge->version;
178         $dl[get_string('language')] = $languages[$badge->language];
179         $dl[get_string('description', 'badges')] = $badge->description;
180         $dl[get_string('createdon', 'search')] = userdate($badge->timecreated);
181         $dl[get_string('badgeimage', 'badges')] = print_badge_image($badge, $context, 'large');
182         $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
183         $dl[get_string('imageauthoremail', 'badges')] =
184             html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
185         $dl[get_string('imageauthorurl', 'badges')] =
186             html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
187         $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
188         $display .= $this->definition_list($dl);
190         // Issuer details.
191         $display .= $this->heading(get_string('issuerdetails', 'badges'), 3);
192         $dl = array();
193         $dl[get_string('issuername', 'badges')] = $badge->issuername;
194         $dl[get_string('contact', 'badges')] = html_writer::tag('a', $badge->issuercontact, array('href' => 'mailto:' . $badge->issuercontact));
195         $display .= $this->definition_list($dl);
197         // Issuance details if any.
198         $display .= $this->heading(get_string('issuancedetails', 'badges'), 3);
199         if ($badge->can_expire()) {
200             if ($badge->expiredate) {
201                 $display .= get_string('expiredate', 'badges', userdate($badge->expiredate));
202             } else if ($badge->expireperiod) {
203                 if ($badge->expireperiod < 60) {
204                     $display .= get_string('expireperiods', 'badges', round($badge->expireperiod, 2));
205                 } else if ($badge->expireperiod < 60 * 60) {
206                     $display .= get_string('expireperiodm', 'badges', round($badge->expireperiod / 60, 2));
207                 } else if ($badge->expireperiod < 60 * 60 * 24) {
208                     $display .= get_string('expireperiodh', 'badges', round($badge->expireperiod / 60 / 60, 2));
209                 } else {
210                     $display .= get_string('expireperiod', 'badges', round($badge->expireperiod / 60 / 60 / 24, 2));
211                 }
212             }
213         } else {
214             $display .= get_string('noexpiry', 'badges');
215         }
217         // Criteria details if any.
218         $display .= $this->heading(get_string('bcriteria', 'badges'), 3);
219         if ($badge->has_criteria()) {
220             $display .= self::print_badge_criteria($badge);
221         } else {
222             $display .= get_string('nocriteria', 'badges');
223             if (has_capability('moodle/badges:configurecriteria', $context)) {
224                 $display .= $this->output->single_button(
225                     new moodle_url('/badges/criteria.php', array('id' => $badge->id)),
226                     get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
227             }
228         }
230         // Awards details if any.
231         if (has_capability('moodle/badges:viewawarded', $context)) {
232             $display .= $this->heading(get_string('awards', 'badges'), 3);
233             if ($badge->has_awards()) {
234                 $url = new moodle_url('/badges/recipients.php', array('id' => $badge->id));
235                 $a = new stdClass();
236                 $a->link = $url->out();
237                 $a->count = count($badge->get_awards());
238                 $display .= get_string('numawards', 'badges', $a);
239             } else {
240                 $display .= get_string('noawards', 'badges');
241             }
243             if (has_capability('moodle/badges:awardbadge', $context) &&
244                 $badge->has_manual_award_criteria() &&
245                 $badge->is_active()) {
246                 $display .= $this->output->single_button(
247                         new moodle_url('/badges/award.php', array('id' => $badge->id)),
248                         get_string('award', 'badges'), 'POST', array('class' => 'activatebadge'));
249             }
250         }
252         $display .= self::print_badge_endorsement($badge);
253         $display .= self::print_badge_related($badge);
254         $display .= self::print_badge_alignments($badge);
256         return html_writer::div($display, null, array('id' => 'badge-overview'));
257     }
259     // Prints action icons for the badge.
260     public function print_badge_table_actions($badge, $context) {
261         $actions = "";
263         if (has_capability('moodle/badges:configuredetails', $context) && $badge->has_criteria()) {
264             // Activate/deactivate badge.
265             if ($badge->status == BADGE_STATUS_INACTIVE || $badge->status == BADGE_STATUS_INACTIVE_LOCKED) {
266                 // "Activate" will go to another page and ask for confirmation.
267                 $url = new moodle_url('/badges/action.php');
268                 $url->param('id', $badge->id);
269                 $url->param('activate', true);
270                 $url->param('sesskey', sesskey());
271                 $return = new moodle_url(qualified_me());
272                 $url->param('return', $return->out_as_local_url(false));
273                 $actions .= $this->output->action_icon($url, new pix_icon('t/show', get_string('activate', 'badges'))) . " ";
274             } else {
275                 $url = new moodle_url(qualified_me());
276                 $url->param('lock', $badge->id);
277                 $url->param('sesskey', sesskey());
278                 $actions .= $this->output->action_icon($url, new pix_icon('t/hide', get_string('deactivate', 'badges'))) . " ";
279             }
280         }
282         // Award badge manually.
283         if ($badge->has_manual_award_criteria() &&
284                 has_capability('moodle/badges:awardbadge', $context) &&
285                 $badge->is_active()) {
286             $url = new moodle_url('/badges/award.php', array('id' => $badge->id));
287             $actions .= $this->output->action_icon($url, new pix_icon('t/award', get_string('award', 'badges'))) . " ";
288         }
290         // Edit badge.
291         if (has_capability('moodle/badges:configuredetails', $context)) {
292             $url = new moodle_url('/badges/edit.php', array('id' => $badge->id, 'action' => 'badge'));
293             $actions .= $this->output->action_icon($url, new pix_icon('t/edit', get_string('edit'))) . " ";
294         }
296         // Duplicate badge.
297         if (has_capability('moodle/badges:createbadge', $context)) {
298             $url = new moodle_url('/badges/action.php', array('copy' => '1', 'id' => $badge->id, 'sesskey' => sesskey()));
299             $actions .= $this->output->action_icon($url, new pix_icon('t/copy', get_string('copy'))) . " ";
300         }
302         // Delete badge.
303         if (has_capability('moodle/badges:deletebadge', $context)) {
304             $url = new moodle_url(qualified_me());
305             $url->param('delete', $badge->id);
306             $actions .= $this->output->action_icon($url, new pix_icon('t/delete', get_string('delete'))) . " ";
307         }
309         return $actions;
310     }
312     /**
313      * Render an issued badge.
314      *
315      * @param \core_badges\output\issued_badge $ibadge
316      * @return string
317      */
318     protected function render_issued_badge(\core_badges\output\issued_badge $ibadge) {
319         global $USER, $CFG, $DB, $SITE;
320         $issued = $ibadge->issued;
321         $userinfo = $ibadge->recipient;
322         $badgeclass = $ibadge->badgeclass;
323         $badge = new badge($ibadge->badgeid);
324         $now = time();
325         $expiration = isset($issued['expires']) ? $issued['expires'] : $now + 86400;
326         $badgeimage = is_array($badgeclass['image']) ? $badgeclass['image']['id'] : $badgeclass['image'];
327         $languages = get_string_manager()->get_list_of_languages();
329         $output = '';
330         $output .= html_writer::start_tag('div', array('id' => 'badge'));
331         $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
332         $output .= html_writer::empty_tag('img', array('src' => $badgeimage, 'alt' => $badge->name, 'width' => '100'));
333         if ($expiration < $now) {
334             $output .= $this->output->pix_icon('i/expired',
335             get_string('expireddate', 'badges', userdate($issued['expires'])),
336                 'moodle',
337                 array('class' => 'expireimage'));
338         }
340         if ($USER->id == $userinfo->id && !empty($CFG->enablebadges)) {
341             $output .= $this->output->single_button(
342                         new moodle_url('/badges/badge.php', array('hash' => $ibadge->hash, 'bake' => true)),
343                         get_string('download'),
344                         'POST');
345             if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now) && badges_user_has_backpack($USER->id)) {
347                 if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
348                     $assertion = new moodle_url('/badges/assertion.php', array('b' => $ibadge->hash));
349                     $action = new component_action('click', 'addtobackpack', array('assertion' => $assertion->out(false)));
350                     $attributes = array(
351                             'type'  => 'button',
352                             'class' => 'btn btn-secondary m-1',
353                             'id'    => 'addbutton',
354                             'value' => get_string('addtobackpack', 'badges'));
355                     $tobackpack = html_writer::tag('input', '', $attributes);
356                     $this->output->add_action_handler($action, 'addbutton');
357                     $output .= $tobackpack;
358                 } else {
359                     if (badges_open_badges_backpack_api() == OPEN_BADGES_V2P1) {
360                         $assertion = new moodle_url('/badges/backpack-export.php', array('hash' => $ibadge->hash));
361                     } else {
362                         $assertion = new moodle_url('/badges/backpack-add.php', array('hash' => $ibadge->hash));
363                     }
364                     $attributes = ['class' => 'btn btn-secondary m-1', 'role' => 'button'];
365                     $tobackpack = html_writer::link($assertion, get_string('addtobackpack', 'badges'), $attributes);
366                     $output .= $tobackpack;
367                 }
368             }
369         }
370         $output .= html_writer::end_tag('div');
372         $output .= html_writer::start_tag('div', array('id' => 'badge-details'));
373         // Recipient information.
374         $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3);
375         $dl = array();
376         if ($userinfo->deleted) {
377             $strdata = new stdClass();
378             $strdata->user = fullname($userinfo);
379             $strdata->site = format_string($SITE->fullname, true, array('context' => context_system::instance()));
381             $dl[get_string('name')] = get_string('error:userdeleted', 'badges', $strdata);
382         } else {
383             $dl[get_string('name')] = fullname($userinfo);
384         }
385         $output .= $this->definition_list($dl);
387         $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
388         $dl = array();
389         $dl[get_string('issuername', 'badges')] = $badge->issuername;
390         if (isset($badge->issuercontact) && !empty($badge->issuercontact)) {
391             $dl[get_string('contact', 'badges')] = obfuscate_mailto($badge->issuercontact);
392         }
393         $output .= $this->definition_list($dl);
395         $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
396         $dl = array();
397         $dl[get_string('name')] = $badge->name;
398         if (!empty($badge->version)) {
399             $dl[get_string('version', 'badges')] = $badge->version;
400         }
401         if (!empty($badge->language)) {
402             $dl[get_string('language')] = $languages[$badge->language];
403         }
404         $dl[get_string('description', 'badges')] = $badge->description;
405         if (!empty($badge->imageauthorname)) {
406             $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
407         }
408         if (!empty($badge->imageauthoremail)) {
409             $dl[get_string('imageauthoremail', 'badges')] =
410                     html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
411         }
412         if (!empty($badge->imageauthorurl)) {
413             $dl[get_string('imageauthorurl', 'badges')] =
414                     html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
415         }
416         if (!empty($badge->imagecaption)) {
417             $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
418         }
420         if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) {
421             $coursename = $DB->get_field('course', 'fullname', array('id' => $badge->courseid));
422             $dl[get_string('course')] = $coursename;
423         }
424         $dl[get_string('bcriteria', 'badges')] = self::print_badge_criteria($badge);
425         $output .= $this->definition_list($dl);
427         $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
428         $dl = array();
429         if (!is_numeric($issued['issuedOn'])) {
430             $issued['issuedOn'] = strtotime($issued['issuedOn']);
431         }
432         $dl[get_string('dateawarded', 'badges')] = userdate($issued['issuedOn']);
433         if (isset($issued['expires'])) {
434             if (!is_numeric($issued['expires'])) {
435                 $issued['expires'] = strtotime($issued['expires']);
436             }
437             if ($issued['expires'] < $now) {
438                 $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']) . get_string('warnexpired', 'badges');
440             } else {
441                 $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']);
442             }
443         }
445         // Print evidence.
446         $agg = $badge->get_aggregation_methods();
447         $evidence = $badge->get_criteria_completions($userinfo->id);
448         $eids = array_map(function($o) {
449             return $o->critid;
450         }, $evidence);
451         unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
453         $items = array();
454         foreach ($badge->criteria as $type => $c) {
455             if (in_array($c->id, $eids)) {
456                 if (count($c->params) == 1) {
457                     $items[] = get_string('criteria_descr_single_' . $type , 'badges') . $c->get_details();
458                 } else {
459                     $items[] = get_string('criteria_descr_' . $type , 'badges',
460                             core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) . $c->get_details();
461                 }
462             }
463         }
465         $dl[get_string('evidence', 'badges')] = get_string('completioninfo', 'badges') . html_writer::alist($items, array(), 'ul');
466         $output .= $this->definition_list($dl);
467         $endorsement = $badge->get_endorsement();
468         if (!empty($endorsement)) {
469             $output .= self::print_badge_endorsement($badge);
470         }
472         $relatedbadges = $badge->get_related_badges(true);
473         $items = array();
474         foreach ($relatedbadges as $related) {
475             $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
476             $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
477         }
478         if (!empty($items)) {
479             $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
480             $output .= html_writer::alist($items, array(), 'ul');
481         }
483         $alignments = $badge->get_alignments();
484         if (!empty($alignments)) {
485             $output .= $this->heading(get_string('alignment', 'badges'), 3);
486             $items = array();
487             foreach ($alignments as $alignment) {
488                 $items[] = html_writer::link($alignment->targeturl, $alignment->targetname, array('target' => '_blank'));
489             }
490             $output .= html_writer::alist($items, array(), 'ul');
491         }
492         $output .= html_writer::end_tag('div');
494         return $output;
495     }
497     /**
498      * Render an external badge.
499      *
500      * @param \core_badges\output\external_badge $ibadge
501      * @return string
502      */
503     protected function render_external_badge(\core_badges\output\external_badge $ibadge) {
504         $issued = $ibadge->issued;
505         $assertion = $issued->assertion;
506         $issuer = $assertion->badge->issuer;
507         $userinfo = $ibadge->recipient;
508         $table = new html_table();
509         $today = strtotime(date('Y-m-d'));
511         $output = '';
512         $output .= html_writer::start_tag('div', array('id' => 'badge'));
513         $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
514         if (isset($issued->imageUrl)) {
515             $issued->image = $issued->imageUrl;
516         }
517         $output .= html_writer::empty_tag('img', array('src' => $issued->image, 'width' => '100'));
518         if (isset($assertion->expires)) {
519             $expiration = is_numeric($assertion->expires) ? $assertion->expires : strtotime($assertion->expires);
520             if ($expiration < $today) {
521                 $output .= $this->output->pix_icon('i/expired',
522                         get_string('expireddate', 'badges', userdate($expiration)),
523                         'moodle',
524                         array('class' => 'expireimage'));
525             }
526         }
527         $output .= html_writer::end_tag('div');
529         $output .= html_writer::start_tag('div', array('id' => 'badge-details'));
531         // Recipient information.
532         $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3);
533         $dl = array();
534         // Technically, we should alway have a user at this point, but added an extra check just in case.
535         if ($userinfo) {
536             if (!$ibadge->valid) {
537                 $notify = $this->output->notification(get_string('recipientvalidationproblem', 'badges'), 'notifynotice');
538                 $dl[get_string('name')] = fullname($userinfo) . $notify;
539             } else {
540                 $dl[get_string('name')] = fullname($userinfo);
541             }
542         } else {
543             $notify = $this->output->notification(get_string('recipientidentificationproblem', 'badges'), 'notifynotice');
544             $dl[get_string('name')] = $notify;
545         }
546         $output .= $this->definition_list($dl);
548         $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
549         $dl = array();
550         $dl[get_string('issuername', 'badges')] = s($issuer->name);
551         if (isset($issuer->origin)) {
552             $dl[get_string('issuerurl', 'badges')] = html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin));
553         }
555         if (isset($issuer->contact)) {
556             $dl[get_string('contact', 'badges')] = obfuscate_mailto($issuer->contact);
557         }
558         $output .= $this->definition_list($dl);
560         $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
561         $dl = array();
562         $dl[get_string('name')] = s($assertion->badge->name);
563         $dl[get_string('description', 'badges')] = s($assertion->badge->description);
564         if (isset($assertion->badge->criteria)) {
565             $dl[get_string('bcriteria', 'badges')] = html_writer::tag(
566                 'a',
567                 s($assertion->badge->criteria),
568                 array('href' => $assertion->badge->criteria)
569             );
570         }
571         $output .= $this->definition_list($dl);
573         $dl = array();
574         if (isset($assertion->issued_on)) {
575             $issuedate = is_numeric($assertion->issued_on) ? $assertion->issued_on : strtotime($assertion->issued_on);
576             $dl[get_string('dateawarded', 'badges')] = userdate($issuedate);
577         }
578         if (isset($assertion->expires)) {
579             if ($expiration < $today) {
580                 $dl[get_string('expirydate', 'badges')] = userdate($expiration) . get_string('warnexpired', 'badges');
581             } else {
582                 $dl[get_string('expirydate', 'badges')] = userdate($expiration);
583             }
584         }
585         if (isset($assertion->evidence)) {
586             $dl[get_string('evidence', 'badges')] = html_writer::tag(
587                 'a',
588                 s($assertion->evidence),
589                 array('href' => $assertion->evidence)
590             );
591         }
592         if (!empty($dl)) {
593             $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
594             $output .= $this->definition_list($dl);
595         }
596         $output .= html_writer::end_tag('div');
598         return $output;
599     }
601     /**
602      * Render a collection of user badges.
603      *
604      * @param \core_badges\output\badge_user_collection $badges
605      * @return string
606      */
607     protected function render_badge_user_collection(\core_badges\output\badge_user_collection $badges) {
608         global $CFG, $USER, $SITE;
609         $backpack = $badges->backpack;
610         $mybackpack = new moodle_url('/badges/mybackpack.php');
612         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
613         $htmlpagingbar = $this->render($paging);
615         // Set backpack connection string.
616         $backpackconnect = '';
617         if (!empty($CFG->badges_allowexternalbackpack) && is_null($backpack)) {
618             $backpackconnect = $this->output->box(get_string('localconnectto', 'badges', $mybackpack->out()), 'noticebox');
619         }
620         // Search box.
621         $searchform = $this->output->box($this->helper_search_form($badges->search), 'boxwidthwide boxaligncenter');
623         // Download all button.
624         $actionhtml = $this->output->single_button(
625                     new moodle_url('/badges/mybadges.php', array('downloadall' => true, 'sesskey' => sesskey())),
626                     get_string('downloadall'), 'POST', array('class' => 'activatebadge'));
627         $downloadall = $this->output->box('', 'col-md-3');
628         $downloadall .= $this->output->box($actionhtml, 'col-md-9');
629         $downloadall = $this->output->box($downloadall, 'row ml-5');
631         // Local badges.
632         $localhtml = html_writer::start_tag('div', array('id' => 'issued-badge-table', 'class' => 'generalbox'));
633         $sitename = format_string($SITE->fullname, true, array('context' => context_system::instance()));
634         $heading = get_string('localbadges', 'badges', $sitename);
635         $localhtml .= $this->output->heading_with_help($heading, 'localbadgesh', 'badges');
636         if ($badges->badges) {
637             $countmessage = $this->output->box(get_string('badgesearned', 'badges', $badges->totalcount));
639             $htmllist = $this->print_badges_list($badges->badges, $USER->id);
640             $localhtml .= $backpackconnect . $countmessage . $searchform;
641             $localhtml .= $htmlpagingbar . $htmllist . $htmlpagingbar . $downloadall;
642         } else {
643             $localhtml .= $searchform . $this->output->notification(get_string('nobadges', 'badges'));
644         }
645         $localhtml .= html_writer::end_tag('div');
647         // External badges.
648         $externalhtml = "";
649         if (!empty($CFG->badges_allowexternalbackpack)) {
650             $externalhtml .= html_writer::start_tag('div', array('class' => 'generalbox'));
651             $externalhtml .= $this->output->heading_with_help(get_string('externalbadges', 'badges'), 'externalbadges', 'badges');
652             if (!is_null($backpack)) {
653                 if ($backpack->backpackid != $CFG->badges_site_backpack) {
654                     $externalhtml .= $this->output->notification(get_string('backpackneedsupdate', 'badges'), 'warning');
656                 }
657                 if ($backpack->totalcollections == 0) {
658                     $externalhtml .= get_string('nobackpackcollectionssummary', 'badges', $backpack);
659                 } else {
660                     if ($backpack->totalbadges == 0) {
661                         $externalhtml .= get_string('nobackpackbadgessummary', 'badges', $backpack);
662                     } else {
663                         $externalhtml .= get_string('backpackbadgessummary', 'badges', $backpack);
664                         $externalhtml .= '<br/><br/>' . $this->print_badges_list($backpack->badges, $USER->id, true, true);
665                     }
666                 }
667             } else {
668                 $externalhtml .= get_string('externalconnectto', 'badges', $mybackpack->out());
669             }
671             $externalhtml .= html_writer::end_tag('div');
672             $attr = ['class' => 'btn btn-secondary'];
673             $label = get_string('backpackbadgessettings', 'badges');
674             $backpacksettings = html_writer::link(new moodle_url('/badges/mybackpack.php'), $label, $attr);
675             $actionshtml = $this->output->box('', 'col-md-3');
676             $actionshtml .= $this->output->box($backpacksettings, 'col-md-9');
677             $actionshtml = $this->output->box($actionshtml, 'row ml-5');
678             $externalhtml .= $actionshtml;
679         }
681         return $localhtml . $externalhtml;
682     }
684     /**
685      * Render a collection of badges.
686      *
687      * @param \core_badges\output\badge_collection $badges
688      * @return string
689      */
690     protected function render_badge_collection(\core_badges\output\badge_collection $badges) {
691         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
692         $htmlpagingbar = $this->render($paging);
693         $table = new html_table();
694         $table->attributes['class'] = 'table table-bordered table-striped';
696         $sortbyname = $this->helper_sortable_heading(get_string('name'),
697                 'name', $badges->sort, $badges->dir);
698         $sortbyawarded = $this->helper_sortable_heading(get_string('awardedtoyou', 'badges'),
699                 'dateissued', $badges->sort, $badges->dir);
700         $table->head = array(
701                     get_string('badgeimage', 'badges'),
702                     $sortbyname,
703                     get_string('description', 'badges'),
704                     get_string('bcriteria', 'badges'),
705                     $sortbyawarded
706                 );
707         $table->colclasses = array('badgeimage', 'name', 'description', 'criteria', 'awards');
709         foreach ($badges->badges as $badge) {
710             $badgeimage = print_badge_image($badge, $this->page->context, 'large');
711             $name = $badge->name;
712             $description = $badge->description;
713             $criteria = self::print_badge_criteria($badge);
714             if ($badge->dateissued) {
715                 $icon = new pix_icon('i/valid',
716                             get_string('dateearned', 'badges',
717                                 userdate($badge->dateissued, get_string('strftimedatefullshort', 'core_langconfig'))));
718                 $badgeurl = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
719                 $awarded = $this->output->action_icon($badgeurl, $icon, null, null, true);
720             } else {
721                 $awarded = "";
722             }
723             $row = array($badgeimage, $name, $description, $criteria, $awarded);
724             $table->data[] = $row;
725         }
727         $htmltable = html_writer::table($table);
729         return $htmlpagingbar . $htmltable . $htmlpagingbar;
730     }
732     /**
733      * Render a table of badges.
734      *
735      * @param \core_badges\output\badge_management $badges
736      * @return string
737      */
738     protected function render_badge_management(\core_badges\output\badge_management $badges) {
739         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
741         // New badge button.
742         $htmlnew = '';
743         if (has_capability('moodle/badges:createbadge', $this->page->context)) {
744             $n['type'] = $this->page->url->get_param('type');
745             $n['id'] = $this->page->url->get_param('id');
746             $btn = $this->output->single_button(new moodle_url('newbadge.php', $n), get_string('newbadge', 'badges'));
747             $htmlnew = $this->output->box($btn);
748         }
750         $htmlpagingbar = $this->render($paging);
751         $table = new html_table();
752         $table->attributes['class'] = 'table table-bordered table-striped';
754         $sortbyname = $this->helper_sortable_heading(get_string('name'),
755                 'name', $badges->sort, $badges->dir);
756         $sortbystatus = $this->helper_sortable_heading(get_string('status', 'badges'),
757                 'status', $badges->sort, $badges->dir);
758         $table->head = array(
759                 $sortbyname,
760                 $sortbystatus,
761                 get_string('bcriteria', 'badges'),
762                 get_string('awards', 'badges'),
763                 get_string('actions')
764             );
765         $table->colclasses = array('name', 'status', 'criteria', 'awards', 'actions');
767         foreach ($badges->badges as $b) {
768             $style = !$b->is_active() ? array('class' => 'dimmed') : array();
769             $forlink =  print_badge_image($b, $this->page->context) . ' ' .
770                         html_writer::start_tag('span') . $b->name . html_writer::end_tag('span');
771             $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $b->id)), $forlink, $style);
772             $status = $b->statstring;
773             $criteria = self::print_badge_criteria($b, 'short');
775             if (has_capability('moodle/badges:viewawarded', $this->page->context)) {
776                 $awards = html_writer::link(new moodle_url('/badges/recipients.php', array('id' => $b->id)), $b->awards);
777             } else {
778                 $awards = $b->awards;
779             }
781             $actions = self::print_badge_table_actions($b, $this->page->context);
783             $row = array($name, $status, $criteria, $awards, $actions);
784             $table->data[] = $row;
785         }
786         $htmltable = html_writer::table($table);
788         return $htmlnew . $htmlpagingbar . $htmltable . $htmlpagingbar;
789     }
791     /**
792      * Prints tabs for badge editing.
793      *
794      * @param integer $badgeid The badgeid to edit.
795      * @param context $context The current context.
796      * @param string $current The currently selected tab.
797      * @return string
798      */
799     public function print_badge_tabs($badgeid, $context, $current = 'overview') {
800         global $DB;
802         $badge = new badge($badgeid);
803         $row = array();
805         $row[] = new tabobject('overview',
806                     new moodle_url('/badges/overview.php', array('id' => $badgeid)),
807                     get_string('boverview', 'badges')
808                 );
810         if (has_capability('moodle/badges:configuredetails', $context)) {
811             $row[] = new tabobject('details',
812                         new moodle_url('/badges/edit.php', array('id' => $badgeid, 'action' => 'badge')),
813                         get_string('bdetails', 'badges')
814                     );
815         }
817         if (has_capability('moodle/badges:configurecriteria', $context)) {
818             $row[] = new tabobject('criteria',
819                         new moodle_url('/badges/criteria.php', array('id' => $badgeid)),
820                         get_string('bcriteria', 'badges')
821                     );
822         }
824         if (has_capability('moodle/badges:configuremessages', $context)) {
825             $row[] = new tabobject('message',
826                         new moodle_url('/badges/edit.php', array('id' => $badgeid, 'action' => 'message')),
827                         get_string('bmessage', 'badges')
828                     );
829         }
831         if (has_capability('moodle/badges:viewawarded', $context)) {
832             $awarded = $DB->count_records_sql('SELECT COUNT(b.userid)
833                                                FROM {badge_issued} b INNER JOIN {user} u ON b.userid = u.id
834                                                WHERE b.badgeid = :badgeid AND u.deleted = 0', array('badgeid' => $badgeid));
835             $row[] = new tabobject('awards',
836                         new moodle_url('/badges/recipients.php', array('id' => $badgeid)),
837                         get_string('bawards', 'badges', $awarded)
838                     );
839         }
841         if (has_capability('moodle/badges:configuredetails', $context)) {
842             $row[] = new tabobject('bendorsement',
843                 new moodle_url('/badges/endorsement.php', array('id' => $badgeid)),
844                 get_string('bendorsement', 'badges')
845             );
846         }
848         if (has_capability('moodle/badges:configuredetails', $context)) {
849             $sql = "SELECT COUNT(br.badgeid)
850                       FROM {badge_related} br
851                      WHERE (br.badgeid = :badgeid OR br.relatedbadgeid = :badgeid2)";
852             $related = $DB->count_records_sql($sql, ['badgeid' => $badgeid, 'badgeid2' => $badgeid]);
853             $row[] = new tabobject('brelated',
854                 new moodle_url('/badges/related.php', array('id' => $badgeid)),
855                 get_string('brelated', 'badges', $related)
856             );
857         }
859         if (has_capability('moodle/badges:configuredetails', $context)) {
860             $alignments = $DB->count_records_sql("SELECT COUNT(bc.id)
861                       FROM {badge_alignment} bc WHERE bc.badgeid = :badgeid", array('badgeid' => $badgeid));
862             $row[] = new tabobject('balignment',
863                 new moodle_url('/badges/alignment.php', array('id' => $badgeid)),
864                 get_string('balignment', 'badges', $alignments)
865             );
866         }
868         echo $this->tabtree($row, $current);
869     }
871     /**
872      * Prints badge status box.
873      *
874      * @param badge $badge
875      * @return Either the status box html as a string or null
876      */
877     public function print_badge_status_box(badge $badge) {
878         if (has_capability('moodle/badges:configurecriteria', $badge->get_context())) {
880             if (!$badge->has_criteria()) {
881                 $criteriaurl = new moodle_url('/badges/criteria.php', array('id' => $badge->id));
882                 $status = get_string('nocriteria', 'badges');
883                 if ($this->page->url != $criteriaurl) {
884                     $action = $this->output->single_button(
885                         $criteriaurl,
886                         get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
887                 } else {
888                     $action = '';
889                 }
891                 $message = $status . $action;
892             } else {
893                 $status = get_string('statusmessage_' . $badge->status, 'badges');
894                 if ($badge->is_active()) {
895                     $action = $this->output->single_button(new moodle_url('/badges/action.php',
896                                 array('id' => $badge->id, 'lock' => 1, 'sesskey' => sesskey(),
897                                       'return' => $this->page->url->out_as_local_url(false))),
898                             get_string('deactivate', 'badges'), 'POST', array('class' => 'activatebadge'));
899                 } else {
900                     $action = $this->output->single_button(new moodle_url('/badges/action.php',
901                                 array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(),
902                                       'return' => $this->page->url->out_as_local_url(false))),
903                             get_string('activate', 'badges'), 'POST', array('class' => 'activatebadge'));
904                 }
906                 $message = $status . $this->output->help_icon('status', 'badges') . $action;
908             }
910             $style = $badge->is_active() ? 'generalbox statusbox active' : 'generalbox statusbox inactive';
911             return $this->output->box($message, $style);
912         }
914         return null;
915     }
917     /**
918      * Returns information about badge criteria in a list form.
919      *
920      * @param badge $badge Badge objects
921      * @param string $short Indicates whether to print full info about this badge
922      * @return string $output HTML string to output
923      */
924     public function print_badge_criteria(badge $badge, $short = '') {
925         $agg = $badge->get_aggregation_methods();
926         if (empty($badge->criteria)) {
927             return get_string('nocriteria', 'badges');
928         }
930         $overalldescr = '';
931         $overall = $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL];
932         if (!$short && !empty($overall->description)) {
933             $overalldescr = $this->output->box(
934                 format_text($overall->description, $overall->descriptionformat, array('context' => $badge->get_context())),
935                 'criteria-description'
936                 );
937         }
939         // Get the condition string.
940         if (count($badge->criteria) == 2) {
941             $condition = '';
942             if (!$short) {
943                 $condition = get_string('criteria_descr', 'badges');
944             }
945         } else {
946             $condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
947                                       core_text::strtoupper($agg[$badge->get_aggregation_method()]));
948         }
950         unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
952         $items = array();
953         // If only one criterion left, make sure its description goe to the top.
954         if (count($badge->criteria) == 1) {
955             $c = reset($badge->criteria);
956             if (!$short && !empty($c->description)) {
957                 $overalldescr = $this->output->box(
958                     format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
959                     'criteria-description'
960                     );
961             }
962             if (count($c->params) == 1) {
963                 $items[] = get_string('criteria_descr_single_' . $short . $c->criteriatype , 'badges') .
964                            $c->get_details($short);
965             } else {
966                 $items[] = get_string('criteria_descr_' . $short . $c->criteriatype, 'badges',
967                         core_text::strtoupper($agg[$badge->get_aggregation_method($c->criteriatype)])) .
968                         $c->get_details($short);
969             }
970         } else {
971             foreach ($badge->criteria as $type => $c) {
972                 $criteriadescr = '';
973                 if (!$short && !empty($c->description)) {
974                     $criteriadescr = $this->output->box(
975                         format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
976                         'criteria-description'
977                         );
978                 }
979                 if (count($c->params) == 1) {
980                     $items[] = get_string('criteria_descr_single_' . $short . $type , 'badges') .
981                                $c->get_details($short) . $criteriadescr;
982                 } else {
983                     $items[] = get_string('criteria_descr_' . $short . $type , 'badges',
984                             core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) .
985                             $c->get_details($short) .
986                             $criteriadescr;
987                 }
988             }
989         }
991         return $overalldescr . $condition . html_writer::alist($items, array(), 'ul');;
992     }
994     /**
995      * Prints criteria actions for badge editing.
996      *
997      * @param badge $badge
998      * @return string
999      */
1000     public function print_criteria_actions(badge $badge) {
1001         $output = '';
1002         if (!$badge->is_active() && !$badge->is_locked()) {
1003             $accepted = $badge->get_accepted_criteria();
1004             $potential = array_diff($accepted, array_keys($badge->criteria));
1006             if (!empty($potential)) {
1007                 foreach ($potential as $p) {
1008                     if ($p != 0) {
1009                         $select[$p] = get_string('criteria_' . $p, 'badges');
1010                     }
1011                 }
1012                 $output .= $this->output->single_select(
1013                     new moodle_url('/badges/criteria_settings.php', array('badgeid' => $badge->id, 'add' => true)),
1014                     'type',
1015                     $select,
1016                     '',
1017                     array('' => 'choosedots'),
1018                     null,
1019                     array('label' => get_string('addbadgecriteria', 'badges'))
1020                 );
1021             } else {
1022                 $output .= $this->output->box(get_string('nothingtoadd', 'badges'), 'clearfix');
1023             }
1024         }
1026         return $output;
1027     }
1029     /**
1030      * Renders a table with users who have earned the badge.
1031      * Based on stamps collection plugin.
1032      *
1033      * @param \core_badges\output\badge_recipients $recipients
1034      * @return string
1035      */
1036     protected function render_badge_recipients(\core_badges\output\badge_recipients $recipients) {
1037         $paging = new paging_bar($recipients->totalcount, $recipients->page, $recipients->perpage, $this->page->url, 'page');
1038         $htmlpagingbar = $this->render($paging);
1039         $table = new html_table();
1040         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1042         $sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'),
1043                 'firstname', $recipients->sort, $recipients->dir);
1044         $sortbylastname = $this->helper_sortable_heading(get_string('lastname'),
1045                 'lastname', $recipients->sort, $recipients->dir);
1046         if ($this->helper_fullname_format() == 'lf') {
1047             $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
1048         } else {
1049             $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
1050         }
1052         $sortbydate = $this->helper_sortable_heading(get_string('dateawarded', 'badges'),
1053                 'dateissued', $recipients->sort, $recipients->dir);
1055         $table->head = array($sortbyname, $sortbydate, '');
1057         foreach ($recipients->userids as $holder) {
1058             $fullname = fullname($holder);
1059             $fullname = html_writer::link(
1060                             new moodle_url('/user/profile.php', array('id' => $holder->userid)),
1061                             $fullname
1062                         );
1063             $awarded  = userdate($holder->dateissued);
1064             $badgeurl = html_writer::link(
1065                             new moodle_url('/badges/badge.php', array('hash' => $holder->uniquehash)),
1066                             get_string('viewbadge', 'badges')
1067                         );
1069             $row = array($fullname, $awarded, $badgeurl);
1070             $table->data[] = $row;
1071         }
1073         $htmltable = html_writer::table($table);
1075         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1076     }
1078     ////////////////////////////////////////////////////////////////////////////
1079     // Helper methods
1080     // Reused from stamps collection plugin
1081     ////////////////////////////////////////////////////////////////////////////
1083     /**
1084      * Renders a text with icons to sort by the given column
1085      *
1086      * This is intended for table headings.
1087      *
1088      * @param string $text    The heading text
1089      * @param string $sortid  The column id used for sorting
1090      * @param string $sortby  Currently sorted by (column id)
1091      * @param string $sorthow Currently sorted how (ASC|DESC)
1092      *
1093      * @return string
1094      */
1095     protected function helper_sortable_heading($text, $sortid = null, $sortby = null, $sorthow = null) {
1096         $out = html_writer::tag('span', $text, array('class' => 'text'));
1098         if (!is_null($sortid)) {
1099             if ($sortby !== $sortid || $sorthow !== 'ASC') {
1100                 $url = new moodle_url($this->page->url);
1101                 $url->params(array('sort' => $sortid, 'dir' => 'ASC'));
1102                 $out .= $this->output->action_icon($url,
1103                         new pix_icon('t/sort_asc', get_string('sortbyx', 'core', s($text)), null, array('class' => 'iconsort')));
1104             }
1105             if ($sortby !== $sortid || $sorthow !== 'DESC') {
1106                 $url = new moodle_url($this->page->url);
1107                 $url->params(array('sort' => $sortid, 'dir' => 'DESC'));
1108                 $out .= $this->output->action_icon($url,
1109                         new pix_icon('t/sort_desc', get_string('sortbyxreverse', 'core', s($text)), null, array('class' => 'iconsort')));
1110             }
1111         }
1112         return $out;
1113     }
1114     /**
1115      * Tries to guess the fullname format set at the site
1116      *
1117      * @return string fl|lf
1118      */
1119     protected function helper_fullname_format() {
1120         $fake = new stdClass();
1121         $fake->lastname = 'LLLL';
1122         $fake->firstname = 'FFFF';
1123         $fullname = get_string('fullnamedisplay', '', $fake);
1124         if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
1125             return 'lf';
1126         } else {
1127             return 'fl';
1128         }
1129     }
1130     /**
1131      * Renders a search form
1132      *
1133      * @param string $search Search string
1134      * @return string HTML
1135      */
1136     protected function helper_search_form($search) {
1137         global $CFG;
1138         require_once($CFG->libdir . '/formslib.php');
1140         $mform = new MoodleQuickForm('searchform', 'POST', $this->page->url);
1142         $mform->addElement('hidden', 'sesskey', sesskey());
1144         $el[] = $mform->createElement('text', 'search', get_string('search'), array('size' => 20));
1145         $mform->setDefault('search', $search);
1146         $el[] = $mform->createElement('submit', 'submitsearch', get_string('search'));
1147         $el[] = $mform->createElement('submit', 'clearsearch', get_string('clear'));
1148         $mform->addGroup($el, 'searchgroup', get_string('searchname', 'badges'), ' ', false);
1150         ob_start();
1151         $mform->display();
1152         $out = ob_get_clean();
1154         return $out;
1155     }
1157     /**
1158      * Renders a definition list
1159      *
1160      * @param array $items the list of items to define
1161      * @param array
1162      */
1163     protected function definition_list(array $items, array $attributes = array()) {
1164         $output = html_writer::start_tag('dl', $attributes);
1165         foreach ($items as $label => $value) {
1166             $output .= html_writer::tag('dt', $label);
1167             $output .= html_writer::tag('dd', $value);
1168         }
1169         $output .= html_writer::end_tag('dl');
1170         return $output;
1171     }
1173     /**
1174      * Outputs list en badges.
1175      *
1176      * @param badge $badge Badge object.
1177      * @return string $output content endorsement to output.
1178      */
1179     protected function print_badge_endorsement(badge $badge) {
1180         $output = '';
1181         $endorsement = $badge->get_endorsement();
1182         $dl = array();
1183         $output .= $this->heading(get_string('endorsement', 'badges'), 3);
1184         if (!empty($endorsement)) {
1185             $dl[get_string('issuername', 'badges')] = $endorsement->issuername;
1186             $dl[get_string('issueremail', 'badges')] =
1187                 html_writer::tag('a', $endorsement->issueremail, array('href' => 'mailto:' . $endorsement->issueremail));
1188             $dl[get_string('issuerurl', 'badges')] = html_writer::link($endorsement->issuerurl, $endorsement->issuerurl,
1189                 array('target' => '_blank'));
1190             $dl[get_string('dateawarded', 'badges')] = userdate($endorsement->dateissued);
1191             $dl[get_string('claimid', 'badges')] = html_writer::link($endorsement->claimid, $endorsement->claimid,
1192             array('target' => '_blank'));
1193             $dl[get_string('claimcomment', 'badges')] = $endorsement->claimcomment;
1194             $output .= $this->definition_list($dl);
1195         } else {
1196             $output .= get_string('noendorsement', 'badges');
1197         }
1198         return $output;
1199     }
1201     /**
1202      * Print list badges related.
1203      *
1204      * @param badge $badge Badge objects.
1205      * @return string $output List related badges to output.
1206      */
1207     protected function print_badge_related(badge $badge) {
1208         $output = '';
1209         $relatedbadges = $badge->get_related_badges();
1210         $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
1211         if (!empty($relatedbadges)) {
1212             $items = array();
1213             foreach ($relatedbadges as $related) {
1214                 $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
1215                 $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
1216             }
1217             $output .= html_writer::alist($items, array(), 'ul');
1218         } else {
1219             $output .= get_string('norelated', 'badges');
1220         }
1221         return $output;
1222     }
1224     /**
1225      * Print list badge alignments.
1226      *
1227      * @param badge $badge Badge objects.
1228      * @return string $output List alignments to output.
1229      */
1230     protected function print_badge_alignments(badge $badge) {
1231         $output = '';
1232         $output .= $this->heading(get_string('alignment', 'badges'), 3);
1233         $alignments = $badge->get_alignments();
1234         if (!empty($alignments)) {
1235             $items = array();
1236             foreach ($alignments as $alignment) {
1237                 $urlaligment = new moodle_url('alignment.php',
1238                     array('id' => $badge->id, 'alignmentid' => $alignment->id)
1239                 );
1240                 $items[] = html_writer::link($urlaligment, $alignment->targetname, array('target' => '_blank'));
1241             }
1242             $output .= html_writer::alist($items, array(), 'ul');
1243         } else {
1244             $output .= get_string('noalignment', 'badges');
1245         }
1246         return $output;
1247     }
1249     /**
1250      * Renders a table for related badges.
1251      *
1252      * @param \core_badges\output\badge_related $related list related badges.
1253      * @return string list related badges to output.
1254      */
1255     protected function render_badge_related(\core_badges\output\badge_related $related) {
1256         $currentbadge = new badge($related->currentbadgeid);
1257         $languages = get_string_manager()->get_list_of_languages();
1258         $paging = new paging_bar($related->totalcount, $related->page, $related->perpage, $this->page->url, 'page');
1259         $htmlpagingbar = $this->render($paging);
1260         $table = new html_table();
1261         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1262         $table->head = array(
1263             get_string('name'),
1264             get_string('version', 'badges'),
1265             get_string('language', 'badges'),
1266             get_string('type', 'badges')
1267         );
1268         if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1269             array_push($table->head, '');
1270         }
1272         foreach ($related->badges as $badge) {
1273             $badgeobject = new badge($badge->id);
1274             $style = array('title' => $badgeobject->name);
1275             if (!$badgeobject->is_active()) {
1276                 $style['class'] = 'dimmed';
1277             }
1278             $context = ($badgeobject->type == BADGE_TYPE_SITE) ?
1279                 context_system::instance() : context_course::instance($badgeobject->courseid);
1280             $forlink = print_badge_image($badgeobject, $context) . ' ' .
1281                 html_writer::start_tag('span') . $badgeobject->name . html_writer::end_tag('span');
1282             $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $badgeobject->id)), $forlink, $style);
1284             $row = array(
1285                 $name,
1286                 $badge->version,
1287                 $badge->language ? $languages[$badge->language] : '',
1288                 $badge->type == BADGE_TYPE_COURSE ? get_string('badgesview', 'badges') : get_string('sitebadges', 'badges')
1289             );
1290             if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1291                 $action = $this->output->action_icon(
1292                     new moodle_url('related_action.php',
1293                         array(
1294                             'badgeid' => $related->currentbadgeid,
1295                             'relatedid' => $badge->id,
1296                             'action' => 'remove'
1297                         )
1298                     ), new pix_icon('t/delete', get_string('delete')));
1299                 $actions = html_writer::tag('div', $action, array('class' => 'badge-actions'));
1300                 array_push($row, $actions);
1301             }
1302             $table->data[] = $row;
1303         }
1304         $htmltable = html_writer::table($table);
1306         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1307     }
1309     /**
1310      * Renders a table with alignment.
1311      *
1312      * @param core_badges\output\badge_alignments $alignments List alignments.
1313      * @return string List alignment to output.
1314      */
1315     protected function render_badge_alignments(\core_badges\output\badge_alignments $alignments) {
1316         $currentbadge = new badge($alignments->currentbadgeid);
1317         $paging = new paging_bar($alignments->totalcount, $alignments->page, $alignments->perpage, $this->page->url, 'page');
1318         $htmlpagingbar = $this->render($paging);
1319         $table = new html_table();
1320         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1321         $table->head = array('Name', 'URL', '');
1323         foreach ($alignments->alignments as $item) {
1324             $urlaligment = new moodle_url('alignment.php',
1325                 array(
1326                     'id' => $currentbadge->id,
1327                     'alignmentid' => $item->id,
1328                 )
1329             );
1330             $row = array(
1331                 html_writer::link($urlaligment, $item->targetname),
1332                 html_writer::link($item->targeturl, $item->targeturl, array('target' => '_blank'))
1333             );
1334             if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1335                 $delete = $this->output->action_icon(
1336                     new moodle_url('alignment_action.php',
1337                         array(
1338                             'id' => $currentbadge->id,
1339                             'alignmentid' => $item->id,
1340                             'action' => 'remove'
1341                         )
1342                     ), new pix_icon('t/delete', get_string('delete')));
1343                 $edit = $this->output->action_icon(
1344                     new moodle_url('alignment.php',
1345                         array(
1346                             'id' => $currentbadge->id,
1347                             'alignmentid' => $item->id,
1348                             'action' => 'edit'
1349                         )
1350                     ), new pix_icon('t/edit', get_string('edit')));
1351                 $actions = html_writer::tag('div', $edit . $delete, array('class' => 'badge-actions'));
1352                 array_push($row, $actions);
1353             }
1354             $table->data[] = $row;
1355         }
1356         $htmltable = html_writer::table($table);
1358         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1359     }
1361     /**
1362      * Defer to template.
1363      *
1364      * @param \core_badges\output\external_backpacks_page $page
1365      * @return bool|string
1366      */
1367     public function render_external_backpacks_page(\core_badges\output\external_backpacks_page $page) {
1368         $data = $page->export_for_template($this);
1369         return parent::render_from_template('core_badges/external_backpacks_page', $data);
1370     }
1372     /**
1373      * Get the result of a backpack validation with its settings. It returns:
1374      * - A informative message if the backpack version is different from OBv2.
1375      * - A warning with the error if it's not possible to connect to this backpack.
1376      * - A successful message if the connection has worked.
1377      *
1378      * @param  int    $backpackid The backpack identifier.
1379      * @return string A message with the validation result.
1380      */
1381     public function render_test_backpack_result(int $backpackid): string {
1382         // Get the backpack.
1383         $backpack = badges_get_site_backpack($backpackid);
1385         // Add the header to the result.
1386         $result = $this->heading(get_string('testbackpack', 'badges', $backpack->backpackweburl));
1388         if ($backpack->apiversion != OPEN_BADGES_V2) {
1389             // Only OBv2 supports this validation.
1390             $result .= get_string('backpackconnectionnottested', 'badges');
1391         } else {
1392             $message = badges_verify_backpack($backpackid);
1393             if (empty($message)) {
1394                 $result .= get_string('backpackconnectionok', 'badges');
1395             } else {
1396                 $result .= $message;
1397             }
1398         }
1400         return $result;
1401     }