diff --git a/badges/classes/output/issued_badge.php b/badges/classes/output/issued_badge.php
index 2b9e891efe183..e6a7bacb63d13 100644
--- a/badges/classes/output/issued_badge.php
+++ b/badges/classes/output/issued_badge.php
@@ -30,7 +30,12 @@
require_once($CFG->libdir . '/badgeslib.php');
+use context_system;
+use stdClass;
use renderable;
+use core_badges\badge;
+use moodle_url;
+use renderer_base;
/**
* An issued badges for badge.php page
@@ -68,6 +73,9 @@ public function __construct($hash) {
$this->hash = $hash;
$assertion = new \core_badges_assertion($hash, badges_open_badges_backpack_api());
$this->issued = $assertion->get_badge_assertion();
+ if (!is_numeric($this->issued['issuedOn'])) {
+ $this->issued['issuedOn'] = strtotime($this->issued['issuedOn']);
+ }
$this->badgeclass = $assertion->get_badge_class();
$rec = $DB->get_record_sql('SELECT userid, visible, badgeid
@@ -85,5 +93,154 @@ public function __construct($hash) {
$this->badgeid = $rec->badgeid;
}
}
-}
+ /**
+ * Export this data so it can be used as the context for a mustache template.
+ *
+ * @param renderer_base $output Renderer base.
+ * @return stdClass
+ */
+ public function export_for_template(renderer_base $output): stdClass {
+ global $CFG, $DB, $SITE, $USER;
+
+ $now = time();
+ if (isset($this->issued['expires'])) {
+ if (!is_numeric($this->issued['expires'])) {
+ $this->issued['expires'] = strtotime($this->issued['expires']);
+ }
+ $expiration = $this->issued['expires'];
+ } else {
+ $expiration = $now + 86400;
+ }
+
+ $context = null;
+ $data = new stdClass();
+ $badge = new badge($this->badgeid);
+ if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) {
+ $coursename = $DB->get_field('course', 'fullname', ['id' => $badge->courseid]);
+ $data->coursefullname = $coursename;
+ $context = \context_course::instance($badge->courseid);
+ } else {
+ $data->sitefullname = $SITE->fullname;
+ $context = \context_system::instance();
+ }
+
+ // Field: Image.
+ $data->badgeimage = is_array($this->badgeclass['image']) ? $this->badgeclass['image']['id'] : $this->badgeclass['image'];
+
+ // Field: Expiration date.
+ if (isset($this->issued['expires'])) {
+ if ($expiration < $now) {
+ $data->expireddate = $this->issued['expires'];
+ $data->expireddateformatted = userdate($this->issued['expires'], get_string('strftimedatetime', 'langconfig'));
+ } else {
+ $data->expiredate = $this->issued['expires'];
+ }
+ }
+
+ // Fields: Name, description, issuedOn.
+ $data->badgename = $badge->name;
+ $data->badgedescription = $badge->description;
+ $data->badgeissuedon = $this->issued['issuedOn'];
+
+ // Field: Recipient (the badge was awarded to this person).
+ if ($this->recipient->deleted) {
+ $strdata = new stdClass();
+ $strdata->user = fullname($this->recipient);
+ $strdata->site = format_string($SITE->fullname, true, ['context' => context_system::instance()]);
+ $data->recipientname = get_string('error:userdeleted', 'badges', $strdata);
+ } else {
+ $data->recipientname = fullname($this->recipient);
+ }
+
+ // Field: Criteria.
+ // This method will return the HTML with the badge criteria.
+ $data->criteria = $output->print_badge_criteria($badge);
+
+ // Field: Issuer.
+ $data->issuedby = $badge->issuername;
+ if (isset($badge->issuercontact) && !empty($badge->issuercontact)) {
+ $data->issuedbyemailobfuscated = obfuscate_mailto($badge->issuercontact, $badge->issuername);
+ }
+
+ // Fields: Other details, such as language or version.
+ $data->hasotherfields = false;
+ if (!empty($badge->language)) {
+ $data->hasotherfields = true;
+ $languages = get_string_manager()->get_list_of_languages();
+ $data->language = $languages[$badge->language];
+ }
+ if (!empty($badge->version)) {
+ $data->hasotherfields = true;
+ $data->version = $badge->version;
+ }
+ if (!empty($badge->imageauthorname)) {
+ $data->hasotherfields = true;
+ $data->imageauthorname = $badge->imageauthorname;
+ }
+ if (!empty($badge->imageauthoremail)) {
+ $data->hasotherfields = true;
+ $data->imageauthoremail = obfuscate_mailto($badge->imageauthoremail, $badge->imageauthoremail);
+ }
+ if (!empty($badge->imageauthorurl)) {
+ $data->hasotherfields = true;
+ $data->imageauthorurl = $badge->imageauthorurl;
+ }
+ if (!empty($badge->imagecaption)) {
+ $data->hasotherfields = true;
+ $data->imagecaption = $badge->imagecaption;
+ }
+
+ // Field: Endorsement.
+ $endorsement = $badge->get_endorsement();
+ if (!empty($endorsement)) {
+ $data->hasotherfields = true;
+ $endorsement = $badge->get_endorsement();
+ $endorsement->issueremail = obfuscate_mailto($endorsement->issueremail, $endorsement->issueremail);
+ $data->endorsement = (array) $endorsement;
+ }
+
+ // Field: Related badges.
+ $relatedbadges = $badge->get_related_badges(true);
+ if (!empty($relatedbadges)) {
+ $data->hasotherfields = true;
+ $data->hasrelatedbadges = true;
+ $data->relatedbadges = [];
+ foreach ($relatedbadges as $related) {
+ if (isloggedin() && !is_guest($context)) {
+ $related->url = (new moodle_url('/badges/overview.php', ['id' => $related->id]))->out(false);
+ }
+ $data->relatedbadges[] = (array)$related;
+ }
+ }
+
+ // Field: Alignments.
+ $alignments = $badge->get_alignments();
+ if (!empty($alignments)) {
+ $data->hasotherfields = true;
+ $data->hasalignments = true;
+ $data->alignments = [];
+ foreach ($alignments as $alignment) {
+ $data->alignments[] = (array)$alignment;
+ }
+ }
+
+ // Buttons to display.
+ if ($USER->id == $this->recipient->id && !empty($CFG->enablebadges)) {
+ $data->downloadurl = (new moodle_url('/badges/badge.php', ['hash' => $this->hash, 'bake' => true]))->out(false);
+
+ if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now)
+ && $userbackpack = badges_get_user_backpack($USER->id)) {
+
+ if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2P1) {
+ $addtobackpackurl = new moodle_url('/badges/backpack-export.php', ['hash' => $this->hash]);
+ } else {
+ $addtobackpackurl = new moodle_url('/badges/backpack-add.php', ['hash' => $this->hash]);
+ }
+ $data->addtobackpackurl = $addtobackpackurl->out(false);
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/badges/renderer.php b/badges/renderer.php
index ba16434237b40..81b733024d466 100644
--- a/badges/renderer.php
+++ b/badges/renderer.php
@@ -313,176 +313,8 @@ public function print_badge_table_actions($badge, $context) {
* @return string
*/
protected function render_issued_badge(\core_badges\output\issued_badge $ibadge) {
- global $USER, $CFG, $DB, $SITE;
- $issued = $ibadge->issued;
- $userinfo = $ibadge->recipient;
- $badgeclass = $ibadge->badgeclass;
- $badge = new badge($ibadge->badgeid);
- $now = time();
- if (isset($issued['expires'])) {
- if (!is_numeric($issued['expires'])) {
- $issued['expires'] = strtotime($issued['expires']);
- }
- $expiration = $issued['expires'];
- } else {
- $expiration = $now + 86400;
- }
-
- $badgeimage = is_array($badgeclass['image']) ? $badgeclass['image']['id'] : $badgeclass['image'];
- $languages = get_string_manager()->get_list_of_languages();
-
- $output = '';
- $output .= html_writer::start_tag('div', array('id' => 'badge'));
- $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
- $output .= html_writer::empty_tag('img', array('src' => $badgeimage, 'alt' => $badge->name, 'width' => '100'));
- if ($expiration < $now) {
- $output .= $this->output->pix_icon('i/expired',
- get_string('expireddate', 'badges', userdate($issued['expires'])),
- 'moodle',
- array('class' => 'expireimage'));
- }
-
- if ($USER->id == $userinfo->id && !empty($CFG->enablebadges)) {
- $output .= $this->output->single_button(
- new moodle_url('/badges/badge.php', array('hash' => $ibadge->hash, 'bake' => true)),
- get_string('download'),
- 'POST');
- if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now)
- && $userbackpack = badges_get_user_backpack($USER->id)) {
-
- if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2P1) {
- $assertion = new moodle_url('/badges/backpack-export.php', array('hash' => $ibadge->hash));
- } else {
- $assertion = new moodle_url('/badges/backpack-add.php', array('hash' => $ibadge->hash));
- }
-
- $attributes = ['class' => 'btn btn-secondary m-1', 'role' => 'button'];
- $tobackpack = html_writer::link($assertion, get_string('addtobackpack', 'badges'), $attributes);
- $output .= $tobackpack;
- }
- }
- $output .= html_writer::end_tag('div');
-
- $output .= html_writer::start_tag('div', array('id' => 'badge-details'));
- // Recipient information.
- $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3);
- $dl = array();
- if ($userinfo->deleted) {
- $strdata = new stdClass();
- $strdata->user = fullname($userinfo);
- $strdata->site = format_string($SITE->fullname, true, array('context' => context_system::instance()));
-
- $dl[get_string('name')] = get_string('error:userdeleted', 'badges', $strdata);
- } else {
- $dl[get_string('name')] = fullname($userinfo);
- }
- $output .= $this->definition_list($dl);
-
- $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
- $dl = array();
- $dl[get_string('issuername', 'badges')] = $badge->issuername;
- if (isset($badge->issuercontact) && !empty($badge->issuercontact)) {
- $dl[get_string('contact', 'badges')] = obfuscate_mailto($badge->issuercontact);
- }
- $output .= $this->definition_list($dl);
-
- $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
- $dl = array();
- $dl[get_string('name')] = $badge->name;
- if (!empty($badge->version)) {
- $dl[get_string('version', 'badges')] = $badge->version;
- }
- if (!empty($badge->language)) {
- $dl[get_string('language')] = $languages[$badge->language];
- }
- $dl[get_string('description', 'badges')] = $badge->description;
- if (!empty($badge->imageauthorname)) {
- $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
- }
- if (!empty($badge->imageauthoremail)) {
- $dl[get_string('imageauthoremail', 'badges')] =
- html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
- }
- if (!empty($badge->imageauthorurl)) {
- $dl[get_string('imageauthorurl', 'badges')] =
- html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
- }
- if (!empty($badge->imagecaption)) {
- $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
- }
-
- if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) {
- $coursename = $DB->get_field('course', 'fullname', array('id' => $badge->courseid));
- $dl[get_string('course')] = $coursename;
- }
- $dl[get_string('bcriteria', 'badges')] = self::print_badge_criteria($badge);
- $output .= $this->definition_list($dl);
-
- $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
- $dl = array();
- if (!is_numeric($issued['issuedOn'])) {
- $issued['issuedOn'] = strtotime($issued['issuedOn']);
- }
- $dl[get_string('dateawarded', 'badges')] = userdate($issued['issuedOn']);
- if (isset($issued['expires'])) {
- if ($issued['expires'] < $now) {
- $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']) . get_string('warnexpired', 'badges');
-
- } else {
- $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']);
- }
- }
-
- // Print evidence.
- $agg = $badge->get_aggregation_methods();
- $evidence = $badge->get_criteria_completions($userinfo->id);
- $eids = array_map(function($o) {
- return $o->critid;
- }, $evidence);
- unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
-
- $items = array();
- foreach ($badge->criteria as $type => $c) {
- if (in_array($c->id, $eids)) {
- if (count($c->params) == 1) {
- $items[] = get_string('criteria_descr_single_' . $type , 'badges') . $c->get_details();
- } else {
- $items[] = get_string('criteria_descr_' . $type , 'badges',
- core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) . $c->get_details();
- }
- }
- }
-
- $dl[get_string('evidence', 'badges')] = get_string('completioninfo', 'badges') . html_writer::alist($items, array(), 'ul');
- $output .= $this->definition_list($dl);
- $endorsement = $badge->get_endorsement();
- if (!empty($endorsement)) {
- $output .= self::print_badge_endorsement($badge);
- }
-
- $relatedbadges = $badge->get_related_badges(true);
- $items = array();
- foreach ($relatedbadges as $related) {
- $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
- $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
- }
- if (!empty($items)) {
- $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
- $output .= html_writer::alist($items, array(), 'ul');
- }
-
- $alignments = $badge->get_alignments();
- if (!empty($alignments)) {
- $output .= $this->heading(get_string('alignment', 'badges'), 3);
- $items = array();
- foreach ($alignments as $alignment) {
- $items[] = html_writer::link($alignment->targeturl, $alignment->targetname, array('target' => '_blank'));
- }
- $output .= html_writer::alist($items, array(), 'ul');
- }
- $output .= html_writer::end_tag('div');
-
- return $output;
+ $data = $ibadge->export_for_template($this);
+ return parent::render_from_template('core_badges/issued_badge', $data);
}
/**
@@ -924,12 +756,8 @@ public function print_badge_criteria(badge $badge, $short = '') {
}
// Get the condition string.
- if (count($badge->criteria) == 2) {
- $condition = '';
- if (!$short) {
- $condition = get_string('criteria_descr', 'badges');
- }
- } else {
+ $condition = '';
+ if (count($badge->criteria) != 2) {
$condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
core_text::strtoupper($agg[$badge->get_aggregation_method()]));
}
diff --git a/badges/templates/issued_badge.mustache b/badges/templates/issued_badge.mustache
new file mode 100644
index 0000000000000..c9deadf455ef9
--- /dev/null
+++ b/badges/templates/issued_badge.mustache
@@ -0,0 +1,364 @@
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see
{{{badgedescription}}}
+ +{$a->user} has completed all badge requirements and has been awarded the badge. View issued badge at {$a->link}
'; @@ -227,7 +230,7 @@ $string['criteria_descr_single_7'] = 'The following badge has to be earned:'; $string['criteria_descr_single_8'] = 'Membership in the following cohort is required:'; $string['criteria_descr_single_9'] = 'The following competencies have to be completed:'; -$string['criteria_descr_0'] = 'Users are awarded this badge when they complete {$a} of the listed requirements.'; +$string['criteria_descr_0'] = 'Complete {$a} of the listed requirements.'; $string['criteria_descr_1'] = '{$a} of the following activities are completed:'; $string['criteria_descr_2'] = 'This badge has to be awarded by the users with {$a} of the following roles:'; $string['criteria_descr_4'] = 'Users must complete the course'; @@ -342,6 +345,8 @@ $string['expired'] = 'Expired'; $string['expiredate'] = 'This badge expires on {$a}.'; $string['expireddate'] = 'This badge expired on {$a}.'; +$string['expiredin'] = 'Expired {$a}'; +$string['expiresin'] = 'Expires {$a}'; $string['expireperiod'] = 'This badge expires {$a} day(s) after being issued.'; $string['expireperiodh'] = 'This badge expires {$a} hour(s) after being issued.'; $string['expireperiodm'] = 'This badge expires {$a} minute(s) after being issued.'; @@ -363,8 +368,10 @@ $string['imageauthorurl'] = 'Image author\'s URL'; $string['imageauthorurl_help'] = 'If specified, a link to the badge image author\'s website is displayed on the badge page. The URL should have a prefix http:// or https://.'; $string['invalidurl'] = 'Invalid URL'; -$string['issuedbadge'] = 'Issued badge information'; $string['issuancedetails'] = 'Badge expiry'; +$string['issuedbadge'] = 'Issued badge information'; +$string['issuedby'] = 'Issued by {$a}'; +$string['issuedon'] = 'Issued {$a}'; $string['issuerdetails'] = 'Issuer details'; $string['issueremail'] = 'Email'; $string['issueremail_help'] = 'A contact email address of the organisation issuing the endorsement.'; @@ -398,6 +405,7 @@ $string['method'] = 'This criterion is complete when...'; $string['mingrade'] = 'Minimum grade required'; $string['month'] = 'Month(s)'; +$string['moredetails'] = 'More details'; $string['mybadges'] = 'My badges'; $string['mybackpack'] = 'My backpack settings'; $string['never'] = 'Never'; @@ -518,6 +526,7 @@ $string['sitebadges_help'] = 'Site badges can only be awarded to users for site-related activities. These include completing a set of courses or parts of user profiles. Site badges can also be issued manually by one user to another. Badges for course-related activities must be created at the course level. Course badges can be found under Course Administration > Badges.'; +$string['sitebadgetitle'] = '{$a} site badge'; $string['statusmessage_0'] = 'This badge is currently not available to users. Enable access if you want users to earn this badge. '; $string['statusmessage_1'] = 'This badge is currently available to users. Disable access to make any changes. '; $string['statusmessage_2'] = 'This badge is currently not available to users, and its criteria are locked. Enable access if you want users to earn this badge. '; diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index e53b43cbfd9b0..f5c33cb2c2854 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -1948,6 +1948,14 @@ ul.badges { } } +#badge-criteria li li { + list-style-type: none; +} + +#badge-image-col { + flex: 0 0 400px; +} + .badge-profile { vertical-align: top; } diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 107bb9846ce01..3c9a90d90bf86 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -11257,6 +11257,12 @@ ul.badges { width: 79%; margin-left: 1%; } +#badge-criteria li li { + list-style-type: none; } + +#badge-image-col { + flex: 0 0 400px; } + .badge-profile { vertical-align: top; } diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 0307759222cd7..9acfe6c3df945 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -11475,6 +11475,12 @@ ul.badges { width: 79%; margin-left: 1%; } +#badge-criteria li li { + list-style-type: none; } + +#badge-image-col { + flex: 0 0 400px; } + .badge-profile { vertical-align: top; }