Merge branch 'MDL-43938-main' of https://github.com/sarjona/moodle

This commit is contained in:
Huong Nguyen 2024-07-10 09:20:44 +07:00
commit 0644eeb752
No known key found for this signature in database
GPG Key ID: 40D88AB693A3E72A
12 changed files with 668 additions and 241 deletions

View File

@ -0,0 +1,7 @@
issueNumber: MDL-43938
notes:
core_badges:
- message: >-
The badges/newbadge.php page has been deprecated and merged with
badges/edit.php. Please, use badges/edit.php instead.
type: deprecated

View File

@ -87,7 +87,7 @@ if (($hassiteconfig || has_any_capability(array(
$ADMIN->add('badges',
new admin_externalpage('newbadge',
new lang_string('newbadge', 'badges'),
new moodle_url('/badges/newbadge.php', array('type' => BADGE_TYPE_SITE)),
new moodle_url('/badges/edit.php', ['action' => 'new']),
array('moodle/badges:createbadge'), empty($CFG->enablebadges)
)
);

View File

@ -991,4 +991,146 @@ class badge {
public function get_badge_tags(): array {
return array_values(\core_tag_tag::get_item_tags_array('core_badges', 'badge', $this->id));
}
/**
* Create a badge, to store it in the database.
*
* @param stdClass $data Data to create a badge.
* @param int|null $courseid The course where the badge will be added.
* @return badge The badge object created.
*/
public static function create_badge(stdClass $data, ?int $courseid = null): badge {
global $DB, $USER, $CFG;
$now = time();
$fordb = new stdClass();
$fordb->id = null;
$fordb->courseid = $courseid;
$fordb->type = $courseid ? BADGE_TYPE_COURSE : BADGE_TYPE_SITE;
$fordb->name = trim($data->name);
$fordb->version = $data->version;
$fordb->language = $data->language;
$fordb->description = $data->description;
$fordb->imageauthorname = $data->imageauthorname;
$fordb->imageauthoremail = $data->imageauthoremail;
$fordb->imageauthorurl = $data->imageauthorurl;
$fordb->imagecaption = $data->imagecaption;
$fordb->timecreated = $now;
$fordb->timemodified = $now;
$fordb->usercreated = $USER->id;
$fordb->usermodified = $USER->id;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
$fordb->issuername = $data->issuername;
$fordb->issuerurl = $data->issuerurl;
$fordb->issuercontact = $data->issuercontact;
} else {
$url = parse_url($CFG->wwwroot);
$fordb->issuerurl = $url['scheme'] . '://' . $url['host'];
$fordb->issuername = $CFG->badges_defaultissuername;
$fordb->issuercontact = $CFG->badges_defaultissuercontact;
}
if (!property_exists($data, 'expiry')) {
$data->expiry = 0;
}
$fordb->expiredate = ($data->expiry == 1) ? $data->expiredate : null;
$fordb->expireperiod = ($data->expiry == 2) ? $data->expireperiod : null;
$fordb->messagesubject = get_string('messagesubject', 'badges');
$fordb->message = get_string('messagebody', 'badges',
html_writer::link($CFG->wwwroot . '/badges/mybadges.php', get_string('managebadges', 'badges')));
$fordb->attachment = 1;
$fordb->notification = BADGE_MESSAGE_NEVER;
$fordb->status = BADGE_STATUS_INACTIVE;
$badgeid = $DB->insert_record('badge', $fordb, true);
if ($courseid) {
$course = get_course($courseid);
$context = context_course::instance($course->id);
} else {
$context = context_system::instance();
}
// Trigger event, badge created.
$eventparams = [
'objectid' => $badgeid,
'context' => $context,
];
$event = \core\event\badge_created::create($eventparams);
$event->trigger();
$badge = new badge($badgeid);
if (property_exists($data, 'tags')) {
\core_tag_tag::set_item_tags('core_badges', 'badge', $badgeid, $context, $data->tags);
}
return $badge;
}
/**
* Update badge data.
*
* @param stdClass $data Data to update a badge.
* @return bool A status for update a badge.
*/
public function update(stdClass $data): bool {
global $USER;
$this->name = trim($data->name);
$this->version = trim($data->version);
$this->language = $data->language;
$this->description = $data->description;
$this->imageauthorname = $data->imageauthorname;
$this->imageauthoremail = $data->imageauthoremail;
$this->imageauthorurl = $data->imageauthorurl;
$this->imagecaption = $data->imagecaption;
$this->usermodified = $USER->id;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
$this->issuername = $data->issuername;
$this->issuerurl = $data->issuerurl;
$this->issuercontact = $data->issuercontact;
}
$this->expiredate = ($data->expiry == 1) ? $data->expiredate : null;
$this->expireperiod = ($data->expiry == 2) ? $data->expireperiod : null;
// Need to unset message_editor options to avoid errors on form edit.
unset($this->messageformat);
unset($this->message_editor);
if (!$this->save()) {
return false;
}
\core_tag_tag::set_item_tags('core_badges', 'badge', $this->id, $this->get_context(), $data->tags);
return true;
}
/**
* Update the message of badge.
*
* @param stdClass $data Data to update a badge message.
* @return bool A status for update a badge message.
*/
public function update_message(stdClass $data): bool {
// Calculate next message cron if form data is different from original badge data.
if ($data->notification != $this->notification) {
if ($data->notification > BADGE_MESSAGE_ALWAYS) {
$this->nextcron = badges_calculate_message_schedule($data->notification);
} else {
$this->nextcron = null;
}
}
$this->message = clean_text($data->message_editor['text'], FORMAT_HTML);
$this->messagesubject = $data->messagesubject;
$this->notification = $data->notification;
$this->attachment = $data->attachment;
unset($this->messageformat);
unset($this->message_editor);
return $this->save();
}
}

View File

@ -14,16 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Form classes for editing badges
*
* @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\form;
defined('MOODLE_INTERNAL') || die();
@ -35,8 +25,12 @@ require_once($CFG->libdir . '/filelib.php');
use moodleform;
/**
* Form to edit badge details.
* Form classes for editing badges
*
* @package core_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>
*/
class badge extends moodleform {
@ -49,15 +43,24 @@ class badge extends moodleform {
$mform = $this->_form;
$badge = (isset($this->_customdata['badge'])) ? $this->_customdata['badge'] : false;
$action = $this->_customdata['action'];
if (array_key_exists('courseid', $this->_customdata)) {
$courseid = $this->_customdata['courseid'];
} else if (array_key_exists('badge', $this->_customdata)) {
$courseid = $this->_customdata['badge']->courseid;
}
if (!empty($courseid)) {
$mform->addElement('hidden', 'courseid', $courseid);
$mform->setType('courseid', PARAM_INT);
}
$mform->addElement('header', 'badgedetails', get_string('badgedetails', 'badges'));
$mform->addElement('text', 'name', get_string('name'), array('size' => '70'));
$mform->addElement('text', 'name', get_string('name'), ['size' => '70']);
// When downloading badge, it will be necessary to clean the name as PARAM_FILE.
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', null, 'required');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->addElement('text', 'version', get_string('version', 'badges'), array('size' => '70'));
$mform->addElement('text', 'version', get_string('version', 'badges'), ['size' => '70']);
$mform->setType('version', PARAM_TEXT);
$mform->addHelpButton('version', 'version', 'badges');
@ -70,7 +73,7 @@ class badge extends moodleform {
$mform->addRule('description', null, 'required');
$str = $action == 'new' ? get_string('badgeimage', 'badges') : get_string('newimage', 'badges');
$imageoptions = array('maxbytes' => 262144, 'accepted_types' => array('optimised_image'));
$imageoptions = ['maxbytes' => 262144, 'accepted_types' => ['optimised_image']];
$mform->addElement('filepicker', 'image', $str, null, $imageoptions);
if ($action == 'new') {
@ -80,16 +83,16 @@ class badge extends moodleform {
$mform->insertElementBefore($currentimage, 'image');
}
$mform->addHelpButton('image', 'badgeimage', 'badges');
$mform->addElement('text', 'imageauthorname', get_string('imageauthorname', 'badges'), array('size' => '70'));
$mform->addElement('text', 'imageauthorname', get_string('imageauthorname', 'badges'), ['size' => '70']);
$mform->setType('imageauthorname', PARAM_TEXT);
$mform->addHelpButton('imageauthorname', 'imageauthorname', 'badges');
$mform->addElement('text', 'imageauthoremail', get_string('imageauthoremail', 'badges'), array('size' => '70'));
$mform->addElement('text', 'imageauthoremail', get_string('imageauthoremail', 'badges'), ['size' => '70']);
$mform->setType('imageauthoremail', PARAM_TEXT);
$mform->addHelpButton('imageauthoremail', 'imageauthoremail', 'badges');
$mform->addElement('text', 'imageauthorurl', get_string('imageauthorurl', 'badges'), array('size' => '70'));
$mform->addElement('text', 'imageauthorurl', get_string('imageauthorurl', 'badges'), ['size' => '70']);
$mform->setType('imageauthorurl', PARAM_URL);
$mform->addHelpButton('imageauthorurl', 'imageauthorurl', 'badges');
$mform->addElement('text', 'imagecaption', get_string('imagecaption', 'badges'), array('size' => '70'));
$mform->addElement('text', 'imagecaption', get_string('imagecaption', 'badges'), ['size' => '70']);
$mform->setType('imagecaption', PARAM_TEXT);
$mform->addHelpButton('imagecaption', 'imagecaption', 'badges');
$mform->addElement('tags', 'tags', get_string('tags', 'badges'), ['itemtype' => 'badge', 'component' => 'core_badges']);
@ -97,7 +100,7 @@ class badge extends moodleform {
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
$mform->addElement('header', 'issuerdetails', get_string('issuerdetails', 'badges'));
$mform->addElement('text', 'issuername', get_string('name'), array('size' => '70'));
$mform->addElement('text', 'issuername', get_string('name'), ['size' => '70']);
$mform->setType('issuername', PARAM_NOTAGS);
$mform->addRule('issuername', null, 'required');
if (isset($CFG->badges_defaultissuername)) {
@ -105,7 +108,7 @@ class badge extends moodleform {
}
$mform->addHelpButton('issuername', 'issuername', 'badges');
$mform->addElement('text', 'issuercontact', get_string('contact', 'badges'), array('size' => '70'));
$mform->addElement('text', 'issuercontact', get_string('contact', 'badges'), ['size' => '70']);
if (isset($CFG->badges_defaultissuercontact)) {
$mform->setDefault('issuercontact', $CFG->badges_defaultissuercontact);
}
@ -120,17 +123,17 @@ class badge extends moodleform {
$mform->addElement('header', 'issuancedetails', get_string('issuancedetails', 'badges'));
$issuancedetails = array();
$issuancedetails[] =& $mform->createElement('radio', 'expiry', '', get_string('never', 'badges'), 0);
$issuancedetails[] =& $mform->createElement('static', 'none_break', null, '<br/>');
$issuancedetails[] =& $mform->createElement('radio', 'expiry', '', get_string('fixed', 'badges'), 1);
$issuancedetails[] =& $mform->createElement('date_selector', 'expiredate', '');
$issuancedetails[] =& $mform->createElement('static', 'expirydate_break', null, '<br/>');
$issuancedetails[] =& $mform->createElement('radio', 'expiry', '', get_string('relative', 'badges'), 2);
$issuancedetails[] =& $mform->createElement('duration', 'expireperiod', '', array('defaultunit' => 86400, 'optional' => false));
$issuancedetails[] =& $mform->createElement('static', 'expiryperiods_break', null, get_string('after', 'badges'));
$issuancedetails = [];
$issuancedetails[] = $mform->createElement('radio', 'expiry', '', get_string('never', 'badges'), 0);
$issuancedetails[] = $mform->createElement('static', 'none_break', null, '<br/>');
$issuancedetails[] = $mform->createElement('radio', 'expiry', '', get_string('fixed', 'badges'), 1);
$issuancedetails[] = $mform->createElement('date_selector', 'expiredate', '');
$issuancedetails[] = $mform->createElement('static', 'expirydate_break', null, '<br/>');
$issuancedetails[] = $mform->createElement('radio', 'expiry', '', get_string('relative', 'badges'), 2);
$issuancedetails[] = $mform->createElement('duration', 'expireperiod', '', ['defaultunit' => 86400, 'optional' => false]);
$issuancedetails[] = $mform->createElement('static', 'expiryperiods_break', null, get_string('after', 'badges'));
$mform->addGroup($issuancedetails, 'expirydategr', get_string('expirydate', 'badges'), array(' '), false);
$mform->addGroup($issuancedetails, 'expirydategr', get_string('expirydate', 'badges'), [' '], false);
$mform->addHelpButton('expirydategr', 'expirydate', 'badges');
$mform->setDefault('expiry', 0);
$mform->setDefault('expiredate', strtotime('+1 year'));
@ -165,7 +168,7 @@ class badge extends moodleform {
// Freeze all elements if badge is active or locked.
if ($badge->is_active() || $badge->is_locked()) {
$mform->hardFreezeAllVisibleExcept(array());
$mform->hardFreezeAllVisibleExcept([]);
}
}
}
@ -173,11 +176,11 @@ class badge extends moodleform {
/**
* Load in existing data as form defaults
*
* @param stdClass|array $badge object or array of default values
* @param \core_badges\badge $badge object or array of default values
*/
public function set_data($badge) {
$defaultvalues = [];
parent::set_data($badge);
parent::set_data((object) $badge);
if (!empty($badge->expiredate)) {
$defaultvalues['expiry'] = 1;
@ -186,6 +189,11 @@ class badge extends moodleform {
$defaultvalues['expiry'] = 2;
$defaultvalues['expireperiod'] = $badge->expireperiod;
}
if (!empty($badge->name)) {
$defaultvalues['name'] = trim($badge->name);
}
$defaultvalues['tags'] = \core_tag_tag::get_item_tags_array('core_badges', 'badge', $badge->id);
$defaultvalues['currentimage'] = print_badge_image($badge, $badge->get_context(), 'large');
@ -196,7 +204,11 @@ class badge extends moodleform {
* Validates form data
*/
public function validation($data, $files) {
global $DB;
global $DB, $SITE;
// Trim badge name (to guarantee no badges are created with the same name but some extra spaces).
$data['name'] = trim($data['name']);
$errors = parent::validation($data, $files);
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
@ -217,19 +229,6 @@ class badge extends moodleform {
$errors['imageauthoremail'] = get_string('invalidemail');
}
// Check for duplicate badge names.
if ($data['action'] == 'new') {
$duplicate = $DB->record_exists_select('badge', 'name = :name AND status != :deleted',
array('name' => $data['name'], 'deleted' => BADGE_STATUS_ARCHIVED));
} else {
$duplicate = $DB->record_exists_select('badge', 'name = :name AND id != :badgeid AND status != :deleted',
array('name' => $data['name'], 'badgeid' => $data['id'], 'deleted' => BADGE_STATUS_ARCHIVED));
}
if ($duplicate) {
$errors['name'] = get_string('error:duplicatename', 'badges');
}
if ($data['imageauthorurl'] && !preg_match('@^https?://.+@', $data['imageauthorurl'])) {
$errors['imageauthorurl'] = get_string('invalidurl', 'badges');
}
@ -237,4 +236,3 @@ class badge extends moodleform {
return $errors;
}
}

View File

@ -88,8 +88,19 @@ class standard_action_bar extends base_action_bar {
}
if ($this->showaddbadge && has_capability('moodle/badges:createbadge', $this->page->context)) {
$buttons[] = new single_button(new moodle_url('/badges/newbadge.php', $params),
get_string('newbadge', 'core_badges'), 'post', single_button::BUTTON_PRIMARY);
$editparams = ['action' => 'new'];
if (array_key_exists('id', $params)) {
$editparams['courseid'] = $params['id'];
}
$buttons[] = new single_button(
new moodle_url(
'/badges/edit.php',
$editparams,
),
get_string('newbadge', 'core_badges'),
'post',
single_button::BUTTON_PRIMARY,
);
}
foreach ($buttons as $key => $button) {

View File

@ -15,10 +15,9 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Editing badge details, criteria, messages
* Editing badge details, criteria, messages.
*
* @package core
* @subpackage badges
* @package core_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>
@ -28,7 +27,14 @@ require_once(__DIR__ . '/../config.php');
require_once($CFG->libdir . '/badgeslib.php');
require_once($CFG->libdir . '/filelib.php');
$badgeid = required_param('id', PARAM_INT);
// Used only for creating new badge.
$courseid = optional_param('courseid', 0, PARAM_INT);
if ($courseid === 0 ) {
$courseid = null;
}
// Used for editing existing badge.
$badgeid = optional_param('id', null, PARAM_INT);
$action = optional_param('action', 'badge', PARAM_TEXT);
require_login();
@ -37,24 +43,54 @@ if (empty($CFG->enablebadges)) {
throw new \moodle_exception('badgesdisabled', 'badges');
}
$badge = new badge($badgeid);
$context = $badge->get_context();
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
if (!empty($badgeid)) {
// Existing badge.
$badge = new badge($badgeid);
if ($action == 'message') {
require_capability('moodle/badges:configuremessages', $context);
if ($badge->courseid) {
$course = get_course($badge->courseid);
}
$params = ['id' => $badgeid, 'action' => $action];
$badgename = $badge->name;
// Check capabilities.
$context = $badge->get_context();
if ($action == 'message') {
require_capability('moodle/badges:configuremessages', $context);
} else {
require_capability('moodle/badges:configuredetails', $context);
}
} else {
require_capability('moodle/badges:configuredetails', $context);
// New badge.
if ($courseid) {
$course = get_course($courseid);
$context = context_course::instance($course->id);
} else {
$context = context_system::instance();
}
$badge = new stdClass();
$badge->id = null;
$badge->type = $courseid ? BADGE_TYPE_COURSE : BADGE_TYPE_SITE;
$badge->courseid = $courseid;
$params = ['courseid' => $courseid];
$badgename = get_string('create', 'badges');
// Check capabilities.
require_capability('moodle/badges:createbadge', $context);
}
// Check if course badges are enabled.
if (empty($CFG->badges_allowcoursebadges) && ($badge->type == BADGE_TYPE_COURSE)) {
throw new \moodle_exception('coursebadgesdisabled', 'badges');
}
$navurl = new moodle_url('/badges/index.php', ['type' => $badge->type]);
if ($badge->type == BADGE_TYPE_COURSE) {
if (empty($CFG->badges_allowcoursebadges)) {
throw new \moodle_exception('coursebadgesdisabled', 'badges');
}
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$navurl = new moodle_url('/badges/index.php', ['type' => $badge->type, 'id' => $badge->courseid]);
$PAGE->set_pagelayout('incourse');
navigation_node::override_active_url($navurl);
} else {
@ -63,106 +99,104 @@ if ($badge->type == BADGE_TYPE_COURSE) {
navigation_node::override_active_url($navurl, true);
}
$currenturl = new moodle_url('/badges/edit.php', array('id' => $badge->id, 'action' => $action));
$currenturl = new moodle_url('/badges/edit.php', $params);
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title($badgename);
$PAGE->add_body_class('limitedwidth');
$PAGE->navbar->add($badge->name);
$PAGE->navbar->add($badgename);
/** @var \core_badges_renderer $output*/
$output = $PAGE->get_renderer('core', 'badges');
$statusmsg = '';
$errormsg = '';
$badge->message = clean_text($badge->message, FORMAT_HTML);
$editoroptions = array(
$editoroptions = [];
if ($badge->id && $action == 'message') {
$badge->message = clean_text($badge->message, FORMAT_HTML);
$editoroptions = [
'subdirs' => 0,
'maxbytes' => 0,
'maxfiles' => 0,
'changeformat' => 0,
'context' => $context,
'noclean' => false,
'trusttext' => false
);
$badge = file_prepare_standard_editor($badge, 'message', $editoroptions, $context);
'trusttext' => false,
];
$badge = file_prepare_standard_editor($badge, 'message', $editoroptions, $context);
}
$formclass = '\core_badges\form' . '\\' . $action;
$form = new $formclass($currenturl, array('badge' => $badge, 'action' => $action, 'editoroptions' => $editoroptions));
$formclass = '\core_badges\form' . '\\' . ($action == 'new' ? 'badge' : $action);
$params = [
'action' => $action,
];
if ($badge->id) {
$params['badge'] = $badge;
$params['editoroptions'] = $editoroptions;
} else {
$params['courseid'] = $courseid;
}
$form = new $formclass($currenturl, $params);
if ($form->is_cancelled()) {
redirect(new moodle_url('/badges/overview.php', array('id' => $badgeid)));
redirect(new moodle_url('/badges/overview.php', ['id' => $badgeid]));
} else if ($form->is_submitted() && $form->is_validated() && ($data = $form->get_data())) {
if ($action == 'badge') {
$badge->name = $data->name;
$badge->version = trim($data->version);
$badge->language = $data->language;
$badge->description = $data->description;
$badge->imageauthorname = $data->imageauthorname;
$badge->imageauthoremail = $data->imageauthoremail;
$badge->imageauthorurl = $data->imageauthorurl;
$badge->imagecaption = $data->imagecaption;
$badge->usermodified = $USER->id;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
$badge->issuername = $data->issuername;
$badge->issuerurl = $data->issuerurl;
$badge->issuercontact = $data->issuercontact;
}
$badge->expiredate = ($data->expiry == 1) ? $data->expiredate : null;
$badge->expireperiod = ($data->expiry == 2) ? $data->expireperiod : null;
// Need to unset message_editor options to avoid errors on form edit.
unset($badge->messageformat);
unset($badge->message_editor);
if ($badge->save()) {
core_tag_tag::set_item_tags('core_badges', 'badge', $badge->id, $context, $data->tags);
switch ($action) {
case 'new':
// Create new badge.
$badge = badge::create_badge($data, $courseid);
$badgeid = $badge->id;
badges_process_badge_image($badge, $form->save_temp_file('image'));
$form->set_data($badge);
$statusmsg = get_string('changessaved');
} else {
$errormsg = get_string('error:save', 'badges');
}
} else if ($action == 'message') {
// Calculate next message cron if form data is different from original badge data.
if ($data->notification != $badge->notification) {
if ($data->notification > BADGE_MESSAGE_ALWAYS) {
$badge->nextcron = badges_calculate_message_schedule($data->notification);
} else {
$badge->nextcron = null;
// If a user can configure badge criteria, they will be redirected to the criteria page.
if (has_capability('moodle/badges:configurecriteria', $context)) {
redirect(new moodle_url('/badges/criteria.php', ['id' => $badgeid]));
}
}
redirect(new moodle_url('/badges/overview.php', ['id' => $badgeid]));
break;
$badge->message = clean_text($data->message_editor['text'], FORMAT_HTML);
$badge->messagesubject = $data->messagesubject;
$badge->notification = $data->notification;
$badge->attachment = $data->attachment;
case 'badge':
// Edit existing badge.
if ($badge->update($data)) {
badges_process_badge_image($badge, $form->save_temp_file('image'));
$form->set_data($badge);
$statusmsg = get_string('changessaved');
} else {
$errormsg = get_string('error:save', 'badges');
}
break;
unset($badge->messageformat);
unset($badge->message_editor);
if ($badge->save()) {
$statusmsg = get_string('changessaved');
} else {
$errormsg = get_string('error:save', 'badges');
}
case 'message':
// Update badge message.
if ($badge->update_message($data)) {
$statusmsg = get_string('changessaved');
} else {
$errormsg = get_string('error:save', 'badges');
}
break;
}
}
echo $OUTPUT->header();
$actionbar = new \core_badges\output\manage_badge_action_bar($badge, $PAGE);
echo $output->render_tertiary_navigation($actionbar);
echo $output->header();
echo $OUTPUT->heading(print_badge_image($badge, $context, 'small') . ' ' . $badge->name);
if ($badge->id) {
$actionbar = new \core_badges\output\manage_badge_action_bar($badge, $PAGE);
echo $output->render_tertiary_navigation($actionbar);
echo $output->heading(print_badge_image($badge, $context, 'small') . ' ' . $badge->name);
if ($errormsg !== '') {
echo $OUTPUT->notification($errormsg);
if ($errormsg !== '') {
echo $output->notification($errormsg);
} else if ($statusmsg !== '') {
echo $OUTPUT->notification($statusmsg, 'notifysuccess');
} else if ($statusmsg !== '') {
echo $output->notification($statusmsg, 'notifysuccess');
}
echo $output->print_badge_status_box($badge);
} else {
echo $output->heading($badgename);
}
echo $output->print_badge_status_box($badge);
$form->display();
echo $OUTPUT->footer();
echo $output->footer();

View File

@ -17,117 +17,19 @@
/**
* First step page for creating a new badge
*
* @package core
* @subpackage badges
* @package core_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>
* @deprecated since 4.5. Use badges/edit.php instead.
* @todo MDL-82383 This file will be deleted in Moodle 6.0.
*/
require_once(__DIR__ . '/../config.php');
require_once($CFG->libdir . '/badgeslib.php');
$type = required_param('type', PARAM_INT);
$courseid = optional_param('id', 0, PARAM_INT);
require_login();
if (empty($CFG->enablebadges)) {
throw new \moodle_exception('badgesdisabled', 'badges');
}
if (empty($CFG->badges_allowcoursebadges) && ($type == BADGE_TYPE_COURSE)) {
throw new \moodle_exception('coursebadgesdisabled', 'badges');
}
$title = get_string('create', 'badges');
$PAGE->add_body_class('limitedwidth');
if (($type == BADGE_TYPE_COURSE) && ($course = $DB->get_record('course', array('id' => $courseid)))) {
require_login($course);
$coursecontext = context_course::instance($course->id);
$PAGE->set_context($coursecontext);
$PAGE->set_pagelayout('incourse');
$PAGE->set_url('/badges/newbadge.php', array('type' => $type, 'id' => $course->id));
$heading = format_string($course->fullname, true, array('context' => $coursecontext)) . ": " . $title;
$PAGE->set_heading($heading);
$PAGE->set_title($heading);
} else {
$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('admin');
$PAGE->set_url('/badges/newbadge.php', array('type' => $type));
$PAGE->set_heading($title);
$PAGE->set_title($title);
}
require_capability('moodle/badges:createbadge', $PAGE->context);
$fordb = new stdClass();
$fordb->id = null;
$form = new \core_badges\form\badge($PAGE->url, array('action' => 'new'));
if ($form->is_cancelled()) {
redirect(new moodle_url('/badges/index.php', array('type' => $type, 'id' => $courseid)));
} else if ($data = $form->get_data()) {
// Creating new badge here.
$now = time();
$fordb->name = $data->name;
$fordb->version = $data->version;
$fordb->language = $data->language;
$fordb->description = $data->description;
$fordb->imageauthorname = $data->imageauthorname;
$fordb->imageauthoremail = $data->imageauthoremail;
$fordb->imageauthorurl = $data->imageauthorurl;
$fordb->imagecaption = $data->imagecaption;
$fordb->timecreated = $now;
$fordb->timemodified = $now;
$fordb->usercreated = $USER->id;
$fordb->usermodified = $USER->id;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
$fordb->issuername = $data->issuername;
$fordb->issuerurl = $data->issuerurl;
$fordb->issuercontact = $data->issuercontact;
} else {
$url = parse_url($CFG->wwwroot);
$fordb->issuerurl = $url['scheme'] . '://' . $url['host'];
$fordb->issuername = $CFG->badges_defaultissuername;
$fordb->issuercontact = $CFG->badges_defaultissuercontact;
}
$fordb->expiredate = ($data->expiry == 1) ? $data->expiredate : null;
$fordb->expireperiod = ($data->expiry == 2) ? $data->expireperiod : null;
$fordb->type = $type;
$fordb->courseid = ($type == BADGE_TYPE_COURSE) ? $courseid : null;
$fordb->messagesubject = get_string('messagesubject', 'badges');
$fordb->message = get_string('messagebody', 'badges',
html_writer::link($CFG->wwwroot . '/badges/mybadges.php', get_string('managebadges', 'badges')));
$fordb->attachment = 1;
$fordb->notification = BADGE_MESSAGE_NEVER;
$fordb->status = BADGE_STATUS_INACTIVE;
$newid = $DB->insert_record('badge', $fordb, true);
// Trigger event, badge created.
$eventparams = array('objectid' => $newid, 'context' => $PAGE->context);
$event = \core\event\badge_created::create($eventparams);
$event->trigger();
$newbadge = new badge($newid);
core_tag_tag::set_item_tags('core_badges', 'badge', $newid, $PAGE->context, $data->tags);
badges_process_badge_image($newbadge, $form->save_temp_file('image'));
// If a user can configure badge criteria, they will be redirected to the criteria page.
if (has_capability('moodle/badges:configurecriteria', $PAGE->context)) {
redirect(new moodle_url('/badges/criteria.php', array('id' => $newid)));
}
redirect(new moodle_url('/badges/overview.php', array('id' => $newid)));
}
echo $OUTPUT->header();
echo $OUTPUT->box('', 'notifyproblem hide', 'check_connection');
$form->display();
echo $OUTPUT->footer();
$newpageurl = new moodle_url('/badges/edit.php', ['courseid' => $courseid, 'action' => 'new']);
redirect($newpageurl, get_string('newbadgedeprecated', 'core_badges'));

298
badges/tests/badge_test.php Normal file
View File

@ -0,0 +1,298 @@
<?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/>.
declare(strict_types=1);
namespace core_badges;
use core_badges_generator;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->libdir}/badgeslib.php");
/**
* Unit tests for badge class.
*
* @package core_badges
* @covers \core_badges\badge
* @copyright 2024 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class badge_test extends \advanced_testcase {
/**
* Test create_badge.
*
* @dataProvider badges_provider
* @param bool $iscourse Whether the badge is a course badge or not.
* @param array $data Badge data. It will override the default data.
*/
public function test_create_badge(bool $iscourse = false, array $data = []): void {
global $DB;
$this->resetAfterTest();
$courseid = null;
if ($iscourse) {
$course = $this->getDataGenerator()->create_course();
$courseid = (int) $course->id;
}
$user1 = $this->getDataGenerator()->create_user();
$this->setUser($user1);
// Check no badges exist.
$this->assertEquals(0, $DB->count_records('badge'));
$data = (object) array_merge($this->get_badge(), $data);
// Trigger and capture events.
$sink = $this->redirectEvents();
$badge = badge::create_badge($data, $courseid);
// Check the badge was created with the correct data.
$this->assertEquals(1, $DB->count_records('badge'));
$this->assertNotEmpty($badge->id);
if ($iscourse) {
$this->assertEquals(BADGE_TYPE_COURSE, $badge->type);
$this->assertEquals($course->id, $badge->courseid);
} else {
$this->assertEquals(BADGE_TYPE_SITE, $badge->type);
$this->assertNull($badge->courseid);
}
// Badges are always inactive by default, regardless the given status.
$this->assertEquals(BADGE_STATUS_INACTIVE, $badge->status);
if (property_exists($data, 'tags')) {
$this->assertEquals($data->tags, $badge->get_badge_tags());
}
// Check that the event was triggered.
$events = $sink->get_events();
$event = reset($events);
// Check that the event data is valid.
$this->assertInstanceOf('\core\event\badge_created', $event);
$this->assertEquals($badge->usercreated, $event->userid);
$this->assertEquals($badge->id, $event->objectid);
$this->assertDebuggingNotCalled();
$sink->close();
}
/**
* Test update() in badge class.
*
* @dataProvider badges_provider
* @param bool $iscourse Whether the badge is a course badge or not.
* @param array $data Badge data to update the badge with. It will override the default data.
*/
public function test_udpate_badge(bool $iscourse = false, array $data = []): void {
global $USER, $DB;
$this->resetAfterTest();
$record = [];
if ($iscourse) {
$course = $this->getDataGenerator()->create_course();
$record['type'] = BADGE_TYPE_COURSE;
$record['courseid'] = $course->id;
}
/** @var core_badges_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_badges');
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$this->setUser($user1);
/** @var badge $badge */
$badge = $generator->create_badge($record);
$data = (object) array_merge($this->get_badge(), $data);
// Check the badge has been created.
$this->assertEquals(1, $DB->count_records('badge'));
$this->assertNotEquals($data->name, $badge->name);
$this->assertEmpty($badge->get_badge_tags());
// Trigger and capture events.
$sink = $this->redirectEvents();
$this->setUser($user2);
$this->assertTrue($badge->update($data));
// Check the badge was updated with the correct data.
$this->assertEquals(1, $DB->count_records('badge'));
$this->assertNotEmpty($badge->id);
$this->assertEquals($data->name, $badge->name);
if ($iscourse) {
$this->assertEquals(BADGE_TYPE_COURSE, $badge->type);
$this->assertEquals($course->id, $badge->courseid);
} else {
$this->assertEquals(BADGE_TYPE_SITE, $badge->type);
$this->assertNull($badge->courseid);
}
$this->assertEquals(BADGE_STATUS_ACTIVE, $badge->status);
$this->assertEquals($USER->id, $badge->usermodified);
if (property_exists($data, 'tags')) {
$this->assertEquals($data->tags, $badge->get_badge_tags());
}
// Check that the event was triggered.
$events = $sink->get_events();
$event = reset($events);
// Check that the event data is valid.
$this->assertInstanceOf('\core\event\badge_updated', $event);
$this->assertEquals($badge->usermodified, $event->userid);
$this->assertEquals($badge->id, $event->objectid);
$this->assertDebuggingNotCalled();
$sink->close();
}
/**
* Test update_message() in badge class.
*
* @dataProvider badges_provider
* @param bool $iscourse Whether the badge is a course badge or not.
* @param array $data Badge data to update the badge with. It will override the default data.
*/
public function test_udpate_message_badge(bool $iscourse = false, array $data = []): void {
global $USER, $DB;
$this->resetAfterTest();
$record = [];
if ($iscourse) {
$course = $this->getDataGenerator()->create_course();
$record['type'] = BADGE_TYPE_COURSE;
$record['courseid'] = $course->id;
}
/** @var core_badges_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_badges');
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$this->setUser($user1);
/** @var badge $badge */
$badge = $generator->create_badge($record);
$data = (object) array_merge($this->get_badge(), $data);
// Check the badge has been created.
$this->assertEquals(1, $DB->count_records('badge'));
$this->assertNotEquals($data->name, $badge->name);
$this->assertNotEquals($data->messagesubject, $badge->messagesubject);
$this->assertNotEquals($data->message_editor['text'], $badge->message);
$this->assertEmpty($badge->get_badge_tags());
// Trigger and capture events.
$sink = $this->redirectEvents();
$this->setUser($user2);
$this->assertTrue($badge->update_message($data));
// Check the badge was updated with the correct data.
$this->assertEquals(1, $DB->count_records('badge'));
$this->assertNotEmpty($badge->id);
$this->assertNotEquals($data->name, $badge->name);
$this->assertEquals($data->messagesubject, $badge->messagesubject);
$this->assertEquals($data->message_editor['text'], $badge->message);
if ($iscourse) {
$this->assertEquals(BADGE_TYPE_COURSE, $badge->type);
$this->assertEquals($course->id, $badge->courseid);
} else {
$this->assertEquals(BADGE_TYPE_SITE, $badge->type);
$this->assertNull($badge->courseid);
}
$this->assertEquals(BADGE_STATUS_ACTIVE, $badge->status);
$this->assertEquals($user1->id, $badge->usermodified);
// Check that the event was triggered.
$events = $sink->get_events();
$event = reset($events);
// Check that the event data is valid.
$this->assertInstanceOf('\core\event\badge_updated', $event);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals($badge->id, $event->objectid);
$this->assertDebuggingNotCalled();
$sink->close();
}
/**
* Data provider for badge tests.
*
* @return array
*/
public static function badges_provider(): array {
return [
'Site badge' => [
],
'Site badge with tags' => [
'iscourse' => false,
'data' => [
'tags' => ['tag1', 'tag2'],
],
],
'Course badge' => [
'iscourse' => true,
],
];
}
/**
* Get default badge data for testing purpose.
*
* @return array Badge data.
*/
private function get_badge(): array {
global $USER;
return [
'name' => 'My test badge',
'description' => 'Testing badge description',
'timecreated' => time(),
'timemodified' => time(),
'usercreated' => $USER->id,
'usermodified' => $USER->id,
'issuername' => 'Test issuer',
'issuerurl' => 'http://issuer-url.domain.co.nz',
'issuercontact' => 'issuer@example.com',
'expiry' => 0,
'expiredate' => null,
'expireperiod' => null,
'type' => BADGE_TYPE_SITE,
'courseid' => null,
'messagesubject' => 'The new test message subject',
'messageformat' => '1',
'message_editor' => [
'text' => 'The new test message body',
],
'attachment' => 1,
'notification' => 0,
'status' => BADGE_STATUS_ACTIVE_LOCKED,
'version' => OPEN_BADGES_V2,
'language' => 'en',
'imageauthorname' => 'Image author',
'imageauthoremail' => 'author@example.com',
'imageauthorurl' => 'http://image.example.com/',
'imagecaption' => 'Image caption',
'tags' => [],
];
}
}

View File

@ -129,3 +129,33 @@ Feature: Manage badges
| Badge #1 | Not available | 2 |
| Badge #2 | Available | 1 |
| Badge #3 | Available | 0 |
@_file_upload
Scenario: Badge names are not unique anymore
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "core_badges > Badge" exists:
| name | Badge #2 |
| status | 0 |
| course | C1 |
| type | 1 |
| version | 1.0 |
| language | en |
| description | Test badge description |
| image | badges/tests/behat/badge.png |
| imageauthorurl | http://author.example.com |
| imagecaption | Test caption image |
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 | Badge #1 |
| description | Test badge description |
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
When I press "Create badge"
Then I should see "Criteria for this badge have not been set up yet."
And I select "Edit details" from the "jump" singleselect
# Set name for a site badge with existing badge name in a course is also allowed.
And I set the field "name" to "Badge #2"
And I press "Save changes"
And I should see "Changes saved"

View File

@ -302,7 +302,6 @@ $string['error:cannotrevokebadge'] = 'Cannot revoke badge from a user.';
$string['error:cannotdeletecriterion'] = 'This criterion cannot be deleted. ';
$string['error:connectionunknownreason'] = 'The connection was unsuccessful but no reason was given.';
$string['error:clone'] = 'Cannot clone the badge.';
$string['error:duplicatename'] = 'Badge with such name already exists in the system.';
$string['error:externalbadgedoesntexist'] = 'Badge not found';
$string['error:guestuseraccess'] = 'You are currently using guest access. To see badges you need to log in with your user account.';
$string['error:invalidcriteriatype'] = 'Invalid criteria type.';
@ -421,6 +420,8 @@ $string['namewithlink'] = 'Name with link';
$string['never'] = 'Never';
$string['newbackpack'] = 'Add a new backpack';
$string['newbadge'] = 'Add a new badge';
$string['newbadgedeprecated'] = 'You have been redirected from badges/newbadge.php. Please note that badges/newbadge.php will be removed in the near future.
<br/>Update links and bookmarks to use the current page badges/edit.php.';
$string['newimage'] = 'New image';
$string['noalignment'] = 'This badge does not have any external skills or standards specified.';
$string['noawards'] = 'This badge has not been earned yet.';
@ -595,3 +596,6 @@ $string['includeauthdetails'] = "Include authentication details with the backpac
// Deprecated since Moodle 4.3.
$string['backpackemail'] = 'Email address';
$string['backpackemail_help'] = 'The email address associated with your backpack. While you are connected, any badges earned on this site will be associated with this email address.';
// Deprecated since Moodle 4.5.
$string['error:duplicatename'] = 'Badge with such name already exists in the system.';

View File

@ -119,4 +119,5 @@ datechanged,core
siteregistrationcontact,core_hub
siteregistrationcontact_help,core_hub
registrationcontactno,core
registrationcontactyes,core
registrationcontactyes,core
error:duplicatename,core_badges

View File

@ -517,7 +517,7 @@ function badges_add_course_navigation(navigation_node $coursenode, stdClass $cou
navigation_node::TYPE_SETTING, null, 'coursebadges');
if (has_capability('moodle/badges:createbadge', $coursecontext)) {
$url = new moodle_url('/badges/newbadge.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
$url = new moodle_url('/badges/edit.php', ['action' => 'new', 'courseid' => $course->id]);
$coursenode->get('coursebadges')->add(get_string('newbadge', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'newbadge');