diff --git a/badges/badge_json.php b/badges/badge_json.php
index b7526d5ec76..60f25a589f9 100644
--- a/badges/badge_json.php
+++ b/badges/badge_json.php
@@ -66,7 +66,9 @@ if ($badge->status != BADGE_STATUS_INACTIVE) {
$json['image'] = $urlimage;
}
- $json['criteria']['id'] = $url->out(false);
+ $params = ['id' => $badge->id];
+ $badgeurl = new moodle_url('/badges/badgeclass.php', $params);
+ $json['criteria']['id'] = $badgeurl->out(false);
$json['criteria']['narrative'] = $badge->markdown_badge_criteria();
$json['issuer'] = $badge->get_badge_issuer();
$json['@context'] = OPEN_BADGES_V2_CONTEXT;
diff --git a/badges/badgeclass.php b/badges/badgeclass.php
new file mode 100644
index 00000000000..c71b07df896
--- /dev/null
+++ b/badges/badgeclass.php
@@ -0,0 +1,57 @@
+.
+
+/**
+ * Display details of a badge.
+ *
+ * @package core_badges
+ * @copyright 2022 Sara Arjona (sara@moodle.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../config.php');
+require_once($CFG->libdir . '/badgeslib.php');
+
+$badgeid = required_param('id', PARAM_ALPHANUM);
+$badgeclass = new \core_badges\output\badgeclass($badgeid);
+
+$context = !empty($badgeclass) ? $badgeclass->context : \context_system::instance();
+$PAGE->set_context($context);
+$output = $PAGE->get_renderer('core', 'badges');
+$PAGE->set_url('/badges/badgeclass.php', ['id' => $badgeid]);
+$PAGE->set_pagelayout('base');
+$PAGE->set_title(get_string('badgedetails', 'badges'));
+
+if (!empty($badgeclass->badge)) {
+ $PAGE->navbar->add($badgeclass->badge->name);
+ $url = new moodle_url($CFG->wwwroot);
+ navigation_node::override_active_url($url);
+
+ echo $OUTPUT->header();
+ echo $output->render($badgeclass);
+} else {
+ echo $OUTPUT->header();
+ echo $OUTPUT->notification(get_string('error:relatedbadgedoesntexist', 'badges'));
+}
+
+// Trigger event, badge viewed.
+$other = ['badgeid' => $badgeclass->badgeid];
+$eventparams = ['context' => $PAGE->context, 'other' => $other];
+
+$event = \core\event\badge_viewed::create($eventparams);
+$event->trigger();
+
+echo $OUTPUT->footer();
diff --git a/badges/classes/assertion.php b/badges/classes/assertion.php
index bbfa50b4f0c..6565493c7c3 100644
--- a/badges/classes/assertion.php
+++ b/badges/classes/assertion.php
@@ -196,7 +196,10 @@ class core_badges_assertion {
}
}
$class['image'] = 'data:image/png;base64,' . $imagedata;
- $class['criteria'] = $this->_url->out(false); // Currently issued badge URL.
+
+ $params = ['id' => $this->get_badge_id()];
+ $badgeurl = new moodle_url('/badges/badgeclass.php', $params);
+ $class['criteria'] = $badgeurl->out(false); // Currently badge URL.
if ($issued) {
$params = ['id' => $this->get_badge_id(), 'obversion' => $this->_obversion];
$issuerurl = new moodle_url('/badges/issuer_json.php', $params);
@@ -281,13 +284,15 @@ class core_badges_assertion {
public function get_criteria_badge_class() {
$badge = new badge($this->_data->id);
$narrative = $badge->markdown_badge_criteria();
+ $params = ['id' => $this->get_badge_id()];
+ $badgeurl = new moodle_url('/badges/badgeclass.php', $params);
if (!empty($narrative)) {
- $criteria = array();
- $criteria['id'] = $this->_url->out(false);
+ $criteria = [];
+ $criteria['id'] = $badgeurl->out(false);
$criteria['narrative'] = $narrative;
return $criteria;
} else {
- return $this->_url->out(false);
+ return $badgeurl->out(false);
}
}
diff --git a/badges/classes/badge.php b/badges/classes/badge.php
index 6bae4e781cd..a5186070291 100644
--- a/badges/classes/badge.php
+++ b/badges/classes/badge.php
@@ -141,7 +141,7 @@ class badge {
$data = $DB->get_record('badge', array('id' => $badgeid));
if (empty($data)) {
- print_error('error:nosuchbadge', 'badges', $badgeid);
+ throw new moodle_exception('error:nosuchbadge', 'badges', '', $badgeid);
}
foreach ((array)$data as $field => $value) {
diff --git a/badges/classes/output/badgeclass.php b/badges/classes/output/badgeclass.php
new file mode 100644
index 00000000000..d66b37fd0c0
--- /dev/null
+++ b/badges/classes/output/badgeclass.php
@@ -0,0 +1,175 @@
+.
+
+namespace core_badges\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/badgeslib.php');
+
+use coding_exception;
+use context_course;
+use stdClass;
+use renderable;
+use core_badges\badge;
+use moodle_url;
+use renderer_base;
+
+/**
+ * Page to display badge information, such as name, description or criteria. This information is unrelated to assertions.
+ *
+ * @package core_badges
+ * @copyright 2022 Sara Arjona (sara@moodle.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class badgeclass implements renderable {
+
+ /** @var badge class */
+ public $badge;
+
+ /** @var badge class */
+ public $badgeid = 0;
+
+ /** @var \context The badge context*/
+ public $context;
+
+ /**
+ * Initializes the badge to display.
+ *
+ * @param int $id Id of the badge to display.
+ */
+ public function __construct(int $id) {
+ $this->badgeid = $id;
+ $this->badge = new badge($this->badgeid);
+ if ($this->badge->status == BADGE_STATUS_INACTIVE) {
+ // Inactive badges that haven't been published previously can't be displayed.
+ $this->badge = null;
+ } else {
+ $this->context = $this->badge->get_context();
+ }
+ }
+
+ /**
+ * 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 $DB, $SITE;
+
+ $data = new stdClass();
+ if ($this->context instanceof context_course) {
+ $data->coursefullname = format_string($DB->get_field('course', 'fullname', ['id' => $this->badge->courseid]),
+ true, ['context' => $this->context]);
+ } else {
+ $data->sitefullname = format_string($SITE->fullname, true, ['context' => $this->context]);
+ }
+
+ // Field: Image.
+ $storage = get_file_storage();
+ $imagefile = $storage->get_file($this->context->id, 'badges', 'badgeimage', $this->badgeid, '/', 'f3.png');
+ if ($imagefile) {
+ $imagedata = base64_encode($imagefile->get_content());
+ } else {
+ if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
+ // Unit tests the file might not exist yet.
+ $imagedata = '';
+ } else {
+ throw new coding_exception('Image file does not exist.');
+ }
+ }
+ $data->badgeimage = 'data:image/png;base64,' . $imagedata;
+
+ // Fields: Name, description.
+ $data->badgename = $this->badge->name;
+ $data->badgedescription = $this->badge->description;
+
+ // Field: Criteria.
+ // This method will return the HTML with the badge criteria.
+ $data->criteria = $output->print_badge_criteria($this->badge);
+
+ // Field: Issuer.
+ $data->issuedby = format_string($this->badge->issuername, true, ['context' => $this->context]);
+ if (isset($this->badge->issuercontact) && !empty($this->badge->issuercontact)) {
+ $data->issuedbyemailobfuscated = obfuscate_mailto($this->badge->issuercontact, $data->issuedby);
+ }
+
+ // Fields: Other details, such as language or version.
+ $data->hasotherfields = false;
+ if (!empty($this->badge->language)) {
+ $data->hasotherfields = true;
+ $languages = get_string_manager()->get_list_of_languages();
+ $data->language = $languages[$this->badge->language];
+ }
+ if (!empty($this->badge->version)) {
+ $data->hasotherfields = true;
+ $data->version = $this->badge->version;
+ }
+ if (!empty($this->badge->imageauthorname)) {
+ $data->hasotherfields = true;
+ $data->imageauthorname = $this->badge->imageauthorname;
+ }
+ if (!empty($this->badge->imageauthoremail)) {
+ $data->hasotherfields = true;
+ $data->imageauthoremail = obfuscate_mailto($this->badge->imageauthoremail, $this->badge->imageauthoremail);
+ }
+ if (!empty($this->badge->imageauthorurl)) {
+ $data->hasotherfields = true;
+ $data->imageauthorurl = $this->badge->imageauthorurl;
+ }
+ if (!empty($this->badge->imagecaption)) {
+ $data->hasotherfields = true;
+ $data->imagecaption = $this->badge->imagecaption;
+ }
+
+ // Field: Endorsement.
+ $endorsement = $this->badge->get_endorsement();
+ if (!empty($endorsement)) {
+ $data->hasotherfields = true;
+ $endorsement = $this->badge->get_endorsement();
+ $endorsement->issueremail = obfuscate_mailto($endorsement->issueremail, $endorsement->issueremail);
+ $data->endorsement = (array) $endorsement;
+ }
+
+ // Field: Related badges.
+ $relatedbadges = $this->badge->get_related_badges(true);
+ if (!empty($relatedbadges)) {
+ $data->hasotherfields = true;
+ $data->hasrelatedbadges = true;
+ $data->relatedbadges = [];
+ foreach ($relatedbadges as $related) {
+ if (isloggedin() && !is_guest($this->context)) {
+ $related->url = (new moodle_url('/badges/overview.php', ['id' => $related->id]))->out(false);
+ }
+ $data->relatedbadges[] = (array)$related;
+ }
+ }
+
+ // Field: Alignments.
+ $alignments = $this->badge->get_alignments();
+ if (!empty($alignments)) {
+ $data->hasotherfields = true;
+ $data->hasalignments = true;
+ $data->alignments = [];
+ foreach ($alignments as $alignment) {
+ $data->alignments[] = (array)$alignment;
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/badges/classes/output/external_badge.php b/badges/classes/output/external_badge.php
index 7fad503d1ee..f35d17f736f 100644
--- a/badges/classes/output/external_badge.php
+++ b/badges/classes/output/external_badge.php
@@ -31,6 +31,8 @@ defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/badgeslib.php');
use renderable;
+use renderer_base;
+use stdClass;
/**
* An external badges for external.php page
@@ -39,19 +41,19 @@ use renderable;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class external_badge implements renderable {
- /** @var issued badge */
+ /** @var stdClass Issued badge */
public $issued;
- /** @var User ID */
+ /** @var int User ID */
public $recipient;
- /** @var validation of external badge */
+ /** @var bool Validation of external badge */
public $valid = true;
/**
* Initializes the badge to display
*
- * @param object $badge External badge information.
+ * @param stdClass $badge External badge information.
* @param int $recipient User id.
*/
public function __construct($badge, $recipient) {
@@ -97,5 +99,78 @@ class external_badge implements renderable {
$this->valid = false;
}
}
-}
+ /**
+ * 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 {
+ $data = new stdClass();
+
+ $now = time();
+ if (isset($this->issued->assertion->expires)) {
+ if (!is_numeric($this->issued->assertion->expires)) {
+ $this->issued->assertion->expires = strtotime($this->issued->assertion->expires);
+ }
+ $expiration = $this->issued->assertion->expires;
+ } else {
+ $expiration = $now + 86400;
+ }
+
+ // Field: Image.
+ if (isset($this->issued->imageUrl)) {
+ $this->issued->image = $this->issued->imageUrl;
+ }
+ $data->badgeimage = $this->issued->image;
+
+ // Field: Expiration date.
+ if (isset($this->issued->assertion->expires)) {
+ if ($expiration < $now) {
+ $data->expireddate = $this->issued->assertion->expires;
+ $data->expireddateformatted = userdate(
+ $this->issued->assertion->expires,
+ get_string('strftimedatetime', 'langconfig')
+ );
+ } else {
+ $data->expiredate = $this->issued->assertion->expires;
+ }
+ }
+
+ // Fields: Name, description, issuedOn.
+ $data->badgename = $this->issued->assertion->badge->name;
+ $data->badgedescription = $this->issued->assertion->badge->description;
+ if (isset($this->issued->assertion->issued_on)) {
+ if (!is_numeric($this->issued->assertion->issued_on)) {
+ $this->issued->assertion->issued_on = strtotime($this->issued->assertion->issued_on);
+ }
+ $data->badgeissuedon = $this->issued->assertion->issued_on;
+ }
+
+ // Field: Recipient (the badge was awarded to this person).
+ $data->recipientname = fullname($this->recipient);
+ if (!$this->valid) {
+ $data->recipientnotification = new stdClass();
+ $data->recipientnotification->message = get_string('recipientvalidationproblem', 'badges');
+ }
+
+ // Field: Criteria.
+ if (isset($this->issued->assertion->badgeclass->criteria->narrative)) {
+ $data->criteria = $this->issued->assertion->badgeclass->criteria->narrative;
+ }
+
+ // Field: Issuer.
+ $data->issuedby = $this->issued->issuer->name;
+ if (isset($this->issued->issuer->contact) && !empty($this->issued->issuer->contact)) {
+ $data->issuedbyemailobfuscated = obfuscate_mailto($this->issued->issuer->contact, $data->issuedby);
+ }
+
+ // Field: Hosted URL.
+ if (isset($this->issued->hostedUrl) && !empty($this->issued->hostedUrl)) {
+ $data->hostedurl = $this->issued->hostedUrl;
+ }
+
+ return $data;
+ }
+}
diff --git a/badges/classes/output/issued_badge.php b/badges/classes/output/issued_badge.php
index 2b9e891efe1..e6a7bacb63d 100644
--- a/badges/classes/output/issued_badge.php
+++ b/badges/classes/output/issued_badge.php
@@ -30,7 +30,12 @@ defined('MOODLE_INTERNAL') || die();
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 @@ class issued_badge implements renderable {
$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 @@ class issued_badge implements renderable {
$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 51cbcf1b385..bdc2dbd7023 100644
--- a/badges/renderer.php
+++ b/badges/renderer.php
@@ -323,178 +323,19 @@ class core_badges_renderer extends plugin_renderer_base {
* @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;
- }
+ $data = $ibadge->export_for_template($this);
+ return parent::render_from_template('core_badges/issued_badge', $data);
+ }
- $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->imagecaption, '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')] = format_string($badge->issuername, true,
- ['context' => context_system::instance()]);
-
- 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')] = format_string($coursename, true, ['context' => context_course::instance($badge->courseid)]);
- }
- $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;
+ /**
+ * Render an issued badge.
+ *
+ * @param \core_badges\output\badgeclass $badge
+ * @return string
+ */
+ protected function render_badgeclass(\core_badges\output\badgeclass $badge) {
+ $data = $badge->export_for_template($this);
+ return parent::render_from_template('core_badges/issued_badge', $data);
}
/**
@@ -504,108 +345,8 @@ class core_badges_renderer extends plugin_renderer_base {
* @return string
*/
protected function render_external_badge(\core_badges\output\external_badge $ibadge) {
- $issued = $ibadge->issued;
- $assertion = $issued->assertion;
- $issuer = $assertion->badge->issuer;
- $userinfo = $ibadge->recipient;
- $table = new html_table();
- $today = strtotime(date('Y-m-d'));
-
- $output = '';
- $output .= html_writer::start_tag('div', array('id' => 'badge'));
- $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
- if (isset($issued->imageUrl)) {
- $issued->image = $issued->imageUrl;
- }
- if (is_object($issued->image)) {
- if (!empty($issued->image->caption)) {
- $issued->imagecaption = $issued->image->caption;
- }
- $issued->image = $issued->image->id;
- }
- $imagecaption = $issued->imagecaption ?? '';
- $output .= html_writer::empty_tag('img', ['src' => $issued->image, 'width' => '100', 'alt' => $imagecaption]);
- if (isset($assertion->expires)) {
- $expiration = is_numeric($assertion->expires) ? $assertion->expires : strtotime($assertion->expires);
- if ($expiration < $today) {
- $output .= $this->output->pix_icon('i/expired',
- get_string('expireddate', 'badges', userdate($expiration)),
- 'moodle',
- array('class' => 'expireimage'));
- }
- }
- $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();
- // Technically, we should alway have a user at this point, but added an extra check just in case.
- if ($userinfo) {
- if (!$ibadge->valid) {
- $notify = $this->output->notification(get_string('recipientvalidationproblem', 'badges'), 'notifynotice');
- $dl[get_string('name')] = fullname($userinfo) . $notify;
- } else {
- $dl[get_string('name')] = fullname($userinfo);
- }
- } else {
- $notify = $this->output->notification(get_string('recipientidentificationproblem', 'badges'), 'notifynotice');
- $dl[get_string('name')] = $notify;
- }
- $output .= $this->definition_list($dl);
-
- $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
- $dl = array();
- $dl[get_string('issuername', 'badges')] = s($issuer->name);
- if (isset($issuer->origin)) {
- $dl[get_string('issuerurl', 'badges')] = html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin));
- }
-
- if (isset($issuer->contact)) {
- $dl[get_string('contact', 'badges')] = obfuscate_mailto($issuer->contact);
- }
- $output .= $this->definition_list($dl);
-
- $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
- $dl = array();
- $dl[get_string('name')] = s($assertion->badge->name);
- $dl[get_string('description', 'badges')] = s($assertion->badge->description);
- if (isset($assertion->badge->criteria)) {
- $dl[get_string('bcriteria', 'badges')] = html_writer::tag(
- 'a',
- s($assertion->badge->criteria),
- array('href' => $assertion->badge->criteria)
- );
- }
- $output .= $this->definition_list($dl);
-
- $dl = array();
- if (isset($assertion->issued_on)) {
- $issuedate = is_numeric($assertion->issued_on) ? $assertion->issued_on : strtotime($assertion->issued_on);
- $dl[get_string('dateawarded', 'badges')] = userdate($issuedate);
- }
- if (isset($assertion->expires)) {
- if ($expiration < $today) {
- $dl[get_string('expirydate', 'badges')] = userdate($expiration) . get_string('warnexpired', 'badges');
- } else {
- $dl[get_string('expirydate', 'badges')] = userdate($expiration);
- }
- }
- if (isset($assertion->evidence)) {
- $dl[get_string('evidence', 'badges')] = html_writer::tag(
- 'a',
- s($assertion->evidence),
- array('href' => $assertion->evidence)
- );
- }
- if (!empty($dl)) {
- $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
- $output .= $this->definition_list($dl);
- }
- $output .= html_writer::end_tag('div');
-
- return $output;
+ $data = $ibadge->export_for_template($this);
+ return parent::render_from_template('core_badges/issued_badge', $data);
}
/**
@@ -943,12 +684,8 @@ class core_badges_renderer extends plugin_renderer_base {
}
// 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 00000000000..53222588e4d
--- /dev/null
+++ b/badges/templates/issued_badge.mustache
@@ -0,0 +1,386 @@
+{{!
+ 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}}}
+ +This option means that the badge will be marked as $string['attachment'] = 'Attach badge to message'; $string['attachment_help'] = 'If enabled, an issued badge will be attached to the recipient\'s email for download. (Attachments must be enabled in Site administration / Server / Email / Outgoing mail configuration to use this option.)'; $string['award'] = 'Award badge'; +$string['awardedto'] = 'Awarded to {$a}'; $string['awardedtoyou'] = 'Issued to me'; $string['awardoncron'] = 'Access to the badges was successfully enabled. Too many users can instantly earn this badge. To ensure site performance, this action will take some time to process.'; $string['awards'] = 'Recipients'; @@ -186,9 +187,11 @@ $string['connecting'] = 'Connecting...'; $string['contact'] = 'Contact'; $string['contact_help'] = 'An email address associated with the badge issuer.'; $string['copyof'] = 'Copy of {$a}'; +$string['course'] = 'Course: {$a}'; $string['coursebadgesdisabled'] = 'Course badges are not enabled on this site.'; $string['coursecompletion'] = 'Users must complete this course.'; $string['coursebadges'] = 'Badges'; +$string['coursebadgetitle'] = '{$a} course badge'; $string['create'] = 'New badge'; $string['createbutton'] = 'Create badge'; $string['creatorbody'] = '
{$a->user} has completed all badge requirements and has been awarded the badge. View issued badge at {$a->link}
'; @@ -225,7 +228,7 @@ $string['criteria_descr_single_6'] = 'The following user profile field has to be $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'; @@ -340,6 +343,8 @@ $string['existingrecipients'] = 'Existing badge recipients'; $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.'; @@ -354,6 +359,8 @@ $string['externalbadges_help'] = 'This area displays badges from your external b $string['fixed'] = 'Fixed date'; $string['hidden'] = 'Hidden'; $string['hiddenbadge'] = 'Unfortunately, the badge owner has not made this information available.'; +$string['hostedurl'] = 'External URL'; +$string['hostedurldescription'] = 'External URL where the badge is hosted'; $string['imageauthoremail'] = 'Image author\'s email'; $string['imageauthoremail_help'] = 'If specified, the email address of the badge image author is displayed on the badge page.'; $string['imageauthorname'] = 'Image author\'s name'; @@ -361,8 +368,10 @@ $string['imageauthorname_help'] = 'If specified, the name of the badge image aut $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.'; @@ -396,6 +405,7 @@ $string['messagesubject'] = 'Congratulations! You just earned a badge!'; $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'; @@ -486,7 +496,7 @@ $string['privacy:metadata:manualaward:recipientid'] = 'The ID of the user who is $string['recipients'] = 'Badge recipients'; $string['recipientdetails'] = 'Recipient details'; $string['recipientidentificationproblem'] = 'Cannot find a recipient of this badge among the existing users.'; -$string['recipientvalidationproblem'] = 'Current user cannot be verified as a recipient of this badge.'; +$string['recipientvalidationproblem'] = 'This user cannot be verified as a recipient of this badge.'; $string['relative'] = 'Relative date'; $string['relatedbages'] = 'Related badges'; $string['revoke'] = 'Revoke badge'; @@ -516,6 +526,7 @@ $string['sitebadges'] = 'Site badges'; $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/lib/classes/event/badge_viewed.php b/lib/classes/event/badge_viewed.php index 1f1e15a3bdf..5beda67e2fc 100644 --- a/lib/classes/event/badge_viewed.php +++ b/lib/classes/event/badge_viewed.php @@ -73,7 +73,11 @@ class badge_viewed extends base { * @return \moodle_url */ public function get_url() { - return new \moodle_url('/badges/badge.php', array('hash' => $this->other['badgehash'])); + if (isset($this->other['badgehash'])) { + return new \moodle_url('/badges/badge.php', ['hash' => $this->other['badgehash']]); + } + + return new \moodle_url('/badges/badgeclass.php', ['id' => $this->other['badgeid']]); } /** @@ -88,9 +92,6 @@ class badge_viewed extends base { if (!isset($this->other['badgeid'])) { throw new \coding_exception('The \'badgeid\' must be set in other.'); } - if (!isset($this->other['badgehash'])) { - throw new \coding_exception('The \'badgehash\' must be set in other.'); - } } /** diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index a8c56c179ea..4219c2ecba6 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -1970,6 +1970,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 9e97b730497..96fe44f4304 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -11272,6 +11272,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 5be8318aafe..d1a3c364ae3 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -11490,6 +11490,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; }