<?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/>.
/**
* Badge assertion library.
*
* @package core
* @subpackage badges
* @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Yuliya Bozhko <yuliya.bozhko@totaralms.com>
*/
namespace core_badges;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/lib/badgeslib.php');
use context_system;
use context_course;
use context_user;
use moodle_exception;
use moodle_url;
use core_text;
use award_criteria;
use core_php_time_limit;
use html_writer;
use stdClass;
/**
* Class that represents badge.
*
* @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class badge {
/** @var int Badge id */
public $id;
/** @var string Badge name */
public $name;
/** @var string Badge description */
public $description;
/** @var integer Timestamp this badge was created */
public $timecreated;
/** @var integer Timestamp this badge was modified */
public $timemodified;
/** @var int The user who created this badge */
public $usercreated;
/** @var int The user who modified this badge */
public $usermodified;
/** @var string The name of the issuer of this badge */
public $issuername;
/** @var string The url of the issuer of this badge */
public $issuerurl;
/** @var string The email of the issuer of this badge */
public $issuercontact;
/** @var integer Timestamp this badge will expire */
public $expiredate;
/** @var integer Duration this badge is valid for */
public $expireperiod;
/** @var integer Site or course badge */
public $type;
/** @var integer The course this badge belongs to */
public $courseid;
/** @var string The message this badge includes. */
public $message;
/** @var string The subject of the message for this badge */
public $messagesubject;
/** @var int Is this badge image baked. */
public $attachment;
/** @var int Send a message when this badge is awarded. */
public $notification;
/** @var int Lifecycle status for this badge. */
public $status = 0;
/** @var int Timestamp to next run cron for this badge. */
public $nextcron;
/** @var int What backpack api version to use for this badge. */
public $version;
/** @var string What language is this badge written in. */
public $language;
/** @var string The author of the image for this badge. */
public $imageauthorname;
/** @var string The email of the author of the image for this badge. */
public $imageauthoremail;
/** @var string The url of the author of the image for this badge. */
public $imageauthorurl;
/** @var string The caption of the image for this badge. */
public $imagecaption;
/** @var array Badge criteria */
public $criteria = array();
/**
* Constructs with badge details.
*
* @param int $badgeid badge ID.
*/
public function __construct($badgeid) {
global $DB;
$this->id = $badgeid;
$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) {
if (property_exists($this, $field)) {
$this->{$field} = $value;
}
}
if (badges_open_badges_backpack_api() != OPEN_BADGES_V1) {
// For Open Badges 2 we need to use a single site issuer with no exceptions.
$issuer = badges_get_default_issuer();
$this->issuername = $issuer['name'];
$this->issuercontact = $issuer['email'];
$this->issuerurl = $issuer['url'];
}
$this->criteria = self::get_criteria();
}
/**
* Use to get context instance of a badge.
*
* @return context instance.
*/
public function get_context() {
if ($this->type == BADGE_TYPE_SITE) {
return context_system::instance();
} else if ($this->type == BADGE_TYPE_COURSE) {
return context_course::instance($this->courseid);
} else {
debugging('Something is wrong...');
}
}
/**
* Return array of aggregation methods
*
* @return array
*/
public static function get_aggregation_methods() {
return array(
BADGE_CRITERIA_AGGREGATION_ALL => get_string('all', 'badges'),
BADGE_CRITERIA_AGGREGATION_ANY => get_string('any', 'badges'),
);
}
/**
* Return array of accepted criteria types for this badge
*
* @return array
*/
public function get_accepted_criteria() {
global $CFG;
$criteriatypes = array();
if ($this->type == BADGE_TYPE_COURSE) {
$criteriatypes = array(
BADGE_CRITERIA_TYPE_OVERALL,
BADGE_CRITERIA_TYPE_MANUAL,
BADGE_CRITERIA_TYPE_COURSE,
BADGE_CRITERIA_TYPE_BADGE,
BADGE_CRITERIA_TYPE_ACTIVITY,
BADGE_CRITERIA_TYPE_COMPETENCY
);
} else if ($this->type == BADGE_TYPE_SITE) {
$criteriatypes = array(
BADGE_CRITERIA_TYPE_OVERALL,
BADGE_CRITERIA_TYPE_MANUAL,
BADGE_CRITERIA_TYPE_COURSESET,
BADGE_CRITERIA_TYPE_BADGE,
BADGE_CRITERIA_TYPE_PROFILE,
BADGE_CRITERIA_TYPE_COHORT,
BADGE_CRITERIA_TYPE_COMPETENCY
);
}
$alltypes = badges_list_criteria();
foreach ($criteriatypes as $index => $type) {
if (!isset($alltypes[$type])) {
unset($criteriatypes[$index]);
}
}
return $criteriatypes;
}
/**
* Save/update badge information in 'badge' table only.
* Cannot be used for updating awards and criteria settings.
*
* @return boolean Returns true on success.
*/
public function save() {
global $DB;
$fordb = new stdClass();
foreach (get_object_vars($this) as $k => $v) {
$fordb->{$k} = $v;
}
unset($fordb->criteria);
$fordb->timemodified = time();
if ($DB->update_record_raw('badge', $fordb)) {
// Trigger event, badge updated.
$eventparams = array('objectid' => $this->id, 'context' => $this->get_context());
$event = \core\event\badge_updated::create($eventparams);
$event->trigger();
return true;
} else {
throw new moodle_exception('error:save', 'badges');
return false;
}
}
/**
* Creates and saves a clone of badge with all its properties.
* Clone is not active by default and has 'Copy of' attached to its name.
*
* @return int ID of new badge.
*/
public function make_clone() {
global $DB, $USER, $PAGE;
$fordb = new stdClass();
foreach (get_object_vars($this) as $k => $v) {
$fordb->{$k} = $v;
}
$fordb->name = get_string('copyof', 'badges', $this->name);
$fordb->status = BADGE_STATUS_INACTIVE;
$fordb->usercreated = $USER->id;
$fordb->usermodified = $USER->id;
$fordb->timecreated = time();
$fordb->timemodified = time();
unset($fordb->id);
if ($fordb->notification > 1) {
$fordb->nextcron = badges_calculate_message_schedule($fordb->notification);
}
$criteria = $fordb->criteria;
unset($fordb->criteria);
if ($new = $DB->insert_record('badge', $fordb, true)) {
$newbadge = new badge($new);
// Copy badge image.
$fs = get_file_storage();
< if ($file = $fs->get_file($this->get_context()->id, 'badges', 'badgeimage', $this->id, '/', 'f1.png')) {
> if ($file = $fs->get_file($this->get_context()->id, 'badges', 'badgeimage', $this->id, '/', 'f3.png')) {
if ($imagefile = $file->copy_content_to_temp()) {
badges_process_badge_image($newbadge, $imagefile);
}
}
// Copy badge criteria.
foreach ($this->criteria as $crit) {
$crit->make_clone($new);
}
// Trigger event, badge duplicated.
$eventparams = array('objectid' => $new, 'context' => $PAGE->context);
$event = \core\event\badge_duplicated::create($eventparams);
$event->trigger();
return $new;
} else {
throw new moodle_exception('error:clone', 'badges');
return false;
}
}
/**
* Checks if badges is active.
* Used in badge award.
*
* @return boolean A status indicating badge is active
*/
public function is_active() {
if (($this->status == BADGE_STATUS_ACTIVE) ||
($this->status == BADGE_STATUS_ACTIVE_LOCKED)) {
return true;
}
return false;
}
/**
* Use to get the name of badge status.
*
* @return string
*/
public function get_status_name() {
return get_string('badgestatus_' . $this->status, 'badges');
}
/**
* Use to set badge status.
* Only active badges can be earned/awarded/issued.
*
* @param int $status Status from BADGE_STATUS constants
*/
public function set_status($status = 0) {
$this->status = $status;
$this->save();
if ($status == BADGE_STATUS_ACTIVE) {
// Trigger event, badge enabled.
$eventparams = array('objectid' => $this->id, 'context' => $this->get_context());
$event = \core\event\badge_enabled::create($eventparams);
$event->trigger();
} else if ($status == BADGE_STATUS_INACTIVE) {
// Trigger event, badge disabled.
$eventparams = array('objectid' => $this->id, 'context' => $this->get_context());
$event = \core\event\badge_disabled::create($eventparams);
$event->trigger();
}
}
/**
* Checks if badges is locked.
* Used in badge award and editing.
*
* @return boolean A status indicating badge is locked
*/
public function is_locked() {
if (($this->status == BADGE_STATUS_ACTIVE_LOCKED) ||
($this->status == BADGE_STATUS_INACTIVE_LOCKED)) {
return true;
}
return false;
}
/**
* Checks if badge has been awarded to users.
* Used in badge editing.
*
* @return boolean A status indicating badge has been awarded at least once
*/
public function has_awards() {
global $DB;
$awarded = $DB->record_exists_sql('SELECT b.uniquehash
FROM {badge_issued} b INNER JOIN {user} u ON b.userid = u.id
WHERE b.badgeid = :badgeid AND u.deleted = 0', array('badgeid' => $this->id));
return $awarded;
}
/**
* Gets list of users who have earned an instance of this badge.
*
* @return array An array of objects with information about badge awards.
*/
public function get_awards() {
global $DB;
$awards = $DB->get_records_sql(
'SELECT b.userid, b.dateissued, b.uniquehash, u.firstname, u.lastname
FROM {badge_issued} b INNER JOIN {user} u
ON b.userid = u.id
WHERE b.badgeid = :badgeid AND u.deleted = 0', array('badgeid' => $this->id));
return $awards;
}
/**
* Indicates whether badge has already been issued to a user.
*
* @param int $userid User to check
* @return boolean
*/
public function is_issued($userid) {
global $DB;
return $DB->record_exists('badge_issued', array('badgeid' => $this->id, 'userid' => $userid));
}
/**
* Issue a badge to user.
*
* @param int $userid User who earned the badge
* @param boolean $nobake Not baking actual badges (for testing purposes)
*/
public function issue($userid, $nobake = false) {
global $DB, $CFG;
$now = time();
$issued = new stdClass();
$issued->badgeid = $this->id;
$issued->userid = $userid;
$issued->uniquehash = sha1(rand() . $userid . $this->id . $now);
$issued->dateissued = $now;
if ($this->can_expire()) {
$issued->dateexpire = $this->calculate_expiry($now);
} else {
$issued->dateexpire = null;
}
// Take into account user badges privacy settings.
// If none set, badges default visibility is set to public.
$issued->visible = get_user_preferences('badgeprivacysetting', 1, $userid);
$result = $DB->insert_record('badge_issued', $issued, true);
if ($result) {
// Trigger badge awarded event.
$eventdata = array (
'context' => $this->get_context(),
'objectid' => $this->id,
'relateduserid' => $userid,
'other' => array('dateexpire' => $issued->dateexpire, 'badgeissuedid' => $result)
);
\core\event\badge_awarded::create($eventdata)->trigger();
// Lock the badge, so that its criteria could not be changed any more.
if ($this->status == BADGE_STATUS_ACTIVE) {
$this->set_status(BADGE_STATUS_ACTIVE_LOCKED);
}
// Update details in criteria_met table.
$compl = $this->get_criteria_completions($userid);
foreach ($compl as $c) {
$obj = new stdClass();
$obj->id = $c->id;
$obj->issuedid = $result;
$DB->update_record('badge_criteria_met', $obj, true);
}
if (!$nobake) {
// Bake a badge image.
$pathhash = badges_bake($issued->uniquehash, $this->id, $userid, true);
// Notify recipients and badge creators.
badges_notify_badge_award($this, $userid, $issued->uniquehash, $pathhash);
}
}
}
/**
* Reviews all badge criteria and checks if badge can be instantly awarded.
*
* @return int Number of awards
*/
public function review_all_criteria() {
global $DB, $CFG;
$awards = 0;
// Raise timelimit as this could take a while for big web sites.
core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
foreach ($this->criteria as $crit) {
// Overall criterion is decided when other criteria are reviewed.
if ($crit->criteriatype == BADGE_CRITERIA_TYPE_OVERALL) {
continue;
}
list($extrajoin, $extrawhere, $extraparams) = $crit->get_completed_criteria_sql();
// For site level badges, get all active site users who can earn this badge and haven't got it yet.
if ($this->type == BADGE_TYPE_SITE) {
$sql = "SELECT DISTINCT u.id, bi.badgeid
FROM {user} u
{$extrajoin}
LEFT JOIN {badge_issued} bi
ON u.id = bi.userid AND bi.badgeid = :badgeid
WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0 " . $extrawhere;
$params = array_merge(array('badgeid' => $this->id, 'guestid' => $CFG->siteguest), $extraparams);
$toearn = $DB->get_fieldset_sql($sql, $params);
} else {
// For course level badges, get all users who already earned the badge in this course.
// Then find the ones who are enrolled in the course and don't have a badge yet.
$earned = $DB->get_fieldset_select(
'badge_issued',
'userid AS id',
'badgeid = :badgeid',
array('badgeid' => $this->id)
);
$wheresql = '';
$earnedparams = array();
if (!empty($earned)) {
list($earnedsql, $earnedparams) = $DB->get_in_or_equal($earned, SQL_PARAMS_NAMED, 'u', false);
$wheresql = ' WHERE u.id ' . $earnedsql;
}
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->get_context(), 'moodle/badges:earnbadge', 0, true);
$sql = "SELECT DISTINCT u.id
FROM {user} u
{$extrajoin}
JOIN ({$enrolledsql}) je ON je.id = u.id " . $wheresql . $extrawhere;
$params = array_merge($enrolledparams, $earnedparams, $extraparams);
$toearn = $DB->get_fieldset_sql($sql, $params);
}
foreach ($toearn as $uid) {
$reviewoverall = false;
if ($crit->review($uid, true)) {
$crit->mark_complete($uid);
if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
$this->issue($uid);
$awards++;
} else {
$reviewoverall = true;
}
} else {
// Will be reviewed some other time.
$reviewoverall = false;
}
// Review overall if it is required.
if ($reviewoverall && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) {
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
$this->issue($uid);
$awards++;
}
}
}
return $awards;
}
/**
* Gets an array of completed criteria from 'badge_criteria_met' table.
*
* @param int $userid Completions for a user
* @return array Records of criteria completions
*/
public function get_criteria_completions($userid) {
global $DB;
$completions = array();
$sql = "SELECT bcm.id, bcm.critid
FROM {badge_criteria_met} bcm
INNER JOIN {badge_criteria} bc ON bcm.critid = bc.id
WHERE bc.badgeid = :badgeid AND bcm.userid = :userid ";
$completions = $DB->get_records_sql($sql, array('badgeid' => $this->id, 'userid' => $userid));
return $completions;
}
/**
* Checks if badges has award criteria set up.
*
* @return boolean A status indicating badge has at least one criterion
*/
public function has_criteria() {
if (count($this->criteria) > 0) {
return true;
}
return false;
}
/**
* Returns badge award criteria
*
* @return array An array of badge criteria
*/
public function get_criteria() {
global $DB;
$criteria = array();
if ($records = (array)$DB->get_records('badge_criteria', array('badgeid' => $this->id))) {
foreach ($records as $record) {
$criteria[$record->criteriatype] = award_criteria::build((array)$record);
}
}
return $criteria;
}
/**
* Get aggregation method for badge criteria
*
* @param int $criteriatype If none supplied, get overall aggregation method (optional)
* @return int One of BADGE_CRITERIA_AGGREGATION_ALL or BADGE_CRITERIA_AGGREGATION_ANY
*/
public function get_aggregation_method($criteriatype = 0) {
global $DB;
$params = array('badgeid' => $this->id, 'criteriatype' => $criteriatype);
$aggregation = $DB->get_field('badge_criteria', 'method', $params, IGNORE_MULTIPLE);
if (!$aggregation) {
return BADGE_CRITERIA_AGGREGATION_ALL;
}
return $aggregation;
}
/**
* Checks if badge has expiry period or date set up.
*
* @return boolean A status indicating badge can expire
*/
public function can_expire() {
if ($this->expireperiod || $this->expiredate) {
return true;
}
return false;
}
/**
* Calculates badge expiry date based on either expirydate or expiryperiod.
*
* @param int $timestamp Time of badge issue
* @return int A timestamp
*/
public function calculate_expiry($timestamp) {
$expiry = null;
if (isset($this->expiredate)) {
$expiry = $this->expiredate;
} else if (isset($this->expireperiod)) {
$expiry = $timestamp + $this->expireperiod;
}
return $expiry;
}
/**
* Checks if badge has manual award criteria set.
*
* @return boolean A status indicating badge can be awarded manually
*/
public function has_manual_award_criteria() {
foreach ($this->criteria as $criterion) {
if ($criterion->criteriatype == BADGE_CRITERIA_TYPE_MANUAL) {
return true;
}
}
return false;
}
/**
* Fully deletes the badge or marks it as archived.
*
* @param boolean $archive Achive a badge without actual deleting of any data.
*/
public function delete($archive = true) {
global $DB;
if ($archive) {
$this->status = BADGE_STATUS_ARCHIVED;
$this->save();
// Trigger event, badge archived.
$eventparams = array('objectid' => $this->id, 'context' => $this->get_context());
$event = \core\event\badge_archived::create($eventparams);
$event->trigger();
return;
}
$fs = get_file_storage();
// Remove all issued badge image files and badge awards.
// Cannot bulk remove area files here because they are issued in user context.
$awards = $this->get_awards();
foreach ($awards as $award) {
$usercontext = context_user::instance($award->userid);
$fs->delete_area_files($usercontext->id, 'badges', 'userbadge', $this->id);
}
$DB->delete_records('badge_issued', array('badgeid' => $this->id));
// Remove all badge criteria.
$criteria = $this->get_criteria();
foreach ($criteria as $criterion) {
$criterion->delete();
}
// Delete badge images.
$badgecontext = $this->get_context();
$fs->delete_area_files($badgecontext->id, 'badges', 'badgeimage', $this->id);
// Delete endorsements, competencies and related badges.
$DB->delete_records('badge_endorsement', array('badgeid' => $this->id));
$relatedsql = 'badgeid = :badgeid OR relatedbadgeid = :relatedbadgeid';
$relatedparams = array(
'badgeid' => $this->id,
'relatedbadgeid' => $this->id
);
$DB->delete_records_select('badge_related', $relatedsql, $relatedparams);
$DB->delete_records('badge_alignment', array('badgeid' => $this->id));
// Finally, remove badge itself.
$DB->delete_records('badge', array('id' => $this->id));
// Trigger event, badge deleted.
$eventparams = array('objectid' => $this->id,
'context' => $this->get_context(),
'other' => array('badgetype' => $this->type, 'courseid' => $this->courseid)
);
$event = \core\event\badge_deleted::create($eventparams);
$event->trigger();
}
/**
* Add multiple related badges.
*
* @param array $relatedids Id of badges.
*/
public function add_related_badges($relatedids) {
global $DB;
$relatedbadges = array();
foreach ($relatedids as $relatedid) {
$relatedbadge = new stdClass();
$relatedbadge->badgeid = $this->id;
$relatedbadge->relatedbadgeid = $relatedid;
$relatedbadges[] = $relatedbadge;
}
$DB->insert_records('badge_related', $relatedbadges);
}
/**
* Delete an related badge.
*
* @param int $relatedid Id related badge.
* @return boolean A status for delete an related badge.
*/
public function delete_related_badge($relatedid) {
global $DB;
$sql = "(badgeid = :badgeid AND relatedbadgeid = :relatedid) OR " .
"(badgeid = :relatedid2 AND relatedbadgeid = :badgeid2)";
$params = ['badgeid' => $this->id, 'badgeid2' => $this->id, 'relatedid' => $relatedid, 'relatedid2' => $relatedid];
return $DB->delete_records_select('badge_related', $sql, $params);
}
/**
* Checks if badge has related badges.
*
* @return boolean A status related badge.
*/
public function has_related() {
global $DB;
$sql = "SELECT DISTINCT b.id
FROM {badge_related} br
JOIN {badge} b ON (br.relatedbadgeid = b.id OR br.badgeid = b.id)
WHERE (br.badgeid = :badgeid OR br.relatedbadgeid = :badgeid2) AND b.id != :badgeid3";
return $DB->record_exists_sql($sql, ['badgeid' => $this->id, 'badgeid2' => $this->id, 'badgeid3' => $this->id]);
}
/**
* Get related badges of badge.
*
* @param boolean $activeonly Do not get the inactive badges when is true.
* @return array Related badges information.
*/
public function get_related_badges($activeonly = false) {
global $DB;
$params = array('badgeid' => $this->id, 'badgeid2' => $this->id, 'badgeid3' => $this->id);
$query = "SELECT DISTINCT b.id, b.name, b.version, b.language, b.type
FROM {badge_related} br
JOIN {badge} b ON (br.relatedbadgeid = b.id OR br.badgeid = b.id)
WHERE (br.badgeid = :badgeid OR br.relatedbadgeid = :badgeid2) AND b.id != :badgeid3";
if ($activeonly) {
$query .= " AND b.status <> :status";
$params['status'] = BADGE_STATUS_INACTIVE;
}
$relatedbadges = $DB->get_records_sql($query, $params);
return $relatedbadges;
}
/**
* Insert/update alignment information of badge.
*
* @param stdClass $alignment Data of a alignment.
* @param int $alignmentid ID alignment.
* @return bool|int A status/ID when insert or update data.
*/
public function save_alignment($alignment, $alignmentid = 0) {
global $DB;
$record = $DB->record_exists('badge_alignment', array('id' => $alignmentid));
if ($record) {
$alignment->id = $alignmentid;
return $DB->update_record('badge_alignment', $alignment);
} else {
return $DB->insert_record('badge_alignment', $alignment, true);
}
}
/**
* Delete a alignment of badge.
*
* @param int $alignmentid ID alignment.
* @return boolean A status for delete a alignment.
*/
public function delete_alignment($alignmentid) {
global $DB;
return $DB->delete_records('badge_alignment', array('badgeid' => $this->id, 'id' => $alignmentid));
}
/**
* Get alignments of badge.
*
* @return array List content alignments.
*/
public function get_alignments() {
global $DB;
return $DB->get_records('badge_alignment', array('badgeid' => $this->id));
}
/**
* Insert/update Endorsement information of badge.
*
* @param stdClass $endorsement Data of an endorsement.
* @return bool|int A status/ID when insert or update data.
*/
public function save_endorsement($endorsement) {
global $DB;
$record = $DB->get_record('badge_endorsement', array('badgeid' => $this->id));
if ($record) {
$endorsement->id = $record->id;
return $DB->update_record('badge_endorsement', $endorsement);
} else {
return $DB->insert_record('badge_endorsement', $endorsement, true);
}
}
/**
* Get endorsement of badge.
*
* @return array|stdClass Endorsement information.
*/
public function get_endorsement() {
global $DB;
return $DB->get_record('badge_endorsement', array('badgeid' => $this->id));
}
/**
* Markdown language support for criteria.
*
* @return string $output Markdown content to output.
*/
public function markdown_badge_criteria() {
$agg = $this->get_aggregation_methods();
if (empty($this->criteria)) {
return get_string('nocriteria', 'badges');
}
$overalldescr = '';
$overall = $this->criteria[BADGE_CRITERIA_TYPE_OVERALL];
if (!empty($overall->description)) {
$overalldescr = format_text($overall->description, $overall->descriptionformat,
array('context' => $this->get_context())) . '\n';
}
// Get the condition string.
if (count($this->criteria) == 2) {
$condition = get_string('criteria_descr', 'badges');
} else {
$condition = get_string('criteria_descr_' . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
core_text::strtoupper($agg[$this->get_aggregation_method()]));
}
unset($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
$items = array();
// If only one criterion left, make sure its description goe to the top.
if (count($this->criteria) == 1) {
$c = reset($this->criteria);
if (!empty($c->description)) {
$overalldescr = $c->description . '\n';
}
if (count($c->params) == 1) {
$items[] = ' * ' . get_string('criteria_descr_single_' . $c->criteriatype, 'badges') .
$c->get_details();
} else {
$items[] = '* ' . get_string('criteria_descr_' . $c->criteriatype, 'badges',
core_text::strtoupper($agg[$this->get_aggregation_method($c->criteriatype)])) .
$c->get_details();
}
} else {
foreach ($this->criteria as $type => $c) {
$criteriadescr = '';
if (!empty($c->description)) {
$criteriadescr = $c->description;
}
if (count($c->params) == 1) {
$items[] = ' * ' . get_string('criteria_descr_single_' . $type, 'badges') .
$c->get_details() . $criteriadescr;
} else {
$items[] = '* ' . get_string('criteria_descr_' . $type, 'badges',
core_text::strtoupper($agg[$this->get_aggregation_method($type)])) .
$c->get_details() . $criteriadescr;
}
}
}
return strip_tags($overalldescr . $condition . html_writer::alist($items, array(), 'ul'));
}
/**
* Define issuer information by format Open Badges specification version 2.
*
* @param int $obversion OB version to use.
* @return array Issuer informations of the badge.
*/
public function get_badge_issuer(?int $obversion = null) {
global $DB;
$issuer = [];
if ($obversion == OPEN_BADGES_V1) {
$data = $DB->get_record('badge', ['id' => $this->id]);
$issuer['name'] = $data->issuername;
$issuer['url'] = $data->issuerurl;
$issuer['email'] = $data->issuercontact;
} else {
$issuer['name'] = $this->issuername;
$issuer['url'] = $this->issuerurl;
$issuer['email'] = $this->issuercontact;
$issuer['@context'] = OPEN_BADGES_V2_CONTEXT;
$issueridurl = new moodle_url('/badges/issuer_json.php', array('id' => $this->id));
$issuer['id'] = $issueridurl->out(false);
$issuer['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
}
return $issuer;
}
}