Merge branch 'MDL-66940-311' of https://github.com/sarjona/moodle into MOODLE_311_STABLE

This commit is contained in:
Ilya Tregubov
2022-03-08 05:01:56 +02:00
16 changed files with 1062 additions and 299 deletions
+3 -1
View File
@@ -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;
+57
View File
@@ -0,0 +1,57 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
/**
* Display details of a badge.
*
* @package core_badges
* @copyright 2022 Sara Arjona ([email protected])
* @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();
+9 -4
View File
@@ -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);
}
}
+1 -1
View File
@@ -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) {
+175
View File
@@ -0,0 +1,175 @@
<?php
// 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 <http://www.gnu.org/licenses/>.
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 ([email protected])
* @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;
}
}
+80 -5
View File
@@ -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;
}
}
+158 -1
View File
@@ -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;
}
}
+16 -279
View File
@@ -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()]));
}
+386
View File
@@ -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 <http://www.gnu.org/licenses/>.
}}
{{!
@template core_badges/issued_badges
Display an issued badge.
Context variables required for this template:
* coursefullname - Course name (only available if it's a course badge).
* sitefullname - Site name (only available if it's a site badge).
* badgeimage - Badge image.
* expireddate - Date (in the past) when the badge expired. If expiredate is defined, this field will be empty [optional].
* expireddateformatted - Formatted expired date [optional].
* expiredate - Date (in the future) when the badge will expire. If expireddate is defined, this field will be empty [optional].
* badgename - Badge name.
* badgedescription - Badge description.
* badgeissuedon - Date where the badge was issued on by the user [optional].
* recipientname - User awarded with the badge [optional].
* recipientnotification.message - Message to be displayed if there is some issue with the recipient [optional].
* criteria - HTML code with the criteria to display.
* issuedby - Badge issuer.
* issuedbyemailobfuscated - Badge issuer email link obfuscated.
* hasotherfields - Wheter the badge has other fields or not.
* language - Badge language [optional].
* version - Badge version [optional].
* imageauthorname - Badge image author name [optional].
* imageauthoremail - Badge image author email [optional].
* imageauthorurl - Badge image author URL [optional].
* imagecaption - Badge image caption [optional].
* endorsement - Badge endorsement data, with id, badgeid, issuername... [optional].
* hasrelatedbadges - Whether the badge has related badges or not.
* relatedbadges - Array of related badges (if hasrelatedbadges is set to true).
* hasalignments - Whether the badge has alignments or not.
* alignments - Array of alignments (if hasalignments is set to true).
* hostedurl - The URL where the badge is hosted [optional].
Example context (json):
{
"coursefullname": "Learn Moodle 3.11 Basics",
"badgeimage": "https://moodlesite/pluginfile/badges/123.jpg",
"expiredate": 1656972000,
"badgename": "Lean Moodle 3.11 Basics helper",
"badgedescription":"This badge is awarded to people who have provided outstanding support to other participants in the MOOC",
"badgeissuedon": 1625491897,
"recipientname": "Judit Cortes",
"recipientnotification": {
"message": "This user cannot be verified as a recipient of this badge."
},
"criteria": "Complete <strong>ALL</strong> of the listed requirements.<ul><li>This badge has to be awarded by a user with the following role:<ul><li>Teacher</li></ul></li><li>The following activity has to be completed:<ul><li><strong>View video</strong></li></ul></li><li>The following badge has to be earned:<ul><li><strong>Lean Moodle 3.11 Basics participant</strong></li></ul></li></ul>",
"issuedby": "Moodle HQ",
"issuedbyemailobfuscated": "<a href=\"mailto:xxxxx\">Moodle HQ</a>",
"hasotherfields": true,
"language": "English",
"version": "1.0beta",
"imageauthorname": "Judit Blanque",
"imageauthoremail": "<a href=\"mailto:xxx\">[email protected]</a>",
"imageauthorurl": "http://juditblanque.cat",
"imagecaption": "This is a nice picture from my cat",
"endorsement": {
"id": "2",
"badgeid": "13",
"issuername": "Endorsement",
"issuerurl": "http://endorsement.cat",
"issueremail": "<a href=\"mailto:xxxx\">[email protected]</a>",
"claimid": "http://claim.cat",
"claimcomment": "This is an endorsement comment.",
"dateissued": "1625491680"
},
"hasrelatedbadges": true,
"relatedbadges": [
{
"id": "12",
"name": "Lean Moodle 3.11 Basics participant",
"version": "",
"language": "en",
"type": "2",
"url": "http://xxxxx/badges/overview.php?id=12"
}
],
"hasalignments": true,
"alignments": [
{
"id": "3",
"badgeid": "13",
"targetname": "Skill 1",
"targeturl": "http://skill1.cat",
"targetdescription": "This is the description for \"Skill 1\"",
"targetframework": "Framework name",
"targetcode": "S001"
},
{
"id": "2",
"badgeid": "13",
"targetname": "Alignment1",
"targeturl": "http://alignment1.cat",
"targetdescription": "This is the description for alignament1",
"targetframework": "Framework name",
"targetcode": "A1001"
}
],
"hostedurl": "http://externalbackpack/badge?id=ABC"
}
}}
<div id="badge" class="container-fluid">
<div class="row">
<div id="badge-image-col" class="col col-auto">
<img src="{{badgeimage}}" alt="{{badgename}}" width="300" class="mx-auto d-block"/>
{{#expireddateformatted}}
<span class="expireimage">
{{# pix }} i/expired, core, {{# str }} expireddate, badges, {{expireddateformatted}} {{/ str }}{{/ pix }}
</span>
{{/expireddateformatted}}
{{#downloadurl}}
<form action="{{downloadurl}}" method="post" id="downloadbadgeform">
<button type="submit" class="btn btn-secondary m-1 w-100">{{#str}}download{{/str}}</button>
</form>
{{/downloadurl}}
{{#addtobackpackurl}}
<form action="{{addtobackpackurl}}" method="post" id="addtobackpackform">
<button type="submit" class="btn btn-secondary m-1 w-100">{{#str}}addtobackpack, badges{{/str}}</button>
</form>
{{/addtobackpackurl}}
</div>
<div id="badge-details-col" class="col">
<h2>{{badgename}}</h2>
{{#recipientname}}
<div id="badge-awardedto" class="pt-1 pb-2">
{{#recipientnotification}}
{{> core/notification_warning}}
{{/recipientnotification}}
{{#str}}awardedto, core_badges, {{recipientname}}{{/str}}
</div>
{{/recipientname}}
<div id="badge-issued-expire" class="pt-1 pb-2">
<div class="pb-3">
<small>
{{#badgeissuedon}}
{{#str}}
issuedon,
core_badges,
{{#userdate}}{{badgeissuedon}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}}
{{/str}}
<br/>
{{/badgeissuedon}}
{{#expiredate}}
{{#str}}
expiresin,
core_badges,
{{#userdate}}{{expiredate}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}}
{{/str}}
<br/>
{{/expiredate}}
{{#expireddate}}
{{#str}}
expiredin,
core_badges,
{{#userdate}}{{expireddate}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}}
{{/str}}
{{/expireddate}}
</small>
</div>
{{#issuedby}}
<div class="pb-2">
{{#str}}
issuedby,
core_badges,
{{#issuedbyemailobfuscated}}
{{{issuedbyemailobfuscated}}}
{{/issuedbyemailobfuscated}}
{{^issuedbyemailobfuscated}}
{{issuedby}}
{{/issuedbyemailobfuscated}}
{{/str}}
</div>
{{/issuedby}}
{{#hostedurl}}
<div class="pb-2">
<a href="{{.}}" target="_blank" aria-label="{{#str}}hostedurldescription, core_badges{{/str}}">
{{#str}}hostedurl, core_badges{{/str}}
</a>
</div>
{{/hostedurl}}
{{#coursefullname}}
<div class="pb-2">
{{#str}}
course,
core_badges,
{{coursefullname}}
{{/str}}
</div>
{{/coursefullname}}
</div>
<p class="pb-4">{{{badgedescription}}}</p>
<div id="badge-criteria">
<h3>{{#str}}bcriteria, core_badges{{/str}}</h3>
{{{criteria}}}
</div>
{{#hasotherfields}}
<div id="badge-other-fields">
<a data-toggle="collapse" href="#collapseOtherDetails" role="button" aria-expanded="false" aria-controls="collapseOtherDetails">
{{#str}}moredetails, core_badges{{/str}}
</a>
<div class="collapse" id="collapseOtherDetails">
<div class="container ml-0">
{{#version}}
<dl>
<dt>
{{#str}}version, core_badges{{/str}}
</dt>
<dd>
{{version}}
</dd>
</dl>
{{/version}}
{{#language}}
<dl>
<dt>
{{#str}}language, core_badges{{/str}}
</dt>
<dd>
{{language}}
</dd>
</dl>
{{/language}}
{{#imageauthorname}}
<dl>
<dt>
{{#str}}imageauthorname, core_badges{{/str}}
</dt>
<dd>
{{imageauthorname}}
</dd>
</dl>
{{/imageauthorname}}
{{#imageauthoremail}}
<dl>
<dt>
{{#str}}imageauthoremail, core_badges{{/str}}
</dt>
<dd>
{{{imageauthoremail}}}
</dd>
</dl>
{{/imageauthoremail}}
{{#imageauthorurl}}
<dl>
<dt>
{{#str}}imageauthorurl, core_badges{{/str}}
</dt>
<dd>
<a href="{{imageauthorurl}}" target="_blank">{{imageauthorurl}}</a>
</dd>
</dl>
{{/imageauthorurl}}
{{#imagecaption}}
<dl>
<dt>
{{#str}}imagecaption, core_badges{{/str}}
</dt>
<dd>
{{imagecaption}}
</dd>
</dl>
{{/imagecaption}}
</div>
{{#endorsement}}
<h4>{{#str}}endorsement, core_badges{{/str}}</h4>
<div class="container ml-0">
<dl>
<dt>
{{#str}}issuername, core_badges{{/str}}
</dt>
<dd>
{{issuername}}
</dd>
</dl>
<dl>
<dt>
{{#str}}issueremail, core_badges{{/str}}
</dt>
<dd>
{{{issueremail}}}
</dd>
</dl>
<dl>
<dt>
{{#str}}issuerurl, core_badges{{/str}}
</dt>
<dd>
<a href="{{issuerurl}}" target="_blank">{{issuerurl}}</a>
</dd>
</dl>
<dl>
<dt>
{{#str}}dateawarded, core_badges{{/str}}
</dt>
<dd>
{{#userdate}}{{dateissued}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}}
</dd>
</dl>
<dl>
<dt>
{{#str}}claimid, core_badges{{/str}}
</dt>
<dd>
<a href="{{claimid}}" target="_blank">{{claimid}}</a>
</dd>
</dl>
<dl>
<dt>
{{#str}}claimcomment, core_badges{{/str}}
</dt>
<dd>
{{claimcomment}}
</dd>
</dl>
</div>
{{/endorsement}}
{{#hasrelatedbadges}}
<h4>{{#str}}relatedbages, core_badges{{/str}}</h4>
<ul>
{{/hasrelatedbadges}}
{{#relatedbadges}}
<li>
{{#url}}<a href="{{url}}" target="_blank">{{/url}}
{{name}}
{{#url}}</a>{{/url}}
</li>
{{/relatedbadges}}
{{#hasrelatedbadges}}
</ul>
{{/hasrelatedbadges}}
{{#hasalignments}}
<h4>{{#str}}alignment, core_badges{{/str}}</h4>
<ul>
{{/hasalignments}}
{{#alignments}}
<li>
<a href="{{targeturl}}" target="_blank">{{targetname}}</a>
</li>
{{/alignments}}
{{#hasalignments}}
</ul>
{{/hasalignments}}
</div>
</div>
{{/hasotherfields}}
</div>
</div>
</div>
+1 -1
View File
@@ -193,7 +193,7 @@ Feature: Award badges
And I click on "Course 1" "link" in the "region-main" "region"
And I should see "Course Badge"
And I click on "Course Badge" "link"
And "Course 1" "text" should appear after "Badge details" "text"
And "Course 1" "text" should appear after "Course" "text"
And "Kurs 1" "text" should not exist
@javascript
+137
View File
@@ -0,0 +1,137 @@
@core @core_badges @_file_upload @javascript
Feature: Display badges
In order to access to badges information
As a user
I need to view badges data awarded to users
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
# Create system badge and define a criterion.
And I log in as "admin"
And I navigate to "Badges > Add a new badge" in site administration
And I set the following fields to these values:
| Name | Testing system badge |
| Version | 1.1 |
| Language | Catalan |
| Description | Testing system badge description |
| Image author | http://author.example.com |
| Image caption | Test caption image |
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
And I press "Create badge"
And I set the field "type" to "Manual issue by role"
And I expand all fieldsets
And I set the field "Teacher" to "1"
And I press "Save"
Scenario: Display badge without expired date
# Enable the badge.
Given I press "Enable access"
And I press "Continue"
# Award badge to student1.
And I follow "Recipients (0)"
And I press "Award badge"
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
And I press "Award badge"
# Check badge details are displayed.
And I follow "Testing system badge"
And I follow "Recipients (1)"
When I click on "View issued badge" "link" in the "Student 1" "table_row"
Then I should see "Awarded to Student 1"
And I should see "This badge has to be awarded by a user with the following role:"
And I should not see "Expired"
And I should not see "Expires"
And I follow "More details"
And I should see "Catalan"
And I should see "1.1"
Scenario: Display badge with ALL criteria
# Add another criterion and enable the badge.
Given I set the field "type" to "Profile completion"
And I set the field "id_field_firstname" to "1"
And I press "Save"
And I press "Enable access"
And I press "Continue"
# Award badge to student1.
And I follow "Recipients (0)"
And I press "Award badge"
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
And I press "Award badge"
# Check badge details are displayed.
And I follow "Testing system badge"
And I follow "Recipients (1)"
When I click on "View issued badge" "link" in the "Student 1" "table_row"
Then I should see "Awarded to Student 1"
And I should see "Complete ALL of the listed requirements."
And I should see "This badge has to be awarded by a user with the following role:"
And I should see "The following user profile field has to be completed:"
And I should not see "Expired"
And I should not see "Expires"
And I follow "More details"
And I should see "Catalan"
And I should see "1.1"
Scenario: Display badge with ANY criteria
# Add another criterion and enable the badge.
Given I set the field "type" to "Profile completion"
And I set the field "id_field_firstname" to "1"
And I press "Save"
And I set the field "update" to "2"
And I press "Enable access"
And I press "Continue"
# Check badge details are displayed.
And I follow "Recipients (2)"
When I click on "View issued badge" "link" in the "Student 1" "table_row"
Then I should see "Awarded to Student 1"
And I should see "Complete ANY of the listed requirements."
And I should see "This badge has to be awarded by a user with the following role:"
And I should see "The following user profile field has to be completed:"
And I should not see "Expired"
And I should not see "Expires"
And I follow "More details"
And I should see "Catalan"
And I should see "1.1"
Scenario: Display badge with expiration date but not expired yet
# Set expired date to badge (future date).
Given I follow "Edit details"
When I click on "Relative date" "radio"
And I set the field "expireperiod[number]" to "1"
And I press "Save changes"
And I press "Enable access"
And I press "Continue"
# Award badge to student1.
And I follow "Recipients (0)"
And I press "Award badge"
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
And I press "Award badge"
# Check "Expires" date is displayed.
And I follow "Testing system badge"
And I follow "Recipients (1)"
And I click on "View issued badge" "link" in the "Student 1" "table_row"
Then I should see "Expires"
And I should not see "Expired"
Scenario: Display expired badge
# Set expired date to badge (relative date 1 seconds after the date of issue it).
Given I follow "Edit details"
When I click on "Relative date" "radio"
And I set the field "expireperiod[timeunit]" to "1"
And I set the field "expireperiod[number]" to "1"
And I press "Save changes"
And I press "Enable access"
And I press "Continue"
# Award badge to student1.
And I follow "Recipients (0)"
And I press "Award badge"
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
And I press "Award badge"
# Wait 1 second to guarantee the badge is expired.
And I wait "1" seconds
# Check "Expired" date is displayed.
And I follow "Testing system badge"
And I follow "Recipients (1)"
And I click on "View issued badge" "link" in the "Student 1" "table_row"
Then I should see "Expired"
And I should not see "Expires"
+14 -3
View File
@@ -76,6 +76,7 @@ $string['archivehelp'] = '<p>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'] = '<p>{$a->user} has completed all badge requirements and has been awarded the badge. View issued badge at {$a->link} </p>';
@@ -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 <strong>{$a}</strong> of the listed requirements.';
$string['criteria_descr_0'] = 'Complete <strong>{$a}</strong> of the listed requirements.';
$string['criteria_descr_1'] = '<strong>{$a}</strong> of the following activities are completed:';
$string['criteria_descr_2'] = 'This badge has to be awarded by the users with <strong>{$a}</strong> 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. ';
+5 -4
View File
@@ -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.');
}
}
/**
+8
View File
@@ -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;
}
+6
View File
@@ -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; }
+6
View File
@@ -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; }