diff --git a/badges/classes/output/issued_badge.php b/badges/classes/output/issued_badge.php index 2b9e891efe183..e6a7bacb63d13 100644 --- a/badges/classes/output/issued_badge.php +++ b/badges/classes/output/issued_badge.php @@ -30,7 +30,12 @@ require_once($CFG->libdir . '/badgeslib.php'); +use context_system; +use stdClass; use renderable; +use core_badges\badge; +use moodle_url; +use renderer_base; /** * An issued badges for badge.php page @@ -68,6 +73,9 @@ public function __construct($hash) { $this->hash = $hash; $assertion = new \core_badges_assertion($hash, badges_open_badges_backpack_api()); $this->issued = $assertion->get_badge_assertion(); + if (!is_numeric($this->issued['issuedOn'])) { + $this->issued['issuedOn'] = strtotime($this->issued['issuedOn']); + } $this->badgeclass = $assertion->get_badge_class(); $rec = $DB->get_record_sql('SELECT userid, visible, badgeid @@ -85,5 +93,154 @@ public function __construct($hash) { $this->badgeid = $rec->badgeid; } } -} + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param renderer_base $output Renderer base. + * @return stdClass + */ + public function export_for_template(renderer_base $output): stdClass { + global $CFG, $DB, $SITE, $USER; + + $now = time(); + if (isset($this->issued['expires'])) { + if (!is_numeric($this->issued['expires'])) { + $this->issued['expires'] = strtotime($this->issued['expires']); + } + $expiration = $this->issued['expires']; + } else { + $expiration = $now + 86400; + } + + $context = null; + $data = new stdClass(); + $badge = new badge($this->badgeid); + if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) { + $coursename = $DB->get_field('course', 'fullname', ['id' => $badge->courseid]); + $data->coursefullname = $coursename; + $context = \context_course::instance($badge->courseid); + } else { + $data->sitefullname = $SITE->fullname; + $context = \context_system::instance(); + } + + // Field: Image. + $data->badgeimage = is_array($this->badgeclass['image']) ? $this->badgeclass['image']['id'] : $this->badgeclass['image']; + + // Field: Expiration date. + if (isset($this->issued['expires'])) { + if ($expiration < $now) { + $data->expireddate = $this->issued['expires']; + $data->expireddateformatted = userdate($this->issued['expires'], get_string('strftimedatetime', 'langconfig')); + } else { + $data->expiredate = $this->issued['expires']; + } + } + + // Fields: Name, description, issuedOn. + $data->badgename = $badge->name; + $data->badgedescription = $badge->description; + $data->badgeissuedon = $this->issued['issuedOn']; + + // Field: Recipient (the badge was awarded to this person). + if ($this->recipient->deleted) { + $strdata = new stdClass(); + $strdata->user = fullname($this->recipient); + $strdata->site = format_string($SITE->fullname, true, ['context' => context_system::instance()]); + $data->recipientname = get_string('error:userdeleted', 'badges', $strdata); + } else { + $data->recipientname = fullname($this->recipient); + } + + // Field: Criteria. + // This method will return the HTML with the badge criteria. + $data->criteria = $output->print_badge_criteria($badge); + + // Field: Issuer. + $data->issuedby = $badge->issuername; + if (isset($badge->issuercontact) && !empty($badge->issuercontact)) { + $data->issuedbyemailobfuscated = obfuscate_mailto($badge->issuercontact, $badge->issuername); + } + + // Fields: Other details, such as language or version. + $data->hasotherfields = false; + if (!empty($badge->language)) { + $data->hasotherfields = true; + $languages = get_string_manager()->get_list_of_languages(); + $data->language = $languages[$badge->language]; + } + if (!empty($badge->version)) { + $data->hasotherfields = true; + $data->version = $badge->version; + } + if (!empty($badge->imageauthorname)) { + $data->hasotherfields = true; + $data->imageauthorname = $badge->imageauthorname; + } + if (!empty($badge->imageauthoremail)) { + $data->hasotherfields = true; + $data->imageauthoremail = obfuscate_mailto($badge->imageauthoremail, $badge->imageauthoremail); + } + if (!empty($badge->imageauthorurl)) { + $data->hasotherfields = true; + $data->imageauthorurl = $badge->imageauthorurl; + } + if (!empty($badge->imagecaption)) { + $data->hasotherfields = true; + $data->imagecaption = $badge->imagecaption; + } + + // Field: Endorsement. + $endorsement = $badge->get_endorsement(); + if (!empty($endorsement)) { + $data->hasotherfields = true; + $endorsement = $badge->get_endorsement(); + $endorsement->issueremail = obfuscate_mailto($endorsement->issueremail, $endorsement->issueremail); + $data->endorsement = (array) $endorsement; + } + + // Field: Related badges. + $relatedbadges = $badge->get_related_badges(true); + if (!empty($relatedbadges)) { + $data->hasotherfields = true; + $data->hasrelatedbadges = true; + $data->relatedbadges = []; + foreach ($relatedbadges as $related) { + if (isloggedin() && !is_guest($context)) { + $related->url = (new moodle_url('/badges/overview.php', ['id' => $related->id]))->out(false); + } + $data->relatedbadges[] = (array)$related; + } + } + + // Field: Alignments. + $alignments = $badge->get_alignments(); + if (!empty($alignments)) { + $data->hasotherfields = true; + $data->hasalignments = true; + $data->alignments = []; + foreach ($alignments as $alignment) { + $data->alignments[] = (array)$alignment; + } + } + + // Buttons to display. + if ($USER->id == $this->recipient->id && !empty($CFG->enablebadges)) { + $data->downloadurl = (new moodle_url('/badges/badge.php', ['hash' => $this->hash, 'bake' => true]))->out(false); + + if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now) + && $userbackpack = badges_get_user_backpack($USER->id)) { + + if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2P1) { + $addtobackpackurl = new moodle_url('/badges/backpack-export.php', ['hash' => $this->hash]); + } else { + $addtobackpackurl = new moodle_url('/badges/backpack-add.php', ['hash' => $this->hash]); + } + $data->addtobackpackurl = $addtobackpackurl->out(false); + } + } + + return $data; + } +} diff --git a/badges/renderer.php b/badges/renderer.php index ba16434237b40..81b733024d466 100644 --- a/badges/renderer.php +++ b/badges/renderer.php @@ -313,176 +313,8 @@ public function print_badge_table_actions($badge, $context) { * @return string */ protected function render_issued_badge(\core_badges\output\issued_badge $ibadge) { - global $USER, $CFG, $DB, $SITE; - $issued = $ibadge->issued; - $userinfo = $ibadge->recipient; - $badgeclass = $ibadge->badgeclass; - $badge = new badge($ibadge->badgeid); - $now = time(); - if (isset($issued['expires'])) { - if (!is_numeric($issued['expires'])) { - $issued['expires'] = strtotime($issued['expires']); - } - $expiration = $issued['expires']; - } else { - $expiration = $now + 86400; - } - - $badgeimage = is_array($badgeclass['image']) ? $badgeclass['image']['id'] : $badgeclass['image']; - $languages = get_string_manager()->get_list_of_languages(); - - $output = ''; - $output .= html_writer::start_tag('div', array('id' => 'badge')); - $output .= html_writer::start_tag('div', array('id' => 'badge-image')); - $output .= html_writer::empty_tag('img', array('src' => $badgeimage, 'alt' => $badge->name, 'width' => '100')); - if ($expiration < $now) { - $output .= $this->output->pix_icon('i/expired', - get_string('expireddate', 'badges', userdate($issued['expires'])), - 'moodle', - array('class' => 'expireimage')); - } - - if ($USER->id == $userinfo->id && !empty($CFG->enablebadges)) { - $output .= $this->output->single_button( - new moodle_url('/badges/badge.php', array('hash' => $ibadge->hash, 'bake' => true)), - get_string('download'), - 'POST'); - if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now) - && $userbackpack = badges_get_user_backpack($USER->id)) { - - if (badges_open_badges_backpack_api($userbackpack->id) == OPEN_BADGES_V2P1) { - $assertion = new moodle_url('/badges/backpack-export.php', array('hash' => $ibadge->hash)); - } else { - $assertion = new moodle_url('/badges/backpack-add.php', array('hash' => $ibadge->hash)); - } - - $attributes = ['class' => 'btn btn-secondary m-1', 'role' => 'button']; - $tobackpack = html_writer::link($assertion, get_string('addtobackpack', 'badges'), $attributes); - $output .= $tobackpack; - } - } - $output .= html_writer::end_tag('div'); - - $output .= html_writer::start_tag('div', array('id' => 'badge-details')); - // Recipient information. - $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3); - $dl = array(); - if ($userinfo->deleted) { - $strdata = new stdClass(); - $strdata->user = fullname($userinfo); - $strdata->site = format_string($SITE->fullname, true, array('context' => context_system::instance())); - - $dl[get_string('name')] = get_string('error:userdeleted', 'badges', $strdata); - } else { - $dl[get_string('name')] = fullname($userinfo); - } - $output .= $this->definition_list($dl); - - $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3); - $dl = array(); - $dl[get_string('issuername', 'badges')] = $badge->issuername; - if (isset($badge->issuercontact) && !empty($badge->issuercontact)) { - $dl[get_string('contact', 'badges')] = obfuscate_mailto($badge->issuercontact); - } - $output .= $this->definition_list($dl); - - $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3); - $dl = array(); - $dl[get_string('name')] = $badge->name; - if (!empty($badge->version)) { - $dl[get_string('version', 'badges')] = $badge->version; - } - if (!empty($badge->language)) { - $dl[get_string('language')] = $languages[$badge->language]; - } - $dl[get_string('description', 'badges')] = $badge->description; - if (!empty($badge->imageauthorname)) { - $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname; - } - if (!empty($badge->imageauthoremail)) { - $dl[get_string('imageauthoremail', 'badges')] = - html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail)); - } - if (!empty($badge->imageauthorurl)) { - $dl[get_string('imageauthorurl', 'badges')] = - html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank')); - } - if (!empty($badge->imagecaption)) { - $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption; - } - - if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) { - $coursename = $DB->get_field('course', 'fullname', array('id' => $badge->courseid)); - $dl[get_string('course')] = $coursename; - } - $dl[get_string('bcriteria', 'badges')] = self::print_badge_criteria($badge); - $output .= $this->definition_list($dl); - - $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3); - $dl = array(); - if (!is_numeric($issued['issuedOn'])) { - $issued['issuedOn'] = strtotime($issued['issuedOn']); - } - $dl[get_string('dateawarded', 'badges')] = userdate($issued['issuedOn']); - if (isset($issued['expires'])) { - if ($issued['expires'] < $now) { - $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']) . get_string('warnexpired', 'badges'); - - } else { - $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']); - } - } - - // Print evidence. - $agg = $badge->get_aggregation_methods(); - $evidence = $badge->get_criteria_completions($userinfo->id); - $eids = array_map(function($o) { - return $o->critid; - }, $evidence); - unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]); - - $items = array(); - foreach ($badge->criteria as $type => $c) { - if (in_array($c->id, $eids)) { - if (count($c->params) == 1) { - $items[] = get_string('criteria_descr_single_' . $type , 'badges') . $c->get_details(); - } else { - $items[] = get_string('criteria_descr_' . $type , 'badges', - core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) . $c->get_details(); - } - } - } - - $dl[get_string('evidence', 'badges')] = get_string('completioninfo', 'badges') . html_writer::alist($items, array(), 'ul'); - $output .= $this->definition_list($dl); - $endorsement = $badge->get_endorsement(); - if (!empty($endorsement)) { - $output .= self::print_badge_endorsement($badge); - } - - $relatedbadges = $badge->get_related_badges(true); - $items = array(); - foreach ($relatedbadges as $related) { - $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id)); - $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank')); - } - if (!empty($items)) { - $output .= $this->heading(get_string('relatedbages', 'badges'), 3); - $output .= html_writer::alist($items, array(), 'ul'); - } - - $alignments = $badge->get_alignments(); - if (!empty($alignments)) { - $output .= $this->heading(get_string('alignment', 'badges'), 3); - $items = array(); - foreach ($alignments as $alignment) { - $items[] = html_writer::link($alignment->targeturl, $alignment->targetname, array('target' => '_blank')); - } - $output .= html_writer::alist($items, array(), 'ul'); - } - $output .= html_writer::end_tag('div'); - - return $output; + $data = $ibadge->export_for_template($this); + return parent::render_from_template('core_badges/issued_badge', $data); } /** @@ -924,12 +756,8 @@ public function print_badge_criteria(badge $badge, $short = '') { } // Get the condition string. - if (count($badge->criteria) == 2) { - $condition = ''; - if (!$short) { - $condition = get_string('criteria_descr', 'badges'); - } - } else { + $condition = ''; + if (count($badge->criteria) != 2) { $condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges', core_text::strtoupper($agg[$badge->get_aggregation_method()])); } diff --git a/badges/templates/issued_badge.mustache b/badges/templates/issued_badge.mustache new file mode 100644 index 0000000000000..c9deadf455ef9 --- /dev/null +++ b/badges/templates/issued_badge.mustache @@ -0,0 +1,364 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @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 defined). If expiredate is defined, this field will be empty. + * expireddateformatted - Formatted expired date. + * expiredate - Date (in the future) when the badge will expire (if defined). If expireddate is defined, this field will be empty. + * badgename - Badge name. + * badgedescription - Badge description. + * badgeissuedon - Date where the badge was issued on by the user. + * recipientname - User awarded with the badge. + * 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). + + 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", + "criteria": "Complete ALL of the listed requirements.;", + "issuedby": "Moodle HQ", + "issuedbyemailobfuscated": "Moodle HQ", + "hasotherfields": true, + "language": "English", + "version": "1.0beta", + "imageauthorname": "Judit Blanque", + "imageauthoremail": "judit@moodle.invalid", + "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": "endorsement@moodle.invalid", + "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" + } + ] + } +}} + +
+
+
+ {{badgename}} + {{#expireddateformatted}} + + {{# pix }} i/expired, core, {{# str }} expireddate, badges, {{expireddateformatted}} {{/ str }}{{/ pix }} + + {{/expireddateformatted}} + {{#downloadurl}} +
+ +
+ {{/downloadurl}} + {{#addtobackpackurl}} +
+ +
+ {{/addtobackpackurl}} +
+ +
+

{{badgename}}

+
+ {{#str}}awardedto, core_badges, {{recipientname}}{{/str}} +
+ +
+
+ + {{#str}} + issuedon, + core_badges, + {{#userdate}}{{badgeissuedon}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}} + {{/str}} +
+ {{#expiredate}} + {{#str}} + expiresin, + core_badges, + {{#userdate}}{{expiredate}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}} + {{/str}} +
+ {{/expiredate}} + {{#expireddate}} + {{#str}} + expiredin, + core_badges, + {{#userdate}}{{expireddate}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}} + {{/str}} + {{/expireddate}} +
+
+ + {{#issuedby}} +
+ {{#str}} + issuedby, + core_badges, + {{#issuedbyemailobfuscated}} + {{{issuedbyemailobfuscated}}} + {{/issuedbyemailobfuscated}} + {{^issuedbyemailobfuscated}} + {{issuedby}} + {{/issuedbyemailobfuscated}} + {{/str}} +
+ {{/issuedby}} + + {{#coursefullname}} +
+ {{#str}} + course, + core_badges, + {{coursefullname}} + {{/str}} +
+ {{/coursefullname}} +
+ +

{{{badgedescription}}}

+ +
+

{{#str}}bcriteria, core_badges{{/str}}

+ {{{criteria}}} +
+ + {{#hasotherfields}} +
+ +
+
+ {{#version}} +
+
+ {{#str}}version, core_badges{{/str}} +
+
+ {{version}} +
+
+ {{/version}} + + {{#language}} +
+
+ {{#str}}language, core_badges{{/str}} +
+
+ {{language}} +
+
+ {{/language}} + + {{#imageauthorname}} +
+
+ {{#str}}imageauthorname, core_badges{{/str}} +
+
+ {{imageauthorname}} +
+
+ {{/imageauthorname}} + + {{#imageauthoremail}} +
+
+ {{#str}}imageauthoremail, core_badges{{/str}} +
+
+ {{{imageauthoremail}}} +
+
+ {{/imageauthoremail}} + + {{#imageauthorurl}} +
+
+ {{#str}}imageauthorurl, core_badges{{/str}} +
+
+ {{imageauthorurl}} +
+
+ {{/imageauthorurl}} + {{#imagecaption}} +
+
+ {{#str}}imagecaption, core_badges{{/str}} +
+
+ {{imagecaption}} +
+
+ {{/imagecaption}} +
+ + {{#endorsement}} +

{{#str}}endorsement, core_badges{{/str}}

+
+
+
+ {{#str}}issuername, core_badges{{/str}} +
+
+ {{issuername}} +
+
+ +
+
+ {{#str}}issueremail, core_badges{{/str}} +
+
+ {{{issueremail}}} +
+
+ +
+
+ {{#str}}issuerurl, core_badges{{/str}} +
+
+ {{issuerurl}} +
+
+ +
+
+ {{#str}}dateawarded, core_badges{{/str}} +
+
+ {{#userdate}}{{dateissued}}, {{#str}} strftimedatetime, langconfig {{/str}}{{/userdate}} +
+
+ +
+
+ {{#str}}claimid, core_badges{{/str}} +
+
+ {{claimid}} +
+
+ +
+
+ {{#str}}claimcomment, core_badges{{/str}} +
+
+ {{claimcomment}} +
+
+
+ {{/endorsement}} + + {{#hasrelatedbadges}} +

{{#str}}relatedbages, core_badges{{/str}}

+ + {{/hasrelatedbadges}} + + {{#hasalignments}} +

{{#str}}alignment, core_badges{{/str}}

+
    + {{/hasalignments}} + {{#alignments}} +
  • + {{targetname}} +
  • + {{/alignments}} + {{#hasalignments}} +
+ {{/hasalignments}} +
+
+ {{/hasotherfields}} +
+
+
diff --git a/badges/tests/behat/view_badge.feature b/badges/tests/behat/view_badge.feature new file mode 100644 index 0000000000000..fa2e0c6cb3e0e --- /dev/null +++ b/badges/tests/behat/view_badge.feature @@ -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" diff --git a/lang/en/badges.php b/lang/en/badges.php index 12f250750457e..ed467bf78d30b 100644 --- a/lang/en/badges.php +++ b/lang/en/badges.php @@ -76,6 +76,7 @@ $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'; @@ -188,9 +189,11 @@ $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}

'; @@ -227,7 +230,7 @@ $string['criteria_descr_single_7'] = 'The following badge has to be earned:'; $string['criteria_descr_single_8'] = 'Membership in the following cohort is required:'; $string['criteria_descr_single_9'] = 'The following competencies have to be completed:'; -$string['criteria_descr_0'] = 'Users are awarded this badge when they complete {$a} of the listed requirements.'; +$string['criteria_descr_0'] = 'Complete {$a} of the listed requirements.'; $string['criteria_descr_1'] = '{$a} of the following activities are completed:'; $string['criteria_descr_2'] = 'This badge has to be awarded by the users with {$a} of the following roles:'; $string['criteria_descr_4'] = 'Users must complete the course'; @@ -342,6 +345,8 @@ $string['expired'] = 'Expired'; $string['expiredate'] = 'This badge expires on {$a}.'; $string['expireddate'] = 'This badge expired on {$a}.'; +$string['expiredin'] = 'Expired {$a}'; +$string['expiresin'] = 'Expires {$a}'; $string['expireperiod'] = 'This badge expires {$a} day(s) after being issued.'; $string['expireperiodh'] = 'This badge expires {$a} hour(s) after being issued.'; $string['expireperiodm'] = 'This badge expires {$a} minute(s) after being issued.'; @@ -363,8 +368,10 @@ $string['imageauthorurl'] = 'Image author\'s URL'; $string['imageauthorurl_help'] = 'If specified, a link to the badge image author\'s website is displayed on the badge page. The URL should have a prefix http:// or https://.'; $string['invalidurl'] = 'Invalid URL'; -$string['issuedbadge'] = 'Issued badge information'; $string['issuancedetails'] = 'Badge expiry'; +$string['issuedbadge'] = 'Issued badge information'; +$string['issuedby'] = 'Issued by {$a}'; +$string['issuedon'] = 'Issued {$a}'; $string['issuerdetails'] = 'Issuer details'; $string['issueremail'] = 'Email'; $string['issueremail_help'] = 'A contact email address of the organisation issuing the endorsement.'; @@ -398,6 +405,7 @@ $string['method'] = 'This criterion is complete when...'; $string['mingrade'] = 'Minimum grade required'; $string['month'] = 'Month(s)'; +$string['moredetails'] = 'More details'; $string['mybadges'] = 'My badges'; $string['mybackpack'] = 'My backpack settings'; $string['never'] = 'Never'; @@ -518,6 +526,7 @@ $string['sitebadges_help'] = 'Site badges can only be awarded to users for site-related activities. These include completing a set of courses or parts of user profiles. Site badges can also be issued manually by one user to another. Badges for course-related activities must be created at the course level. Course badges can be found under Course Administration > Badges.'; +$string['sitebadgetitle'] = '{$a} site badge'; $string['statusmessage_0'] = 'This badge is currently not available to users. Enable access if you want users to earn this badge. '; $string['statusmessage_1'] = 'This badge is currently available to users. Disable access to make any changes. '; $string['statusmessage_2'] = 'This badge is currently not available to users, and its criteria are locked. Enable access if you want users to earn this badge. '; diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index e53b43cbfd9b0..f5c33cb2c2854 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -1948,6 +1948,14 @@ ul.badges { } } +#badge-criteria li li { + list-style-type: none; +} + +#badge-image-col { + flex: 0 0 400px; +} + .badge-profile { vertical-align: top; } diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 107bb9846ce01..3c9a90d90bf86 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -11257,6 +11257,12 @@ ul.badges { width: 79%; margin-left: 1%; } +#badge-criteria li li { + list-style-type: none; } + +#badge-image-col { + flex: 0 0 400px; } + .badge-profile { vertical-align: top; } diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 0307759222cd7..9acfe6c3df945 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -11475,6 +11475,12 @@ ul.badges { width: 79%; margin-left: 1%; } +#badge-criteria li li { + list-style-type: none; } + +#badge-image-col { + flex: 0 0 400px; } + .badge-profile { vertical-align: top; }