MDL-82168 badges: Add WS to enable/disable badges
This commit is contained in:
committed by
Jun Pataleta
parent
11b276fc1b
commit
814753e558
@@ -0,0 +1,5 @@
|
||||
issueNumber: MDL-82168
|
||||
notes:
|
||||
core_badges:
|
||||
- message: New webservices enable_badges and disable_badges have been added.
|
||||
type: improved
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_badges\external;
|
||||
|
||||
use core_badges\badge;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_multiple_structure;
|
||||
use core_external\external_value;
|
||||
use core_external\external_warnings;
|
||||
use moodle_exception;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
|
||||
/**
|
||||
* External service to disable badges.
|
||||
*
|
||||
* @package core_badges
|
||||
* @category external
|
||||
* @copyright 2024 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 4.5
|
||||
*/
|
||||
class disable_badges extends external_api {
|
||||
|
||||
/**
|
||||
* Describes the parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'badgeids' => new external_multiple_structure(
|
||||
new external_value(PARAM_TEXT, 'The badge identifiers to update', VALUE_REQUIRED),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the given badges.
|
||||
*
|
||||
* @param array $badgeids List of badge identifiers to disable.
|
||||
* @return array List of results and warnings.
|
||||
*/
|
||||
public static function execute(array $badgeids): array {
|
||||
global $CFG, $DB;
|
||||
|
||||
$warnings = [];
|
||||
|
||||
[
|
||||
'badgeids' => $badgeids,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'badgeids' => $badgeids,
|
||||
]);
|
||||
|
||||
// Check if badges are enabled.
|
||||
if (empty($CFG->enablebadges)) {
|
||||
throw new moodle_exception('badgesdisabled', 'badges');
|
||||
}
|
||||
|
||||
foreach ($badgeids as $badgeid) {
|
||||
$badge = new badge($badgeid);
|
||||
|
||||
// Check capabilities.
|
||||
$context = $badge->get_context();
|
||||
self::validate_context($context);
|
||||
if (!has_capability('moodle/badges:configurecriteria', $context)) {
|
||||
$warnings[] = [
|
||||
'item' => $badgeid,
|
||||
'warningcode' => 'nopermissions',
|
||||
'message' => get_string('nopermissions', 'error'),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if course badges are enabled.
|
||||
if (empty($CFG->badges_allowcoursebadges) && ($badge->type == BADGE_TYPE_COURSE)) {
|
||||
$warnings[] = [
|
||||
'item' => $badgeid,
|
||||
'warningcode' => 'coursebadgesdisabled',
|
||||
'message' => get_string('coursebadgesdisabled', 'badges'),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = ($badge->status == BADGE_STATUS_ACTIVE) ? BADGE_STATUS_INACTIVE : BADGE_STATUS_INACTIVE_LOCKED;
|
||||
// Deactivate the badge.
|
||||
$badge->set_status($status);
|
||||
}
|
||||
|
||||
return [
|
||||
'result' => empty($warnings),
|
||||
'warnings' => $warnings,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([
|
||||
'result' => new external_value(PARAM_BOOL, 'The processing result'),
|
||||
'warnings' => new external_warnings(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_badges\external;
|
||||
|
||||
use core_badges\badge;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_multiple_structure;
|
||||
use core_external\external_value;
|
||||
use core_external\external_warnings;
|
||||
use moodle_exception;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
|
||||
/**
|
||||
* External service to enable badges.
|
||||
*
|
||||
* @package core_badges
|
||||
* @category external
|
||||
* @copyright 2024 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 4.5
|
||||
*/
|
||||
class enable_badges extends external_api {
|
||||
|
||||
/**
|
||||
* Describes the parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'badgeids' => new external_multiple_structure(
|
||||
new external_value(PARAM_TEXT, 'The badge identifiers to update', VALUE_REQUIRED),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the given badges.
|
||||
*
|
||||
* @param array $badgeids List of badge identifiers to enable.
|
||||
* @return array The number of awarded users for each badge or 'cron' when there are more than 1000 users.
|
||||
*/
|
||||
public static function execute(array $badgeids): array {
|
||||
global $CFG, $DB;
|
||||
|
||||
$result = [];
|
||||
$warnings = [];
|
||||
|
||||
[
|
||||
'badgeids' => $badgeids,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'badgeids' => $badgeids,
|
||||
]);
|
||||
|
||||
// Check if badges are enabled.
|
||||
if (empty($CFG->enablebadges)) {
|
||||
throw new moodle_exception('badgesdisabled', 'badges');
|
||||
}
|
||||
|
||||
foreach ($badgeids as $badgeid) {
|
||||
$badge = new badge($badgeid);
|
||||
|
||||
// Check capabilities.
|
||||
$context = $badge->get_context();
|
||||
self::validate_context($context);
|
||||
if (!has_capability('moodle/badges:configurecriteria', $context)) {
|
||||
$warnings[] = [
|
||||
'item' => $badgeid,
|
||||
'warningcode' => 'nopermissions',
|
||||
'message' => get_string('nopermissions', 'error'),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if course badges are enabled.
|
||||
if (empty($CFG->badges_allowcoursebadges) && ($badge->type == BADGE_TYPE_COURSE)) {
|
||||
$warnings[] = [
|
||||
'item' => $badgeid,
|
||||
'warningcode' => 'coursebadgesdisabled',
|
||||
'message' => get_string('coursebadgesdisabled', 'badges'),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the badge has criteria.
|
||||
if (!$badge->has_criteria()) {
|
||||
$warnings[] = [
|
||||
'item' => $badgeid,
|
||||
'warningcode' => 'nocriteria',
|
||||
'message' => get_string('nocriteria', 'badges'),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Activate the badge.
|
||||
$status = ($badge->status == BADGE_STATUS_INACTIVE) ? BADGE_STATUS_ACTIVE : BADGE_STATUS_ACTIVE_LOCKED;
|
||||
$badge->set_status($status);
|
||||
$awards = self::review_criteria($badge);
|
||||
|
||||
$result[] = [
|
||||
'badgeid' => $badgeid,
|
||||
'awards' => $awards,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'result' => $result,
|
||||
'warnings' => $warnings,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([
|
||||
'result' => new external_multiple_structure(
|
||||
new external_single_structure([
|
||||
'badgeid' => new external_value(PARAM_INT, 'The badge identifier'),
|
||||
'awards' => new external_value(PARAM_ALPHANUM, 'The processing result'),
|
||||
]),
|
||||
),
|
||||
'warnings' => new external_warnings(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Review the criteria of the badge.
|
||||
*
|
||||
* @param \core_badges\badge $badge The badge to review the criteria.
|
||||
* @return string The number of awarded users or 'cron' when there are more than 1000 users.
|
||||
*/
|
||||
private static function review_criteria(badge $badge): string {
|
||||
global $CFG, $DB;
|
||||
|
||||
if ($badge->type == BADGE_TYPE_SITE) {
|
||||
// Review on cron if there are more than 1000 users who can earn a site-level badge.
|
||||
$sql = 'SELECT COUNT(u.id) as num
|
||||
FROM {user} u
|
||||
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';
|
||||
$toearn = $DB->get_record_sql(
|
||||
$sql,
|
||||
[
|
||||
'badgeid' => $badge->id,
|
||||
'guestid' => $CFG->siteguest,
|
||||
],
|
||||
);
|
||||
if ($toearn->num < 1000) {
|
||||
$awards = $badge->review_all_criteria();
|
||||
} else {
|
||||
$awards = 'cron';
|
||||
}
|
||||
} else {
|
||||
$awards = $badge->review_all_criteria();
|
||||
}
|
||||
|
||||
return $awards;
|
||||
}
|
||||
}
|
||||
+25
-8
@@ -573,17 +573,34 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
|
||||
$message = $status . $action;
|
||||
} else {
|
||||
$this->page->requires->js_call_amd('core_badges/actions', 'init');
|
||||
|
||||
$status = get_string('statusmessage_' . $badge->status, 'badges');
|
||||
if ($badge->is_active()) {
|
||||
$action = $this->output->single_button(new moodle_url('/badges/action.php',
|
||||
array('id' => $badge->id, 'lock' => 1, 'sesskey' => sesskey(),
|
||||
'return' => $this->page->url->out_as_local_url(false))),
|
||||
get_string('deactivate', 'badges'), 'POST', array('class' => 'activatebadge'));
|
||||
$action = $this->output->single_button(
|
||||
new moodle_url('#'),
|
||||
get_string('deactivate', 'badges'),
|
||||
'POST',
|
||||
[
|
||||
'class' => 'activatebadge',
|
||||
'data-action' => 'disablebadge',
|
||||
'data-badgeid' => $badge->id,
|
||||
'data-badgename' => $badge->name,
|
||||
'data-courseid' => $badge->courseid,
|
||||
],
|
||||
);
|
||||
} else {
|
||||
$action = $this->output->single_button(new moodle_url('/badges/action.php',
|
||||
array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(),
|
||||
'return' => $this->page->url->out_as_local_url(false))),
|
||||
get_string('activate', 'badges'), 'POST', array('class' => 'activatebadge'));
|
||||
$action = $this->output->single_button(
|
||||
new moodle_url('#'),
|
||||
get_string('activate', 'badges'),
|
||||
'POST',
|
||||
[
|
||||
'class' => 'activatebadge',
|
||||
'data-action' => 'enablebadge',
|
||||
'data-badgeid' => $badge->id,
|
||||
'data-badgename' => $badge->name,
|
||||
'data-courseid' => $badge->courseid,
|
||||
]);
|
||||
}
|
||||
|
||||
$message = $status . $this->output->help_icon('status', 'badges') . $action;
|
||||
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_badges\external;
|
||||
|
||||
use core_badges_generator;
|
||||
use core_badges\badge;
|
||||
use externallib_advanced_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
|
||||
/**
|
||||
* Tests for external function disable_badges.
|
||||
*
|
||||
* @package core_badges
|
||||
* @copyright 2024 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 4.5
|
||||
* @covers \core_badges\external\disable_badges
|
||||
*/
|
||||
final class disable_badges_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test execute method.
|
||||
*/
|
||||
public function test_execute(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertTrue($data['sitebadge']->is_active());
|
||||
$this->assertTrue($data['coursebadge']->is_active());
|
||||
|
||||
$result = disable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result);
|
||||
$this->assertTrue($result['result']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertFalse($sitebadge->is_active());
|
||||
$this->assertFalse($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when badges are disabled.
|
||||
*/
|
||||
public function test_execute_badgesdisabled(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Disable course badges.
|
||||
set_config('enablebadges', 0);
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->expectException(\moodle_exception::class);
|
||||
$this->expectExceptionMessage(get_string('badgesdisabled', 'core_badges'));
|
||||
$result = disable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when course badges are disabled.
|
||||
*/
|
||||
public function test_execute_coursebadgesdisabled(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Disable course badges.
|
||||
set_config('badges_allowcoursebadges', 0);
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertTrue($data['sitebadge']->is_active());
|
||||
$this->assertTrue($data['coursebadge']->is_active());
|
||||
|
||||
$result = disable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result);
|
||||
// Course badge can't be disabled because course badges are disabled.
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertNotEmpty($result['warnings']);
|
||||
$this->assertEquals($data['coursebadge']->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('coursebadgesdisabled', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertFalse($sitebadge->is_active());
|
||||
$this->assertTrue($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when the user doesn't have the capability to disable badges.
|
||||
*/
|
||||
public function test_execute_without_capability(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
$this->setUser($data['teacher']);
|
||||
|
||||
$this->assertTrue($data['sitebadge']->is_active());
|
||||
$this->assertTrue($data['coursebadge']->is_active());
|
||||
|
||||
$result = disable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result);
|
||||
// Teacher doesn't have capability to disable site badges.
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertNotEmpty($result['warnings']);
|
||||
$this->assertEquals($data['sitebadge']->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('nopermissions', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertTrue($sitebadge->is_active());
|
||||
$this->assertFalse($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when the badge is already disabled.
|
||||
*/
|
||||
public function test_execute_disabledisabledbadge(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertTrue($data['coursebadge']->is_active());
|
||||
$data['coursebadge']->set_status(BADGE_STATUS_INACTIVE);
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
|
||||
$result = disable_badges::execute([
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(disable_badges::execute_returns(), $result);
|
||||
// Disabled badges can be disabled again.
|
||||
$this->assertTrue($result['result']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertFalse($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the test, creating a few users and badges.
|
||||
*
|
||||
* @return array Test data.
|
||||
*/
|
||||
private function prepare_test_data(): array {
|
||||
global $DB;
|
||||
|
||||
// Setup test data.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create users and enrolments.
|
||||
$student1 = $this->getDataGenerator()->create_and_enrol($course);
|
||||
$student2 = $this->getDataGenerator()->create_and_enrol($course);
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
|
||||
|
||||
/** @var core_badges_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_badges');
|
||||
$sitebadge = $generator->create_badge([
|
||||
'name' => 'Site badge',
|
||||
'description' => 'Site badge',
|
||||
'status' => BADGE_STATUS_ACTIVE,
|
||||
]);
|
||||
$coursebadge = $generator->create_badge([
|
||||
'name' => 'Course badge',
|
||||
'description' => 'Course badge',
|
||||
'type' => BADGE_TYPE_COURSE,
|
||||
'courseid' => $course->id,
|
||||
'status' => BADGE_STATUS_ACTIVE,
|
||||
]);
|
||||
|
||||
// Create criteria for manually awarding by role.
|
||||
$managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
|
||||
$generator->create_criteria(['badgeid' => $sitebadge->id, 'roleid' => $managerrole]);
|
||||
$generator->create_criteria(['badgeid' => $coursebadge->id, 'roleid' => $managerrole]);
|
||||
|
||||
// Issue badges to student1.
|
||||
$sitebadge->issue($student1->id, true);
|
||||
$coursebadge->issue($student1->id, true);
|
||||
|
||||
return [
|
||||
'course' => $course,
|
||||
'student1' => $student1,
|
||||
'student2' => $student2,
|
||||
'teacher' => $teacher,
|
||||
'sitebadge' => $sitebadge,
|
||||
'coursebadge' => $coursebadge,
|
||||
];
|
||||
}
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_badges\external;
|
||||
|
||||
use core_badges_generator;
|
||||
use core_badges\badge;
|
||||
use externallib_advanced_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
|
||||
/**
|
||||
* Tests for external function enable_badges.
|
||||
*
|
||||
* @package core_badges
|
||||
* @copyright 2024 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 4.5
|
||||
* @covers \core_badges\external\enable_badges
|
||||
*/
|
||||
final class enable_badges_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test execute method.
|
||||
*/
|
||||
public function test_execute(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertFalse($data['sitebadge']->is_active());
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
$this->assertEquals($data['sitebadge']->id, $result['result'][0]['badgeid']);
|
||||
$this->assertEquals($data['coursebadge']->id, $result['result'][1]['badgeid']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertTrue($sitebadge->is_active());
|
||||
$this->assertTrue($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when badges are disabled.
|
||||
*/
|
||||
public function test_execute_badgesdisabled(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Disable course badges.
|
||||
set_config('enablebadges', 0);
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->expectException(\moodle_exception::class);
|
||||
$this->expectExceptionMessage(get_string('badgesdisabled', 'core_badges'));
|
||||
$result = enable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when course badges are disabled.
|
||||
*/
|
||||
public function test_execute_coursebadgesdisabled(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Disable course badges.
|
||||
set_config('badges_allowcoursebadges', 0);
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertFalse($data['sitebadge']->is_active());
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
$this->assertEquals($data['sitebadge']->id, $result['result'][0]['badgeid']);
|
||||
// Course badge can't be enabled because course badges are disabled.
|
||||
$this->assertNotEmpty($result['warnings']);
|
||||
$this->assertEquals($data['coursebadge']->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('coursebadgesdisabled', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertTrue($sitebadge->is_active());
|
||||
$this->assertFalse($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when badge doesn't have criteria.
|
||||
*/
|
||||
public function test_execute_badgewithoutcriteria(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertFalse($data['nocriteriabadge']->has_criteria());
|
||||
$this->assertFalse($data['nocriteriabadge']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['nocriteriabadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
$this->assertEmpty($result['result']);
|
||||
// Badges without criteria can't be enabled.
|
||||
$this->assertNotEmpty($result['warnings']);
|
||||
$this->assertEquals($data['nocriteriabadge']->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('nocriteria', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$nocriteriabadge = new badge($data['nocriteriabadge']->id);
|
||||
$this->assertFalse($nocriteriabadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when the badge is already enabled.
|
||||
*/
|
||||
public function test_execute_enableenabledbadge(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
$data['coursebadge']->set_status(BADGE_STATUS_ACTIVE);
|
||||
$this->assertTrue($data['coursebadge']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
$this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']);
|
||||
// Enabled badges can be enabled again.
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertTrue($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when badgeid doesn't exist.
|
||||
*/
|
||||
public function test_execute_wrongbadgeid(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$badgeid = 1234;
|
||||
$this->expectException(\moodle_exception::class);
|
||||
$this->expectExceptionMessage(get_string('error:nosuchbadge', 'core_badges', $badgeid));
|
||||
$result = enable_badges::execute([
|
||||
$badgeid,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when the user doesn't have the capability to enable badges.
|
||||
*/
|
||||
public function test_execute_without_capability(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
$this->setUser($data['teacher']);
|
||||
|
||||
$this->assertFalse($data['sitebadge']->is_active());
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['sitebadge']->id,
|
||||
$data['coursebadge']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
$this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']);
|
||||
// Teacher doesn't have capability to enable site badges.
|
||||
$this->assertNotEmpty($result['warnings']);
|
||||
$this->assertEquals($data['sitebadge']->id, $result['warnings'][0]['item']);
|
||||
$this->assertEquals('nopermissions', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$sitebadge = new badge($data['sitebadge']->id);
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$this->assertFalse($sitebadge->is_active());
|
||||
$this->assertTrue($coursebadge->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when the badge has the same name as another enabled badge.
|
||||
*/
|
||||
public function test_execute_duplicatedname(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$data = $this->prepare_test_data();
|
||||
|
||||
$this->assertFalse($data['coursebadge']->is_active());
|
||||
$this->assertFalse($data['coursebadge2']->is_active());
|
||||
|
||||
$result = enable_badges::execute([
|
||||
$data['coursebadge']->id,
|
||||
$data['coursebadge2']->id,
|
||||
]);
|
||||
$result = \core_external\external_api::clean_returnvalue(enable_badges::execute_returns(), $result);
|
||||
// Badge can be enabled because badges with the same name are now allowed.
|
||||
$this->assertEquals($data['coursebadge']->id, $result['result'][0]['badgeid']);
|
||||
$this->assertEquals($data['coursebadge2']->id, $result['result'][1]['badgeid']);
|
||||
$this->assertEmpty($result['warnings']);
|
||||
|
||||
$coursebadge = new badge($data['coursebadge']->id);
|
||||
$coursebadge2 = new badge($data['coursebadge2']->id);
|
||||
$this->assertTrue($coursebadge->is_active());
|
||||
$this->assertTrue($coursebadge2->is_active());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the test, creating a few users and badges.
|
||||
*
|
||||
* @return array Test data.
|
||||
*/
|
||||
private function prepare_test_data(): array {
|
||||
global $DB;
|
||||
|
||||
// Setup test data.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create users and enrolments.
|
||||
$student1 = $this->getDataGenerator()->create_and_enrol($course);
|
||||
$student2 = $this->getDataGenerator()->create_and_enrol($course);
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
|
||||
|
||||
/** @var core_badges_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_badges');
|
||||
$sitebadge = $generator->create_badge([
|
||||
'name' => 'Site badge',
|
||||
'description' => 'Site badge',
|
||||
'status' => BADGE_STATUS_INACTIVE,
|
||||
]);
|
||||
$coursebadge = $generator->create_badge([
|
||||
'name' => 'Course badge',
|
||||
'description' => 'Course badge',
|
||||
'type' => BADGE_TYPE_COURSE,
|
||||
'courseid' => $course->id,
|
||||
'status' => BADGE_STATUS_INACTIVE,
|
||||
]);
|
||||
$coursebadge2 = $generator->create_badge([
|
||||
'name' => 'Course badge',
|
||||
'description' => 'Course badge',
|
||||
'type' => BADGE_TYPE_COURSE,
|
||||
'courseid' => $course->id,
|
||||
'status' => BADGE_STATUS_INACTIVE,
|
||||
]);
|
||||
$nocriteriabadge = $generator->create_badge([
|
||||
'name' => 'No criteria badge',
|
||||
'description' => 'No criteria badge',
|
||||
'type' => BADGE_TYPE_COURSE,
|
||||
'courseid' => $course->id,
|
||||
'status' => BADGE_STATUS_INACTIVE,
|
||||
]);
|
||||
|
||||
// Create criteria for manually awarding by role.
|
||||
$managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
|
||||
$generator->create_criteria(['badgeid' => $sitebadge->id, 'roleid' => $managerrole]);
|
||||
$generator->create_criteria(['badgeid' => $coursebadge->id, 'roleid' => $managerrole]);
|
||||
$generator->create_criteria(['badgeid' => $coursebadge2->id, 'roleid' => $managerrole]);
|
||||
|
||||
// Issue badges to student1.
|
||||
$sitebadge->issue($student1->id, true);
|
||||
$coursebadge->issue($student1->id, true);
|
||||
|
||||
return [
|
||||
'course' => $course,
|
||||
'student1' => $student1,
|
||||
'student2' => $student2,
|
||||
'teacher' => $teacher,
|
||||
'sitebadge' => $sitebadge,
|
||||
'coursebadge' => $coursebadge,
|
||||
'coursebadge2' => $coursebadge2,
|
||||
'nocriteriabadge' => $nocriteriabadge,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,18 @@ $functions = array(
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
),
|
||||
'core_badges_disable_badges' => [
|
||||
'classname' => 'core_badges\external\disable_badges',
|
||||
'description' => 'Disable badges',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
'core_badges_enable_badges' => [
|
||||
'classname' => 'core_badges\external\enable_badges',
|
||||
'description' => 'Enable badges',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
],
|
||||
'core_badges_get_user_badges' => array(
|
||||
'classname' => 'core_badges_external',
|
||||
'methodname' => 'get_user_badges',
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2024070500.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2024070500.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.5dev (Build: 20240705)'; // Human-friendly version name
|
||||
|
||||
Reference in New Issue
Block a user